From 656c193511a8419813ec9f1be2b6054012ec90fa Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 6 Apr 2020 08:33:07 +0200 Subject: [PATCH] IPC removed, replaced by WS --- .env | 2 +- {WebSocketsServer => BackendServers}/.env | 2 + BackendServers/eventsServer.js | 222 + .../node_modules/child_process/package.json | 15 +- .../node_modules/dotenv/config.js | 0 .../node_modules/dotenv/lib/cli-options.js | 0 .../node_modules/dotenv/lib/env-options.js | 0 .../node_modules/dotenv/lib/main.js | 0 .../node_modules/dotenv/package.json | 15 +- .../node_modules/dotenv/types/tsconfig.json | 0 .../node_modules/dotenv/types/tslint.json | 0 .../node_modules/ws/browser.js | 0 .../node_modules/ws/index.js | 0 .../node_modules/ws/lib/buffer-util.js | 4 +- .../node_modules/ws/lib/constants.js | 0 .../node_modules/ws/lib/event-target.js | 0 .../node_modules/ws/lib/extension.js | 0 BackendServers/node_modules/ws/lib/limiter.js | 54 + .../node_modules/ws/lib/permessage-deflate.js | 40 +- .../node_modules/ws/lib/receiver.js | 20 +- .../node_modules/ws/lib/sender.js | 32 +- .../node_modules/ws/lib/stream.js | 20 +- .../node_modules/ws/lib/validation.js | 2 +- .../node_modules/ws/lib/websocket-server.js | 0 .../node_modules/ws/lib/websocket.js | 5 +- .../node_modules/ws/package.json | 47 +- BackendServers/package-lock.json | 23 + {TaskManager => BackendServers}/package.json | 4 +- BackendServers/server.js | 49 + BackendServers/taskManagerServer.js | 295 + BackendServers/webSocketsServer.js | 112 + CanvasApp/Canvas.js | 2 +- .../FunctionLibraries/SessionFunctions.js | 4 +- .../FunctionLibraries/TaskFunctions.js | 6 +- .../FloatingSpace/CircularProgressBar.js | 4 +- CanvasApp/FloatingSpace/UiObject.js | 10 +- CanvasApp/PostLoader.js | 6 +- CanvasApp/SystemEventHandler.js | 7 +- EventsServer/node_modules/easy-stack/es5.js | 74 - .../node_modules/easy-stack/example/basic.js | 18 - .../node_modules/easy-stack/package.json | 59 - EventsServer/node_modules/easy-stack/stack.js | 39 - .../node_modules/event-pubsub/bower.json | 28 - EventsServer/node_modules/event-pubsub/es5.js | 143 - EventsServer/node_modules/event-pubsub/es6.js | 99 - .../event-pubsub/event-pubsub-browser-es5.js | 141 - .../event-pubsub/event-pubsub-browser.js | 130 - .../node_modules/event-pubsub/event-pubsub.js | 8 - .../node_modules/event-pubsub/package.json | 59 - .../node_modules/js-message/Message.js | 71 - .../js-message/js-message-vanilla.js | 75 - .../node_modules/js-message/package.json | 81 - .../node_modules/js-queue/package.json | 62 - .../node_modules/js-queue/queue-vanilla.js | 74 - EventsServer/node_modules/js-queue/queue.js | 76 - EventsServer/node_modules/js-queue/stack.js | 3 - .../node_modules/node-ipc/dao/client.js | 257 - .../node_modules/node-ipc/dao/socketServer.js | 402 - .../node-ipc/entities/Defaults.js | 80 - .../node-ipc/entities/EventParser.js | 32 - .../Multi-Client-Broadcast/goodbye-client.js | 44 - .../Multi-Client-Broadcast/hello-client.js | 50 - .../Multi-Client-Broadcast/world-server.js | 51 - .../example/TCPSocket/basic/hello-client.js | 39 - .../example/TCPSocket/basic/world-server.js | 44 - .../TCPSocket/basicSync/hello-client.js | 46 - .../TCPSocket/basicSync/world-server.js | 45 - .../TCPSocket/rawBuffer/hello-client.js | 35 - .../TCPSocket/rawBuffer/world.server.js | 40 - .../goodbye-client.js | 47 - .../hello-client.js | 53 - .../world-server.js | 55 - .../basic-local-only/hello-client.js | 42 - .../basic-local-only/world-server.js | 42 - .../basic-more-secure/hello-client.js | 47 - .../basic-more-secure/world-server.js | 48 - .../basic-most-secure/hello-client.js | 48 - .../basic-most-secure/world-server.js | 49 - .../example/TLSSocket/basic/hello-client.js | 42 - .../example/TLSSocket/basic/world-server.js | 42 - .../TLSSocket/basicSync/hello-client.js | 47 - .../TLSSocket/basicSync/world-server.js | 48 - .../hello-client.js | 45 - .../world.server.js | 53 - .../Multi-Client-Broadcast/goodbye-client.js | 48 - .../Multi-Client-Broadcast/hello-client.js | 48 - .../Multi-Client-Broadcast/world-server.js | 63 - .../example/UDPSocket/basic/hello-client.js | 52 - .../example/UDPSocket/basic/world-server.js | 47 - .../UDPSocket/rawBuffer/hello-client.js | 35 - .../UDPSocket/rawBuffer/world.server.js | 43 - .../clusterUnixSocket/cluster-client.js | 31 - .../clusterUnixSocket/cluster-server.js | 32 - .../example/rawBuffer/hello-client.js | 43 - .../example/rawBuffer/world.server.js | 40 - .../Multi-Client-Broadcast/goodbye-client.js | 43 - .../Multi-Client-Broadcast/hello-client.js | 49 - .../Multi-Client-Broadcast/world-server.js | 51 - .../unixWindowsSocket/basic/hello-client.js | 44 - .../unixWindowsSocket/basic/world-server.js | 33 - .../basicSync/hello-client.js | 49 - .../basicSync/world-server.js | 39 - .../rawBuffer/hello-client.js | 35 - .../rawBuffer/world.server.js | 40 - .../node_modules/node-ipc/node-ipc.js | 21 - .../node_modules/node-ipc/package.json | 92 - .../node_modules/node-ipc/services/IPC.js | 337 - EventsServer/package-lock.json | 41 - EventsServer/package.json | 12 - EventsServer/server.js | 249 - Files-Component/src/FileCursor.js | 8 +- Files-Component/src/FileSequence.js | 4 +- Files-Component/src/MarketFiles.js | 4 +- .../Multi-Period-Daily/User.Bot.js | 2 +- .../Multi-Period-Daily/User.Bot.js | 2 +- TaskManager/.env | 12 - TaskManager/SystemEventHandler.js | 178 - TaskManager/node_modules/dotenv/package.json | 77 - TaskManager/node_modules/easy-stack/es5.js | 74 - .../node_modules/easy-stack/example/basic.js | 18 - .../node_modules/easy-stack/package.json | 59 - TaskManager/node_modules/easy-stack/stack.js | 39 - .../node_modules/event-pubsub/bower.json | 28 - TaskManager/node_modules/event-pubsub/es5.js | 143 - TaskManager/node_modules/event-pubsub/es6.js | 99 - .../event-pubsub/event-pubsub-browser-es5.js | 141 - .../event-pubsub/event-pubsub-browser.js | 130 - .../node_modules/event-pubsub/event-pubsub.js | 8 - .../node_modules/event-pubsub/package.json | 59 - .../node_modules/js-message/Message.js | 71 - .../js-message/js-message-vanilla.js | 75 - .../node_modules/js-message/package.json | 81 - .../node_modules/js-queue/package.json | 62 - .../node_modules/js-queue/queue-vanilla.js | 74 - TaskManager/node_modules/js-queue/queue.js | 76 - TaskManager/node_modules/js-queue/stack.js | 3 - .../node_modules/node-ipc/dao/client.js | 257 - .../node_modules/node-ipc/dao/socketServer.js | 402 - .../node-ipc/entities/Defaults.js | 80 - .../node-ipc/entities/EventParser.js | 32 - .../Multi-Client-Broadcast/goodbye-client.js | 44 - .../Multi-Client-Broadcast/hello-client.js | 50 - .../Multi-Client-Broadcast/world-server.js | 51 - .../example/TCPSocket/basic/hello-client.js | 39 - .../example/TCPSocket/basic/world-server.js | 44 - .../TCPSocket/basicSync/hello-client.js | 46 - .../TCPSocket/basicSync/world-server.js | 45 - .../TCPSocket/rawBuffer/hello-client.js | 35 - .../TCPSocket/rawBuffer/world.server.js | 40 - .../goodbye-client.js | 47 - .../hello-client.js | 53 - .../world-server.js | 55 - .../basic-local-only/hello-client.js | 42 - .../basic-local-only/world-server.js | 42 - .../basic-more-secure/hello-client.js | 47 - .../basic-more-secure/world-server.js | 48 - .../basic-most-secure/hello-client.js | 48 - .../basic-most-secure/world-server.js | 49 - .../example/TLSSocket/basic/hello-client.js | 42 - .../example/TLSSocket/basic/world-server.js | 42 - .../TLSSocket/basicSync/hello-client.js | 47 - .../TLSSocket/basicSync/world-server.js | 48 - .../hello-client.js | 45 - .../world.server.js | 53 - .../Multi-Client-Broadcast/goodbye-client.js | 48 - .../Multi-Client-Broadcast/hello-client.js | 48 - .../Multi-Client-Broadcast/world-server.js | 63 - .../example/UDPSocket/basic/hello-client.js | 52 - .../example/UDPSocket/basic/world-server.js | 47 - .../UDPSocket/rawBuffer/hello-client.js | 35 - .../UDPSocket/rawBuffer/world.server.js | 43 - .../clusterUnixSocket/cluster-client.js | 31 - .../clusterUnixSocket/cluster-server.js | 32 - .../example/rawBuffer/hello-client.js | 43 - .../example/rawBuffer/world.server.js | 40 - .../Multi-Client-Broadcast/goodbye-client.js | 43 - .../Multi-Client-Broadcast/hello-client.js | 49 - .../Multi-Client-Broadcast/world-server.js | 51 - .../unixWindowsSocket/basic/hello-client.js | 44 - .../unixWindowsSocket/basic/world-server.js | 33 - .../basicSync/hello-client.js | 49 - .../basicSync/world-server.js | 39 - .../rawBuffer/hello-client.js | 35 - .../rawBuffer/world.server.js | 40 - TaskManager/node_modules/node-ipc/node-ipc.js | 21 - .../node_modules/node-ipc/package.json | 92 - .../node_modules/node-ipc/services/IPC.js | 337 - TaskManager/package-lock.json | 51 - TaskManager/server.js | 122 - TaskServer/.env | 2 + ...emEventHandler.js => EventServerClient.js} | 133 +- TaskServer/IndicatorBotProcessMainLoop.js | 4 +- TaskServer/MultiPeriod.js | 2 +- TaskServer/MultiPeriodDaily.js | 2 +- TaskServer/ProcessExecutionEvents.js | 16 +- TaskServer/ProcessOutput.js | 4 +- TaskServer/SensorBotProcessMainLoop.js | 4 +- TaskServer/Session.js | 4 +- TaskServer/TradingBotProcessMainLoop.js | 14 +- .../node_modules/@types/node/package.json | 220 - .../ccxt/build/cleanup-old-tags.js | 4 +- .../ccxt/build/export-exchanges.js | 287 +- .../node_modules/ccxt/build/transpile.js | 193 +- TaskServer/node_modules/ccxt/ccxt.js | 15 +- .../node_modules/ccxt/dist/ccxt.browser.js | 15705 ++++++++++------ TaskServer/node_modules/ccxt/js/_1btcxe.js | 7 + TaskServer/node_modules/ccxt/js/acx.js | 8 + TaskServer/node_modules/ccxt/js/adara.js | 3 +- TaskServer/node_modules/ccxt/js/anxpro.js | 5 + TaskServer/node_modules/ccxt/js/aofex.js | 1119 ++ .../node_modules/ccxt/js/base/Exchange.js | 284 +- .../ccxt/js/base/functions/generic.js | 20 +- .../ccxt/js/base/functions/number.js | 37 +- .../ccxt/js/base/functions/throttle.js | 4 +- .../ccxt/js/base/functions/type.js | 2 + TaskServer/node_modules/ccxt/js/bcex.js | 23 +- TaskServer/node_modules/ccxt/js/bequant.js | 10 +- TaskServer/node_modules/ccxt/js/bibox.js | 11 +- TaskServer/node_modules/ccxt/js/bigone.js | 5 +- TaskServer/node_modules/ccxt/js/binance.js | 137 +- TaskServer/node_modules/ccxt/js/binanceje.js | 1 + TaskServer/node_modules/ccxt/js/binanceus.js | 1 + TaskServer/node_modules/ccxt/js/bit2c.js | 2 + TaskServer/node_modules/ccxt/js/bitbank.js | 1 + TaskServer/node_modules/ccxt/js/bitbay.js | 75 +- TaskServer/node_modules/ccxt/js/bitfinex.js | 25 +- TaskServer/node_modules/ccxt/js/bitfinex2.js | 651 +- TaskServer/node_modules/ccxt/js/bitflyer.js | 3 + TaskServer/node_modules/ccxt/js/bitforex.js | 6 + TaskServer/node_modules/ccxt/js/bithumb.js | 2 + TaskServer/node_modules/ccxt/js/bitlish.js | 378 - TaskServer/node_modules/ccxt/js/bitmart.js | 3 + TaskServer/node_modules/ccxt/js/bitmax.js | 11 +- TaskServer/node_modules/ccxt/js/bitmex.js | 16 +- TaskServer/node_modules/ccxt/js/bitso.js | 7 +- TaskServer/node_modules/ccxt/js/bitstamp.js | 82 +- TaskServer/node_modules/ccxt/js/bittrex.js | 122 +- TaskServer/node_modules/ccxt/js/bitz.js | 3 + TaskServer/node_modules/ccxt/js/bleutrade.js | 795 +- TaskServer/node_modules/ccxt/js/braziliex.js | 4 +- TaskServer/node_modules/ccxt/js/btcalpha.js | 5 + TaskServer/node_modules/ccxt/js/btcbox.js | 13 +- TaskServer/node_modules/ccxt/js/btcchina.js | 368 - TaskServer/node_modules/ccxt/js/btcmarkets.js | 10 +- TaskServer/node_modules/ccxt/js/btctradeua.js | 6 +- TaskServer/node_modules/ccxt/js/buda.js | 2 + TaskServer/node_modules/ccxt/js/bw.js | 24 +- TaskServer/node_modules/ccxt/js/bybit.js | 1925 ++ TaskServer/node_modules/ccxt/js/bytetrade.js | 95 +- TaskServer/node_modules/ccxt/js/cex.js | 17 +- TaskServer/node_modules/ccxt/js/cobinhood.js | 861 - .../node_modules/ccxt/js/coinbaseprime.js | 1 + .../node_modules/ccxt/js/coinbasepro.js | 4 + TaskServer/node_modules/ccxt/js/coincheck.js | 3 + TaskServer/node_modules/ccxt/js/coinegg.js | 2 + TaskServer/node_modules/ccxt/js/coinex.js | 3 +- TaskServer/node_modules/ccxt/js/coinfalcon.js | 20 + TaskServer/node_modules/ccxt/js/coinfloor.js | 4 +- .../node_modules/ccxt/js/coinmarketcap.js | 6 + TaskServer/node_modules/ccxt/js/coinmate.js | 287 +- TaskServer/node_modules/ccxt/js/coinone.js | 16 + TaskServer/node_modules/ccxt/js/coss.js | 1 + TaskServer/node_modules/ccxt/js/crex24.js | 2 + TaskServer/node_modules/ccxt/js/deribit.js | 1816 +- TaskServer/node_modules/ccxt/js/digifinex.js | 15 +- TaskServer/node_modules/ccxt/js/dsx.js | 7 +- TaskServer/node_modules/ccxt/js/exmo.js | 372 +- TaskServer/node_modules/ccxt/js/exx.js | 16 + TaskServer/node_modules/ccxt/js/fcoin.js | 17 + TaskServer/node_modules/ccxt/js/flowbtc.js | 5 +- TaskServer/node_modules/ccxt/js/ftx.js | 112 +- TaskServer/node_modules/ccxt/js/gateio.js | 44 +- TaskServer/node_modules/ccxt/js/gemini.js | 10 +- TaskServer/node_modules/ccxt/js/hitbtc.js | 1162 +- TaskServer/node_modules/ccxt/js/hitbtc2.js | 1492 +- TaskServer/node_modules/ccxt/js/hollaex.js | 1230 ++ TaskServer/node_modules/ccxt/js/huobipro.js | 373 +- TaskServer/node_modules/ccxt/js/huobiru.js | 7 +- TaskServer/node_modules/ccxt/js/ice3x.js | 5 + TaskServer/node_modules/ccxt/js/idex.js | 25 +- .../ccxt/js/independentreserve.js | 23 + TaskServer/node_modules/ccxt/js/indodax.js | 12 + TaskServer/node_modules/ccxt/js/itbit.js | 56 +- TaskServer/node_modules/ccxt/js/kkex.js | 18 + TaskServer/node_modules/ccxt/js/kraken.js | 23 +- TaskServer/node_modules/ccxt/js/kucoin.js | 43 +- TaskServer/node_modules/ccxt/js/kuna.js | 2 + TaskServer/node_modules/ccxt/js/lakebtc.js | 3 + TaskServer/node_modules/ccxt/js/latoken.js | 4 + TaskServer/node_modules/ccxt/js/lbank.js | 15 + TaskServer/node_modules/ccxt/js/liquid.js | 1 + TaskServer/node_modules/ccxt/js/livecoin.js | 6 + TaskServer/node_modules/ccxt/js/luno.js | 22 + TaskServer/node_modules/ccxt/js/lykke.js | 21 + TaskServer/node_modules/ccxt/js/mercado.js | 1 + TaskServer/node_modules/ccxt/js/oceanex.js | 21 + TaskServer/node_modules/ccxt/js/okcoin.js | 35 + TaskServer/node_modules/ccxt/js/okcoincny.js | 38 - TaskServer/node_modules/ccxt/js/okcoinusd.js | 1116 -- TaskServer/node_modules/ccxt/js/okex.js | 3176 +++- TaskServer/node_modules/ccxt/js/okex3.js | 2722 --- TaskServer/node_modules/ccxt/js/poloniex.js | 9 +- TaskServer/node_modules/ccxt/js/rightbtc.js | 2 + .../node_modules/ccxt/js/southxchange.js | 6 + TaskServer/node_modules/ccxt/js/stex.js | 6 +- TaskServer/node_modules/ccxt/js/stronghold.js | 4 + .../ccxt/js/test/Exchange/test.fetchOHLCV.js | 2 - .../ccxt/js/test/Exchange/test.ohlcv.js | 6 +- .../ccxt/js/test/Exchange/test.orderbook.js | 1 - .../js/test/base/functions/test.crypto.js | 8 + .../js/test/base/functions/test.number.js | 63 +- TaskServer/node_modules/ccxt/js/test/test.js | 12 +- TaskServer/node_modules/ccxt/js/theocean.js | 40 +- TaskServer/node_modules/ccxt/js/therock.js | 1 + TaskServer/node_modules/ccxt/js/tidebit.js | 42 +- TaskServer/node_modules/ccxt/js/tidex.js | 13 +- TaskServer/node_modules/ccxt/js/timex.js | 2 + TaskServer/node_modules/ccxt/js/topq.js | 25 + TaskServer/node_modules/ccxt/js/upbit.js | 27 +- TaskServer/node_modules/ccxt/js/vaultoro.js | 3 + TaskServer/node_modules/ccxt/js/whitebit.js | 11 +- TaskServer/node_modules/ccxt/js/xbtce.js | 3 + TaskServer/node_modules/ccxt/js/yobit.js | 9 +- TaskServer/node_modules/ccxt/js/zaif.js | 13 + TaskServer/node_modules/ccxt/js/zb.js | 2 + TaskServer/node_modules/ccxt/package.json | 53 +- TaskServer/node_modules/easy-stack/es5.js | 74 - .../node_modules/easy-stack/example/basic.js | 18 - .../node_modules/easy-stack/package.json | 62 - TaskServer/node_modules/easy-stack/stack.js | 39 - .../node_modules/event-pubsub/bower.json | 28 - TaskServer/node_modules/event-pubsub/es5.js | 143 - TaskServer/node_modules/event-pubsub/es6.js | 99 - .../event-pubsub/event-pubsub-browser-es5.js | 141 - .../event-pubsub/event-pubsub-browser.js | 130 - .../node_modules/event-pubsub/event-pubsub.js | 8 - .../node_modules/event-pubsub/package.json | 62 - TaskServer/node_modules/js-message/Message.js | 71 - .../js-message/js-message-vanilla.js | 75 - .../node_modules/js-message/package.json | 84 - TaskServer/node_modules/js-queue/package.json | 65 - .../node_modules/js-queue/queue-vanilla.js | 74 - TaskServer/node_modules/js-queue/queue.js | 76 - TaskServer/node_modules/js-queue/stack.js | 3 - .../node_modules/minimist/example/parse.js | 2 +- TaskServer/node_modules/minimist/index.js | 15 +- TaskServer/node_modules/minimist/package.json | 10 +- TaskServer/node_modules/minimist/test/bool.js | 12 + .../node_modules/minimist/test/proto.js | 44 + .../node_modules/node-ipc/dao/client.js | 257 - .../node_modules/node-ipc/dao/socketServer.js | 402 - .../node-ipc/entities/Defaults.js | 80 - .../node-ipc/entities/EventParser.js | 32 - .../Multi-Client-Broadcast/goodbye-client.js | 44 - .../Multi-Client-Broadcast/hello-client.js | 50 - .../Multi-Client-Broadcast/world-server.js | 51 - .../example/TCPSocket/basic/hello-client.js | 39 - .../example/TCPSocket/basic/world-server.js | 44 - .../TCPSocket/basicSync/hello-client.js | 46 - .../TCPSocket/basicSync/world-server.js | 45 - .../TCPSocket/rawBuffer/hello-client.js | 35 - .../TCPSocket/rawBuffer/world.server.js | 40 - .../goodbye-client.js | 47 - .../hello-client.js | 53 - .../world-server.js | 55 - .../basic-local-only/hello-client.js | 42 - .../basic-local-only/world-server.js | 42 - .../basic-more-secure/hello-client.js | 47 - .../basic-more-secure/world-server.js | 48 - .../basic-most-secure/hello-client.js | 48 - .../basic-most-secure/world-server.js | 49 - .../example/TLSSocket/basic/hello-client.js | 42 - .../example/TLSSocket/basic/world-server.js | 42 - .../TLSSocket/basicSync/hello-client.js | 47 - .../TLSSocket/basicSync/world-server.js | 48 - .../hello-client.js | 45 - .../world.server.js | 53 - .../Multi-Client-Broadcast/goodbye-client.js | 48 - .../Multi-Client-Broadcast/hello-client.js | 48 - .../Multi-Client-Broadcast/world-server.js | 63 - .../example/UDPSocket/basic/hello-client.js | 52 - .../example/UDPSocket/basic/world-server.js | 47 - .../UDPSocket/rawBuffer/hello-client.js | 35 - .../UDPSocket/rawBuffer/world.server.js | 43 - .../clusterUnixSocket/cluster-client.js | 31 - .../clusterUnixSocket/cluster-server.js | 32 - .../example/rawBuffer/hello-client.js | 43 - .../example/rawBuffer/world.server.js | 40 - .../Multi-Client-Broadcast/goodbye-client.js | 43 - .../Multi-Client-Broadcast/hello-client.js | 49 - .../Multi-Client-Broadcast/world-server.js | 51 - .../unixWindowsSocket/basic/hello-client.js | 44 - .../unixWindowsSocket/basic/world-server.js | 33 - .../basicSync/hello-client.js | 49 - .../basicSync/world-server.js | 39 - .../rawBuffer/hello-client.js | 35 - .../rawBuffer/world.server.js | 40 - TaskServer/node_modules/node-ipc/node-ipc.js | 21 - TaskServer/node_modules/node-ipc/package.json | 94 - .../node_modules/node-ipc/services/IPC.js | 337 - TaskServer/node_modules/telegraf/context.js | 22 + TaskServer/node_modules/telegraf/markup.js | 120 +- TaskServer/node_modules/telegraf/package.json | 24 +- .../node_modules/telegraf/scenes/context.js | 2 +- TaskServer/node_modules/telegraf/session.js | 2 +- TaskServer/node_modules/telegraf/telegraf.js | 11 +- TaskServer/node_modules/telegraf/telegram.js | 16 + TaskServer/node_modules/ws/browser.js | 8 + TaskServer/node_modules/ws/index.js | 10 + TaskServer/node_modules/ws/lib/buffer-util.js | 146 + TaskServer/node_modules/ws/lib/constants.js | 10 + .../node_modules/ws/lib/event-target.js | 170 + TaskServer/node_modules/ws/lib/extension.js | 223 + TaskServer/node_modules/ws/lib/limiter.js | 54 + .../node_modules/ws/lib/permessage-deflate.js | 512 + TaskServer/node_modules/ws/lib/receiver.js | 506 + TaskServer/node_modules/ws/lib/sender.js | 390 + TaskServer/node_modules/ws/lib/stream.js | 164 + TaskServer/node_modules/ws/lib/validation.js | 30 + .../node_modules/ws/lib/websocket-server.js | 406 + TaskServer/node_modules/ws/lib/websocket.js | 909 + TaskServer/node_modules/ws/package.json | 136 + TaskServer/package-lock.json | 64 +- TaskServer/package.json | 6 +- TaskServer/server.js | 36 +- .../node_modules/async-limiter/index.js | 67 - .../node_modules/async-limiter/package.json | 69 - .../node_modules/dotenv/config.js | 11 - .../node_modules/dotenv/lib/cli-options.js | 13 - .../node_modules/dotenv/lib/env-options.js | 18 - .../node_modules/dotenv/lib/main.js | 113 - .../node_modules/easy-stack/es5.js | 74 - .../node_modules/easy-stack/example/basic.js | 18 - .../node_modules/easy-stack/package.json | 59 - .../node_modules/easy-stack/stack.js | 39 - .../node_modules/event-pubsub/bower.json | 28 - .../node_modules/event-pubsub/es5.js | 143 - .../node_modules/event-pubsub/es6.js | 99 - .../event-pubsub/event-pubsub-browser-es5.js | 141 - .../event-pubsub/event-pubsub-browser.js | 130 - .../node_modules/event-pubsub/event-pubsub.js | 8 - .../node_modules/event-pubsub/package.json | 59 - .../node_modules/js-message/Message.js | 71 - .../js-message/js-message-vanilla.js | 75 - .../node_modules/js-message/package.json | 81 - .../node_modules/js-queue/package.json | 62 - .../node_modules/js-queue/queue-vanilla.js | 74 - .../node_modules/js-queue/queue.js | 76 - .../node_modules/js-queue/stack.js | 3 - .../node_modules/node-ipc/dao/client.js | 257 - .../node_modules/node-ipc/dao/socketServer.js | 402 - .../node-ipc/entities/Defaults.js | 80 - .../node-ipc/entities/EventParser.js | 32 - .../Multi-Client-Broadcast/goodbye-client.js | 44 - .../Multi-Client-Broadcast/hello-client.js | 50 - .../Multi-Client-Broadcast/world-server.js | 51 - .../example/TCPSocket/basic/hello-client.js | 39 - .../example/TCPSocket/basic/world-server.js | 44 - .../TCPSocket/basicSync/hello-client.js | 46 - .../TCPSocket/basicSync/world-server.js | 45 - .../TCPSocket/rawBuffer/hello-client.js | 35 - .../TCPSocket/rawBuffer/world.server.js | 40 - .../goodbye-client.js | 47 - .../hello-client.js | 53 - .../world-server.js | 55 - .../basic-local-only/hello-client.js | 42 - .../basic-local-only/world-server.js | 42 - .../basic-more-secure/hello-client.js | 47 - .../basic-more-secure/world-server.js | 48 - .../basic-most-secure/hello-client.js | 48 - .../basic-most-secure/world-server.js | 49 - .../example/TLSSocket/basic/hello-client.js | 42 - .../example/TLSSocket/basic/world-server.js | 42 - .../TLSSocket/basicSync/hello-client.js | 47 - .../TLSSocket/basicSync/world-server.js | 48 - .../hello-client.js | 45 - .../world.server.js | 53 - .../Multi-Client-Broadcast/goodbye-client.js | 48 - .../Multi-Client-Broadcast/hello-client.js | 48 - .../Multi-Client-Broadcast/world-server.js | 63 - .../example/UDPSocket/basic/hello-client.js | 52 - .../example/UDPSocket/basic/world-server.js | 47 - .../UDPSocket/rawBuffer/hello-client.js | 35 - .../UDPSocket/rawBuffer/world.server.js | 43 - .../clusterUnixSocket/cluster-client.js | 31 - .../clusterUnixSocket/cluster-server.js | 32 - .../example/rawBuffer/hello-client.js | 43 - .../example/rawBuffer/world.server.js | 40 - .../Multi-Client-Broadcast/goodbye-client.js | 43 - .../Multi-Client-Broadcast/hello-client.js | 49 - .../Multi-Client-Broadcast/world-server.js | 51 - .../unixWindowsSocket/basic/hello-client.js | 44 - .../unixWindowsSocket/basic/world-server.js | 33 - .../basicSync/hello-client.js | 49 - .../basicSync/world-server.js | 39 - .../rawBuffer/hello-client.js | 35 - .../rawBuffer/world.server.js | 40 - .../node_modules/node-ipc/node-ipc.js | 21 - .../node_modules/node-ipc/package.json | 92 - .../node_modules/node-ipc/services/IPC.js | 337 - WebSocketsServer/package-lock.json | 59 - WebSocketsServer/package.json | 14 - WebSocketsServer/server.js | 136 - 503 files changed, 28128 insertions(+), 34498 deletions(-) rename {WebSocketsServer => BackendServers}/.env (87%) create mode 100644 BackendServers/eventsServer.js rename {TaskManager => BackendServers}/node_modules/child_process/package.json (87%) rename {TaskManager => BackendServers}/node_modules/dotenv/config.js (100%) rename {TaskManager => BackendServers}/node_modules/dotenv/lib/cli-options.js (100%) rename {TaskManager => BackendServers}/node_modules/dotenv/lib/env-options.js (100%) rename {TaskManager => BackendServers}/node_modules/dotenv/lib/main.js (100%) rename {WebSocketsServer => BackendServers}/node_modules/dotenv/package.json (88%) rename {WebSocketsServer => BackendServers}/node_modules/dotenv/types/tsconfig.json (100%) rename {WebSocketsServer => BackendServers}/node_modules/dotenv/types/tslint.json (100%) rename {WebSocketsServer => BackendServers}/node_modules/ws/browser.js (100%) rename {WebSocketsServer => BackendServers}/node_modules/ws/index.js (100%) rename {WebSocketsServer => BackendServers}/node_modules/ws/lib/buffer-util.js (97%) rename {WebSocketsServer => BackendServers}/node_modules/ws/lib/constants.js (100%) rename {WebSocketsServer => BackendServers}/node_modules/ws/lib/event-target.js (100%) rename {WebSocketsServer => BackendServers}/node_modules/ws/lib/extension.js (100%) create mode 100644 BackendServers/node_modules/ws/lib/limiter.js rename {WebSocketsServer => BackendServers}/node_modules/ws/lib/permessage-deflate.js (94%) rename {WebSocketsServer => BackendServers}/node_modules/ws/lib/receiver.js (94%) rename {WebSocketsServer => BackendServers}/node_modules/ws/lib/sender.js (91%) rename {WebSocketsServer => BackendServers}/node_modules/ws/lib/stream.js (85%) rename {WebSocketsServer => BackendServers}/node_modules/ws/lib/validation.js (96%) rename {WebSocketsServer => BackendServers}/node_modules/ws/lib/websocket-server.js (100%) rename {WebSocketsServer => BackendServers}/node_modules/ws/lib/websocket.js (99%) rename {WebSocketsServer => BackendServers}/node_modules/ws/package.json (69%) create mode 100644 BackendServers/package-lock.json rename {TaskManager => BackendServers}/package.json (80%) create mode 100644 BackendServers/server.js create mode 100644 BackendServers/taskManagerServer.js create mode 100644 BackendServers/webSocketsServer.js delete mode 100644 EventsServer/node_modules/easy-stack/es5.js delete mode 100644 EventsServer/node_modules/easy-stack/example/basic.js delete mode 100644 EventsServer/node_modules/easy-stack/package.json delete mode 100644 EventsServer/node_modules/easy-stack/stack.js delete mode 100644 EventsServer/node_modules/event-pubsub/bower.json delete mode 100644 EventsServer/node_modules/event-pubsub/es5.js delete mode 100644 EventsServer/node_modules/event-pubsub/es6.js delete mode 100644 EventsServer/node_modules/event-pubsub/event-pubsub-browser-es5.js delete mode 100644 EventsServer/node_modules/event-pubsub/event-pubsub-browser.js delete mode 100644 EventsServer/node_modules/event-pubsub/event-pubsub.js delete mode 100644 EventsServer/node_modules/event-pubsub/package.json delete mode 100644 EventsServer/node_modules/js-message/Message.js delete mode 100644 EventsServer/node_modules/js-message/js-message-vanilla.js delete mode 100644 EventsServer/node_modules/js-message/package.json delete mode 100644 EventsServer/node_modules/js-queue/package.json delete mode 100644 EventsServer/node_modules/js-queue/queue-vanilla.js delete mode 100644 EventsServer/node_modules/js-queue/queue.js delete mode 100644 EventsServer/node_modules/js-queue/stack.js delete mode 100644 EventsServer/node_modules/node-ipc/dao/client.js delete mode 100644 EventsServer/node_modules/node-ipc/dao/socketServer.js delete mode 100644 EventsServer/node_modules/node-ipc/entities/Defaults.js delete mode 100644 EventsServer/node_modules/node-ipc/entities/EventParser.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/goodbye-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/world-server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TCPSocket/basic/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TCPSocket/basic/world-server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TCPSocket/basicSync/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TCPSocket/basicSync/world-server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/world.server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/goodbye-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/world-server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/world-server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/world-server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/world-server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TLSSocket/basic/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TLSSocket/basic/world-server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TLSSocket/basicSync/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TLSSocket/basicSync/world-server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/world.server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/goodbye-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/world-server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/UDPSocket/basic/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/UDPSocket/basic/world-server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/world.server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/rawBuffer/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/rawBuffer/world.server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/goodbye-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/world-server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/unixWindowsSocket/basic/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/unixWindowsSocket/basic/world-server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/world-server.js delete mode 100644 EventsServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/hello-client.js delete mode 100644 EventsServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/world.server.js delete mode 100644 EventsServer/node_modules/node-ipc/node-ipc.js delete mode 100644 EventsServer/node_modules/node-ipc/package.json delete mode 100644 EventsServer/node_modules/node-ipc/services/IPC.js delete mode 100644 EventsServer/package-lock.json delete mode 100644 EventsServer/package.json delete mode 100644 EventsServer/server.js delete mode 100644 TaskManager/.env delete mode 100644 TaskManager/SystemEventHandler.js delete mode 100644 TaskManager/node_modules/dotenv/package.json delete mode 100644 TaskManager/node_modules/easy-stack/es5.js delete mode 100644 TaskManager/node_modules/easy-stack/example/basic.js delete mode 100644 TaskManager/node_modules/easy-stack/package.json delete mode 100644 TaskManager/node_modules/easy-stack/stack.js delete mode 100644 TaskManager/node_modules/event-pubsub/bower.json delete mode 100644 TaskManager/node_modules/event-pubsub/es5.js delete mode 100644 TaskManager/node_modules/event-pubsub/es6.js delete mode 100644 TaskManager/node_modules/event-pubsub/event-pubsub-browser-es5.js delete mode 100644 TaskManager/node_modules/event-pubsub/event-pubsub-browser.js delete mode 100644 TaskManager/node_modules/event-pubsub/event-pubsub.js delete mode 100644 TaskManager/node_modules/event-pubsub/package.json delete mode 100644 TaskManager/node_modules/js-message/Message.js delete mode 100644 TaskManager/node_modules/js-message/js-message-vanilla.js delete mode 100644 TaskManager/node_modules/js-message/package.json delete mode 100644 TaskManager/node_modules/js-queue/package.json delete mode 100644 TaskManager/node_modules/js-queue/queue-vanilla.js delete mode 100644 TaskManager/node_modules/js-queue/queue.js delete mode 100644 TaskManager/node_modules/js-queue/stack.js delete mode 100644 TaskManager/node_modules/node-ipc/dao/client.js delete mode 100644 TaskManager/node_modules/node-ipc/dao/socketServer.js delete mode 100644 TaskManager/node_modules/node-ipc/entities/Defaults.js delete mode 100644 TaskManager/node_modules/node-ipc/entities/EventParser.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/goodbye-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/world-server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TCPSocket/basic/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TCPSocket/basic/world-server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TCPSocket/basicSync/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TCPSocket/basicSync/world-server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TCPSocket/rawBuffer/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TCPSocket/rawBuffer/world.server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/goodbye-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/world-server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TLSSocket/basic-local-only/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TLSSocket/basic-local-only/world-server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TLSSocket/basic-more-secure/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TLSSocket/basic-more-secure/world-server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TLSSocket/basic-most-secure/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TLSSocket/basic-most-secure/world-server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TLSSocket/basic/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TLSSocket/basic/world-server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TLSSocket/basicSync/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TLSSocket/basicSync/world-server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/world.server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/goodbye-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/world-server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/UDPSocket/basic/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/UDPSocket/basic/world-server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/UDPSocket/rawBuffer/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/UDPSocket/rawBuffer/world.server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/clusterUnixSocket/cluster-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/clusterUnixSocket/cluster-server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/rawBuffer/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/rawBuffer/world.server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/goodbye-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/world-server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/unixWindowsSocket/basic/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/unixWindowsSocket/basic/world-server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/unixWindowsSocket/basicSync/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/unixWindowsSocket/basicSync/world-server.js delete mode 100644 TaskManager/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/hello-client.js delete mode 100644 TaskManager/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/world.server.js delete mode 100644 TaskManager/node_modules/node-ipc/node-ipc.js delete mode 100644 TaskManager/node_modules/node-ipc/package.json delete mode 100644 TaskManager/node_modules/node-ipc/services/IPC.js delete mode 100644 TaskManager/package-lock.json delete mode 100644 TaskManager/server.js rename TaskServer/{SystemEventHandler.js => EventServerClient.js} (57%) delete mode 100644 TaskServer/node_modules/@types/node/package.json create mode 100644 TaskServer/node_modules/ccxt/js/aofex.js delete mode 100644 TaskServer/node_modules/ccxt/js/bitlish.js delete mode 100644 TaskServer/node_modules/ccxt/js/btcchina.js create mode 100644 TaskServer/node_modules/ccxt/js/bybit.js delete mode 100644 TaskServer/node_modules/ccxt/js/cobinhood.js create mode 100644 TaskServer/node_modules/ccxt/js/hollaex.js create mode 100644 TaskServer/node_modules/ccxt/js/okcoin.js delete mode 100644 TaskServer/node_modules/ccxt/js/okcoincny.js delete mode 100644 TaskServer/node_modules/ccxt/js/okcoinusd.js delete mode 100644 TaskServer/node_modules/ccxt/js/okex3.js create mode 100644 TaskServer/node_modules/ccxt/js/topq.js delete mode 100644 TaskServer/node_modules/easy-stack/es5.js delete mode 100644 TaskServer/node_modules/easy-stack/example/basic.js delete mode 100644 TaskServer/node_modules/easy-stack/package.json delete mode 100644 TaskServer/node_modules/easy-stack/stack.js delete mode 100644 TaskServer/node_modules/event-pubsub/bower.json delete mode 100644 TaskServer/node_modules/event-pubsub/es5.js delete mode 100644 TaskServer/node_modules/event-pubsub/es6.js delete mode 100644 TaskServer/node_modules/event-pubsub/event-pubsub-browser-es5.js delete mode 100644 TaskServer/node_modules/event-pubsub/event-pubsub-browser.js delete mode 100644 TaskServer/node_modules/event-pubsub/event-pubsub.js delete mode 100644 TaskServer/node_modules/event-pubsub/package.json delete mode 100644 TaskServer/node_modules/js-message/Message.js delete mode 100644 TaskServer/node_modules/js-message/js-message-vanilla.js delete mode 100644 TaskServer/node_modules/js-message/package.json delete mode 100644 TaskServer/node_modules/js-queue/package.json delete mode 100644 TaskServer/node_modules/js-queue/queue-vanilla.js delete mode 100644 TaskServer/node_modules/js-queue/queue.js delete mode 100644 TaskServer/node_modules/js-queue/stack.js create mode 100644 TaskServer/node_modules/minimist/test/proto.js delete mode 100644 TaskServer/node_modules/node-ipc/dao/client.js delete mode 100644 TaskServer/node_modules/node-ipc/dao/socketServer.js delete mode 100644 TaskServer/node_modules/node-ipc/entities/Defaults.js delete mode 100644 TaskServer/node_modules/node-ipc/entities/EventParser.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/goodbye-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/world-server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TCPSocket/basic/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TCPSocket/basic/world-server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TCPSocket/basicSync/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TCPSocket/basicSync/world-server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/world.server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/goodbye-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/world-server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/world-server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/world-server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/world-server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TLSSocket/basic/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TLSSocket/basic/world-server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TLSSocket/basicSync/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TLSSocket/basicSync/world-server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/world.server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/goodbye-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/world-server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/UDPSocket/basic/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/UDPSocket/basic/world-server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/world.server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/rawBuffer/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/rawBuffer/world.server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/goodbye-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/world-server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/unixWindowsSocket/basic/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/unixWindowsSocket/basic/world-server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/world-server.js delete mode 100644 TaskServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/hello-client.js delete mode 100644 TaskServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/world.server.js delete mode 100644 TaskServer/node_modules/node-ipc/node-ipc.js delete mode 100644 TaskServer/node_modules/node-ipc/package.json delete mode 100644 TaskServer/node_modules/node-ipc/services/IPC.js create mode 100644 TaskServer/node_modules/ws/browser.js create mode 100644 TaskServer/node_modules/ws/index.js create mode 100644 TaskServer/node_modules/ws/lib/buffer-util.js create mode 100644 TaskServer/node_modules/ws/lib/constants.js create mode 100644 TaskServer/node_modules/ws/lib/event-target.js create mode 100644 TaskServer/node_modules/ws/lib/extension.js create mode 100644 TaskServer/node_modules/ws/lib/limiter.js create mode 100644 TaskServer/node_modules/ws/lib/permessage-deflate.js create mode 100644 TaskServer/node_modules/ws/lib/receiver.js create mode 100644 TaskServer/node_modules/ws/lib/sender.js create mode 100644 TaskServer/node_modules/ws/lib/stream.js create mode 100644 TaskServer/node_modules/ws/lib/validation.js create mode 100644 TaskServer/node_modules/ws/lib/websocket-server.js create mode 100644 TaskServer/node_modules/ws/lib/websocket.js create mode 100644 TaskServer/node_modules/ws/package.json delete mode 100644 WebSocketsServer/node_modules/async-limiter/index.js delete mode 100644 WebSocketsServer/node_modules/async-limiter/package.json delete mode 100644 WebSocketsServer/node_modules/dotenv/config.js delete mode 100644 WebSocketsServer/node_modules/dotenv/lib/cli-options.js delete mode 100644 WebSocketsServer/node_modules/dotenv/lib/env-options.js delete mode 100644 WebSocketsServer/node_modules/dotenv/lib/main.js delete mode 100644 WebSocketsServer/node_modules/easy-stack/es5.js delete mode 100644 WebSocketsServer/node_modules/easy-stack/example/basic.js delete mode 100644 WebSocketsServer/node_modules/easy-stack/package.json delete mode 100644 WebSocketsServer/node_modules/easy-stack/stack.js delete mode 100644 WebSocketsServer/node_modules/event-pubsub/bower.json delete mode 100644 WebSocketsServer/node_modules/event-pubsub/es5.js delete mode 100644 WebSocketsServer/node_modules/event-pubsub/es6.js delete mode 100644 WebSocketsServer/node_modules/event-pubsub/event-pubsub-browser-es5.js delete mode 100644 WebSocketsServer/node_modules/event-pubsub/event-pubsub-browser.js delete mode 100644 WebSocketsServer/node_modules/event-pubsub/event-pubsub.js delete mode 100644 WebSocketsServer/node_modules/event-pubsub/package.json delete mode 100644 WebSocketsServer/node_modules/js-message/Message.js delete mode 100644 WebSocketsServer/node_modules/js-message/js-message-vanilla.js delete mode 100644 WebSocketsServer/node_modules/js-message/package.json delete mode 100644 WebSocketsServer/node_modules/js-queue/package.json delete mode 100644 WebSocketsServer/node_modules/js-queue/queue-vanilla.js delete mode 100644 WebSocketsServer/node_modules/js-queue/queue.js delete mode 100644 WebSocketsServer/node_modules/js-queue/stack.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/dao/client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/dao/socketServer.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/entities/Defaults.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/entities/EventParser.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/goodbye-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/world-server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TCPSocket/basic/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TCPSocket/basic/world-server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TCPSocket/basicSync/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TCPSocket/basicSync/world-server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/world.server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/goodbye-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/world-server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/world-server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/world-server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/world-server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic/world-server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basicSync/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basicSync/world-server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/world.server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/goodbye-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/world-server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/UDPSocket/basic/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/UDPSocket/basic/world-server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/world.server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/rawBuffer/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/rawBuffer/world.server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/goodbye-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/world-server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/basic/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/basic/world-server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/world-server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/hello-client.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/world.server.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/node-ipc.js delete mode 100644 WebSocketsServer/node_modules/node-ipc/package.json delete mode 100644 WebSocketsServer/node_modules/node-ipc/services/IPC.js delete mode 100644 WebSocketsServer/package-lock.json delete mode 100644 WebSocketsServer/package.json delete mode 100644 WebSocketsServer/server.js diff --git a/.env b/.env index ea4b3c2b2..304416b4f 100644 --- a/.env +++ b/.env @@ -1,7 +1,7 @@ #PORT NUMBERS: If any of these ports are already in use by a different app, please pick a new number between 1 and 50000. WEB_SERVER_PORT=34247 -WEB_SOCKETS_PORT=8080 +WEB_SOCKETS_SERVER_PORT=8080 # TASK MANAGER VARIABLES: diff --git a/WebSocketsServer/.env b/BackendServers/.env similarity index 87% rename from WebSocketsServer/.env rename to BackendServers/.env index 4bc79e391..471650a5a 100644 --- a/WebSocketsServer/.env +++ b/BackendServers/.env @@ -8,3 +8,5 @@ WRITE_LOGS_TO_FILES=true BOTS_PATH=../Legacy-Code LOG_PATH=../Log-Files +WEB_SOCKETS_SERVER_PORT=8080 + diff --git a/BackendServers/eventsServer.js b/BackendServers/eventsServer.js new file mode 100644 index 000000000..82730dfb7 --- /dev/null +++ b/BackendServers/eventsServer.js @@ -0,0 +1,222 @@ +exports.newEventsServer = function newEventsServer() { + + const MODULE = "Events Server" + const LOG_INFO = false + + let thisObject = { + initialize: initialize, + finalize: finalize, + run: run, + onMessage: onMessage + } + + let eventHandlers = new Map() + let counter = 0 + + return thisObject + + function finalize() { + + } + + function initialize() { + + } + + function onMessage(data, callbackFunction) { + try { + let command = JSON.parse(data) + + switch (command.action) { + case "greetings": { + sendResponse(global.DEFAULT_OK_RESPONSE) + return + } + case "createEventHandler": { + let eventHandler = eventHandlers.get(command.eventHandlerName) + if (eventHandler === undefined) { + /* + We will only create event handlers which were not created before. Remember that someone trying to listen events + at an event handler that does not exist, will create that eventhandler, so it is possible that the emitter + when trying to create the event handler in fact was late and the event handler is already there if the listener + arrived here first. An event handler created with this method is not destroyed if there are no listeners or they + all leave. + */ + eventHandler = newEventHandler() + eventHandler.deleteWhenAllListenersAreGone = false + eventHandlers.set(command.eventHandlerName, eventHandler) + } + sendResponse(global.DEFAULT_OK_RESPONSE) + return + } + case "deleteEventHandler": { + let eventHandler = eventHandlers.get(command.eventHandlerName) + if (eventHandler !== undefined) { + /* + We will only delete event handlers which have noone listening, allowing a listener to continue listening even + when the event emitter is gone, asuming that it could come back at some point in time and resume emitting. + */ + if (eventHandler.listeners.length === 0) { + eventHandlers.delete(command.eventHandlerName) + } else { + eventHandler.deleteWhenAllListenersAreGone = true + } + } + + sendResponse(global.DEFAULT_OK_RESPONSE) + return + } + case "listenToEvent": { + let eventHandler = eventHandlers.get(command.eventHandlerName) + if (eventHandler === undefined) { + /* + We will create event handlers which were not created before if a listener tries to listen to a handler that does noet + exist before the emitter comes and create it. This is to aviod syncronization problems and also problems with emitters life + cycles with higher frecuency that the ones of listeners. Created in this way, event handlers are marked for deletion if + all listeners stop listening at one point in time. + */ + eventHandler = newEventHandler() + eventHandler.deleteWhenAllListenersAreGone = true + eventHandlers.set(command.eventHandlerName, eventHandler) + } + eventSubscriptionId = eventHandler.listenToEvent(command.eventHandlerName, command.eventType, command.callerId, handlerFunction, command.extraData) + + function handlerFunction(event, extraData) { + let outputData = { + action: 'Event Raised', + eventHandlerName: command.eventHandlerName, + eventType: command.eventType, + event: event, + callerId: command.callerId, + extraData: extraData + } + callbackFunction(JSON.stringify(outputData)) + } + + let response = { + result: global.DEFAULT_OK_RESPONSE.result, + message: global.DEFAULT_OK_RESPONSE.message, + eventSubscriptionId: eventSubscriptionId + } + + sendResponse(response) + return + } + case "stopListening": { + let eventHandler = eventHandlers.get(command.eventHandlerName) + + if (eventHandler === undefined) { + + /* If the event handler does not exist anymore, then there is no need to perform further actiions. */ + sendResponse(global.DEFAULT_OK_RESPONSE) + return + } + + eventHandler.stopListening(command.eventHandlerName, command.eventType, command.callerId, command.eventSubscriptionId) + + /* + We check here if there are no more listeners and the event handler original emmiter is also gone, then we need to delete + this event handlers since chances are that is not needed anymore. + */ + if (eventHandler.listeners.length === 0 && eventHandler.deleteWhenAllListenersAreGone === true) { + eventHandlers.delete(command.eventHandlerName) + } + + sendResponse(global.DEFAULT_OK_RESPONSE) + return + } + case "raiseEvent": { + let eventHandler = eventHandlers.get(command.eventHandlerName) + + if (eventHandler === undefined) { + + eventHandler = newEventHandler() + eventHandlers.set(command.eventHandlerName, eventHandler) + + /* No matter if it is the listener or the emiter the one that acts first, if an event handler does not exist we just create it acan keep it there. */ + + } + //console.log("[INFO] BackendServers -> Events Server -> Raising Event " + command.eventHandlerName + " " + command.eventType) + eventHandler.raiseEvent(command.eventType, command.event) + sendResponse(global.DEFAULT_OK_RESPONSE) + return + } + } + + console.log("[WARN] BackendServers -> Events Server -> onMessage -> Unknown Command Received:" + data) + + function sendResponse(message) { + if (command.callerId !== undefined) { + message.callerId = command.callerId + } + message.action = 'Event Server Response' + callbackFunction(JSON.stringify(message)) + } + + } catch (err) { + console.log("[ERROR] BackendServers -> Events Server -> onMessage -> Bad Command Received:" + data) + console.log("[ERROR] BackendServers -> Events Server -> onMessage -> An Error Happened:" + err.stack) + } + } + + function run() { + console.log('Events Server Started.') + } + + function newEventHandler() { + let thisObject = { + name: undefined, // This is for debugging purposes only. + deleteWhenAllListenersAreGone: false, + listeners: [], // Here we store all the functions we will call when an event is raiseed. + listenToEvent: listenToEvent, + stopListening: stopListening, + raiseEvent: raiseEvent, + finalize: finalize + } + + return thisObject + + function finalize() { + thisObject.listeners = [] + } + + function listenToEvent(eventHandlerName, eventType, callerId, handler, extraData) { + let eventSubscriptionId = Math.trunc(Math.random() * 1000000) + thisObject.listeners.push([eventHandlerName, eventType, callerId, handler, extraData, eventSubscriptionId]) + return eventSubscriptionId + } + + function stopListening(eventHandlerName, eventType, callerId, eventSubscriptionId) { + + if (eventSubscriptionId !== undefined) { + for (let i = 0; i < thisObject.listeners.length; i++) { + if (eventSubscriptionId === thisObject.listeners[i][5]) { + thisObject.listeners.splice(i, 1) + return + } + } + } + if (eventHandlerName !== undefined && eventType !== undefined && callerId !== undefined) { + for (let i = 0; i < thisObject.listeners.length; i++) { + if (eventHandlerName === thisObject.listeners[i][0] && eventType === thisObject.listeners[i][1] && callerId === thisObject.listeners[i][2]) { + thisObject.listeners.splice(i, 1) + return + } + } + } + } + + function raiseEvent(eventType, event) { + for (let i = 0; i < thisObject.listeners.length; i++) { + /* We will execute all the functions listening to this event type. */ + + if (thisObject.listeners[i][1] === eventType) { + let handler = thisObject.listeners[i][3] + let extraData = thisObject.listeners[i][4] + + handler(event, extraData) + } + } + } + } +} \ No newline at end of file diff --git a/TaskManager/node_modules/child_process/package.json b/BackendServers/node_modules/child_process/package.json similarity index 87% rename from TaskManager/node_modules/child_process/package.json rename to BackendServers/node_modules/child_process/package.json index 3d6309506..bf3b85ff6 100644 --- a/TaskManager/node_modules/child_process/package.json +++ b/BackendServers/node_modules/child_process/package.json @@ -1,28 +1,27 @@ { - "_from": "child_process", + "_from": "child_process@^1.0.2", "_id": "child_process@1.0.2", "_inBundle": false, "_integrity": "sha1-sffn/HPSXn/R1FWtyU4UODAYK1o=", "_location": "/child_process", "_phantomChildren": {}, "_requested": { - "type": "tag", + "type": "range", "registry": true, - "raw": "child_process", + "raw": "child_process@^1.0.2", "name": "child_process", "escapedName": "child_process", - "rawSpec": "", + "rawSpec": "^1.0.2", "saveSpec": null, - "fetchSpec": "latest" + "fetchSpec": "^1.0.2" }, "_requiredBy": [ - "#USER", "/" ], "_resolved": "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz", "_shasum": "b1f7e7fc73d25e7fd1d455adc94e143830182b5a", - "_spec": "child_process", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\BackendServer", + "_spec": "child_process@^1.0.2", + "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\BackendServers", "author": "", "bugs": { "url": "https://github.com/npm/security-holder/issues" diff --git a/TaskManager/node_modules/dotenv/config.js b/BackendServers/node_modules/dotenv/config.js similarity index 100% rename from TaskManager/node_modules/dotenv/config.js rename to BackendServers/node_modules/dotenv/config.js diff --git a/TaskManager/node_modules/dotenv/lib/cli-options.js b/BackendServers/node_modules/dotenv/lib/cli-options.js similarity index 100% rename from TaskManager/node_modules/dotenv/lib/cli-options.js rename to BackendServers/node_modules/dotenv/lib/cli-options.js diff --git a/TaskManager/node_modules/dotenv/lib/env-options.js b/BackendServers/node_modules/dotenv/lib/env-options.js similarity index 100% rename from TaskManager/node_modules/dotenv/lib/env-options.js rename to BackendServers/node_modules/dotenv/lib/env-options.js diff --git a/TaskManager/node_modules/dotenv/lib/main.js b/BackendServers/node_modules/dotenv/lib/main.js similarity index 100% rename from TaskManager/node_modules/dotenv/lib/main.js rename to BackendServers/node_modules/dotenv/lib/main.js diff --git a/WebSocketsServer/node_modules/dotenv/package.json b/BackendServers/node_modules/dotenv/package.json similarity index 88% rename from WebSocketsServer/node_modules/dotenv/package.json rename to BackendServers/node_modules/dotenv/package.json index e34966ff3..a23bec94a 100644 --- a/WebSocketsServer/node_modules/dotenv/package.json +++ b/BackendServers/node_modules/dotenv/package.json @@ -1,28 +1,27 @@ { - "_from": "dotenv", + "_from": "dotenv@^8.2.0", "_id": "dotenv@8.2.0", "_inBundle": false, "_integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", "_location": "/dotenv", "_phantomChildren": {}, "_requested": { - "type": "tag", + "type": "range", "registry": true, - "raw": "dotenv", + "raw": "dotenv@^8.2.0", "name": "dotenv", "escapedName": "dotenv", - "rawSpec": "", + "rawSpec": "^8.2.0", "saveSpec": null, - "fetchSpec": "latest" + "fetchSpec": "^8.2.0" }, "_requiredBy": [ - "#USER", "/" ], "_resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", "_shasum": "97e619259ada750eea3e4ea3e26bceea5424b16a", - "_spec": "dotenv", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\WebSocketsServer", + "_spec": "dotenv@^8.2.0", + "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\BackendServers", "bugs": { "url": "https://github.com/motdotla/dotenv/issues" }, diff --git a/WebSocketsServer/node_modules/dotenv/types/tsconfig.json b/BackendServers/node_modules/dotenv/types/tsconfig.json similarity index 100% rename from WebSocketsServer/node_modules/dotenv/types/tsconfig.json rename to BackendServers/node_modules/dotenv/types/tsconfig.json diff --git a/WebSocketsServer/node_modules/dotenv/types/tslint.json b/BackendServers/node_modules/dotenv/types/tslint.json similarity index 100% rename from WebSocketsServer/node_modules/dotenv/types/tslint.json rename to BackendServers/node_modules/dotenv/types/tslint.json diff --git a/WebSocketsServer/node_modules/ws/browser.js b/BackendServers/node_modules/ws/browser.js similarity index 100% rename from WebSocketsServer/node_modules/ws/browser.js rename to BackendServers/node_modules/ws/browser.js diff --git a/WebSocketsServer/node_modules/ws/index.js b/BackendServers/node_modules/ws/index.js similarity index 100% rename from WebSocketsServer/node_modules/ws/index.js rename to BackendServers/node_modules/ws/index.js diff --git a/WebSocketsServer/node_modules/ws/lib/buffer-util.js b/BackendServers/node_modules/ws/lib/buffer-util.js similarity index 97% rename from WebSocketsServer/node_modules/ws/lib/buffer-util.js rename to BackendServers/node_modules/ws/lib/buffer-util.js index 02973ae39..3648638b0 100644 --- a/WebSocketsServer/node_modules/ws/lib/buffer-util.js +++ b/BackendServers/node_modules/ws/lib/buffer-util.js @@ -19,10 +19,12 @@ function concat(list, totalLength) { for (let i = 0; i < list.length; i++) { const buf = list[i]; - buf.copy(target, offset); + target.set(buf, offset); offset += buf.length; } + if (offset < totalLength) return target.slice(0, offset); + return target; } diff --git a/WebSocketsServer/node_modules/ws/lib/constants.js b/BackendServers/node_modules/ws/lib/constants.js similarity index 100% rename from WebSocketsServer/node_modules/ws/lib/constants.js rename to BackendServers/node_modules/ws/lib/constants.js diff --git a/WebSocketsServer/node_modules/ws/lib/event-target.js b/BackendServers/node_modules/ws/lib/event-target.js similarity index 100% rename from WebSocketsServer/node_modules/ws/lib/event-target.js rename to BackendServers/node_modules/ws/lib/event-target.js diff --git a/WebSocketsServer/node_modules/ws/lib/extension.js b/BackendServers/node_modules/ws/lib/extension.js similarity index 100% rename from WebSocketsServer/node_modules/ws/lib/extension.js rename to BackendServers/node_modules/ws/lib/extension.js diff --git a/BackendServers/node_modules/ws/lib/limiter.js b/BackendServers/node_modules/ws/lib/limiter.js new file mode 100644 index 000000000..8e990865d --- /dev/null +++ b/BackendServers/node_modules/ws/lib/limiter.js @@ -0,0 +1,54 @@ +'use strict'; + +const kDone = Symbol('kDone'); +const kRun = Symbol('kRun'); + +/** + * A very simple job queue with adjustable concurrency. Adapted from + * https://github.com/STRML/async-limiter + */ +class Limiter { + /** + * Creates a new `Limiter`. + * + * @param {Number} concurrency The maximum number of jobs allowed to run + * concurrently + */ + constructor(concurrency) { + this[kDone] = () => { + this.pending--; + this[kRun](); + }; + this.concurrency = concurrency || Infinity; + this.jobs = []; + this.pending = 0; + } + + /** + * Adds a job to the queue. + * + * @public + */ + add(job) { + this.jobs.push(job); + this[kRun](); + } + + /** + * Removes a job from the queue and runs it if possible. + * + * @private + */ + [kRun]() { + if (this.pending === this.concurrency) return; + + if (this.jobs.length) { + const job = this.jobs.shift(); + + this.pending++; + job(this[kDone]); + } + } +} + +module.exports = Limiter; diff --git a/WebSocketsServer/node_modules/ws/lib/permessage-deflate.js b/BackendServers/node_modules/ws/lib/permessage-deflate.js similarity index 94% rename from WebSocketsServer/node_modules/ws/lib/permessage-deflate.js rename to BackendServers/node_modules/ws/lib/permessage-deflate.js index ddb2aa669..7bb7c98d7 100644 --- a/WebSocketsServer/node_modules/ws/lib/permessage-deflate.js +++ b/BackendServers/node_modules/ws/lib/permessage-deflate.js @@ -1,14 +1,12 @@ 'use strict'; -const Limiter = require('async-limiter'); const zlib = require('zlib'); const bufferUtil = require('./buffer-util'); +const Limiter = require('./limiter'); const { kStatusCode, NOOP } = require('./constants'); const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]); -const EMPTY_BLOCK = Buffer.from([0x00]); - const kPerMessageDeflate = Symbol('permessage-deflate'); const kTotalLength = Symbol('total-length'); const kCallback = Symbol('callback'); @@ -66,7 +64,7 @@ class PerMessageDeflate { this._options.concurrencyLimit !== undefined ? this._options.concurrencyLimit : 10; - zlibLimiter = new Limiter({ concurrency }); + zlibLimiter = new Limiter(concurrency); } } @@ -133,12 +131,18 @@ class PerMessageDeflate { } if (this._deflate) { - if (this._deflate[kCallback]) { - this._deflate[kCallback](); - } + const callback = this._deflate[kCallback]; this._deflate.close(); this._deflate = null; + + if (callback) { + callback( + new Error( + 'The deflate stream was closed while data was being processed' + ) + ); + } } } @@ -288,7 +292,7 @@ class PerMessageDeflate { } /** - * Decompress data. Concurrency limited by async-limiter. + * Decompress data. Concurrency limited. * * @param {Buffer} data Compressed data * @param {Boolean} fin Specifies whether or not this is the last fragment @@ -296,7 +300,7 @@ class PerMessageDeflate { * @public */ decompress(data, fin, callback) { - zlibLimiter.push((done) => { + zlibLimiter.add((done) => { this._decompress(data, fin, (err, result) => { done(); callback(err, result); @@ -305,7 +309,7 @@ class PerMessageDeflate { } /** - * Compress data. Concurrency limited by async-limiter. + * Compress data. Concurrency limited. * * @param {Buffer} data Data to compress * @param {Boolean} fin Specifies whether or not this is the last fragment @@ -313,12 +317,10 @@ class PerMessageDeflate { * @public */ compress(data, fin, callback) { - zlibLimiter.push((done) => { + zlibLimiter.add((done) => { this._compress(data, fin, (err, result) => { done(); - if (err || result) { - callback(err, result); - } + callback(err, result); }); }); } @@ -393,11 +395,6 @@ class PerMessageDeflate { * @private */ _compress(data, fin, callback) { - if (!data || data.length === 0) { - process.nextTick(callback, null, EMPTY_BLOCK); - return; - } - const endpoint = this._isServer ? 'server' : 'client'; if (!this._deflate) { @@ -431,10 +428,7 @@ class PerMessageDeflate { this._deflate.flush(zlib.Z_SYNC_FLUSH, () => { if (!this._deflate) { // - // This `if` statement is only needed for Node.js < 10.0.0 because as of - // commit https://github.com/nodejs/node/commit/5e3f5164, the flush - // callback is no longer called if the deflate stream is closed while - // data is being processed. + // The deflate stream was closed while data was being processed. // return; } diff --git a/WebSocketsServer/node_modules/ws/lib/receiver.js b/BackendServers/node_modules/ws/lib/receiver.js similarity index 94% rename from WebSocketsServer/node_modules/ws/lib/receiver.js rename to BackendServers/node_modules/ws/lib/receiver.js index 28ffca0f5..57daa725d 100644 --- a/WebSocketsServer/node_modules/ws/lib/receiver.js +++ b/BackendServers/node_modules/ws/lib/receiver.js @@ -30,14 +30,17 @@ class Receiver extends Writable { * * @param {String} binaryType The type for binary data * @param {Object} extensions An object containing the negotiated extensions + * @param {Boolean} isServer Specifies whether to operate in client or server + * mode * @param {Number} maxPayload The maximum allowed message length */ - constructor(binaryType, extensions, maxPayload) { + constructor(binaryType, extensions, isServer, maxPayload) { super(); this._binaryType = binaryType || BINARY_TYPES[0]; this[kWebSocket] = undefined; this._extensions = extensions || {}; + this._isServer = !!isServer; this._maxPayload = maxPayload | 0; this._bufferedBytes = 0; @@ -96,11 +99,12 @@ class Receiver extends Writable { do { const buf = this._buffers[0]; + const offset = dst.length - n; if (n >= buf.length) { - this._buffers.shift().copy(dst, dst.length - n); + dst.set(this._buffers.shift(), offset); } else { - buf.copy(dst, dst.length - n, 0, n); + dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset); this._buffers[0] = buf.slice(n); } @@ -224,6 +228,16 @@ class Receiver extends Writable { if (!this._fin && !this._fragmented) this._fragmented = this._opcode; this._masked = (buf[1] & 0x80) === 0x80; + if (this._isServer) { + if (!this._masked) { + this._loop = false; + return error(RangeError, 'MASK must be set', true, 1002); + } + } else if (this._masked) { + this._loop = false; + return error(RangeError, 'MASK must be clear', true, 1002); + } + if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16; else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64; else return this.haveLength(); diff --git a/WebSocketsServer/node_modules/ws/lib/sender.js b/BackendServers/node_modules/ws/lib/sender.js similarity index 91% rename from WebSocketsServer/node_modules/ws/lib/sender.js rename to BackendServers/node_modules/ws/lib/sender.js index a9bcef201..75c78fb35 100644 --- a/WebSocketsServer/node_modules/ws/lib/sender.js +++ b/BackendServers/node_modules/ws/lib/sender.js @@ -110,7 +110,13 @@ class Sender { buf = Buffer.allocUnsafe(2); buf.writeUInt16BE(code, 0); } else { - buf = Buffer.allocUnsafe(2 + Buffer.byteLength(data)); + const length = Buffer.byteLength(data); + + if (length > 123) { + throw new RangeError('The message must not be greater than 123 bytes'); + } + + buf = Buffer.allocUnsafe(2 + length); buf.writeUInt16BE(code, 0); buf.write(data, 2); } @@ -154,6 +160,10 @@ class Sender { ping(data, mask, cb) { const buf = toBuffer(data); + if (buf.length > 125) { + throw new RangeError('The data size must not be greater than 125 bytes'); + } + if (this._deflating) { this.enqueue([this.doPing, buf, mask, toBuffer.readOnly, cb]); } else { @@ -194,6 +204,10 @@ class Sender { pong(data, mask, cb) { const buf = toBuffer(data); + if (buf.length > 125) { + throw new RangeError('The data size must not be greater than 125 bytes'); + } + if (this._deflating) { this.enqueue([this.doPong, buf, mask, toBuffer.readOnly, cb]); } else { @@ -306,6 +320,22 @@ class Sender { this._deflating = true; perMessageDeflate.compress(data, options.fin, (_, buf) => { + if (this._socket.destroyed) { + const err = new Error( + 'The socket was closed while data was being compressed' + ); + + if (typeof cb === 'function') cb(err); + + for (let i = 0; i < this._queue.length; i++) { + const callback = this._queue[i][4]; + + if (typeof callback === 'function') callback(err); + } + + return; + } + this._deflating = false; options.readOnly = false; this.sendFrame(Sender.frame(buf, options), cb); diff --git a/WebSocketsServer/node_modules/ws/lib/stream.js b/BackendServers/node_modules/ws/lib/stream.js similarity index 85% rename from WebSocketsServer/node_modules/ws/lib/stream.js rename to BackendServers/node_modules/ws/lib/stream.js index adfcf3193..c6811afb1 100644 --- a/WebSocketsServer/node_modules/ws/lib/stream.js +++ b/BackendServers/node_modules/ws/lib/stream.js @@ -67,7 +67,6 @@ function createWebSocketStream(ws, options) { autoDestroy: false, emitClose: false, objectMode: false, - readableObjectMode: false, writableObjectMode: false }); @@ -79,6 +78,8 @@ function createWebSocketStream(ws, options) { }); ws.once('error', function error(err) { + if (duplex.destroyed) return; + duplex.destroy(err); }); @@ -95,8 +96,15 @@ function createWebSocketStream(ws, options) { return; } - ws.once('close', function close() { + let called = false; + + ws.once('error', function error(err) { + called = true; callback(err); + }); + + ws.once('close', function close() { + if (!called) callback(err); process.nextTick(emitClose, duplex); }); ws.terminate(); @@ -110,6 +118,12 @@ function createWebSocketStream(ws, options) { return; } + // If the value of the `_socket` property is `null` it means that `ws` is a + // client websocket and the handshake failed. In fact, when this happens, a + // socket is never assigned to the websocket. Wait for the `'error'` event + // that will be emitted by the websocket. + if (ws._socket === null) return; + if (ws._socket._writableState.finished) { if (duplex._readableState.endEmitted) duplex.destroy(); callback(); @@ -117,7 +131,7 @@ function createWebSocketStream(ws, options) { ws._socket.once('finish', function finish() { // `duplex` is not destroyed here because the `'end'` event will be // emitted on `duplex` after this `'finish'` event. The EOF signaling - // `null` chunk is, in fact, pushed when the WebSocket emits `'close'`. + // `null` chunk is, in fact, pushed when the websocket emits `'close'`. callback(); }); ws.close(); diff --git a/WebSocketsServer/node_modules/ws/lib/validation.js b/BackendServers/node_modules/ws/lib/validation.js similarity index 96% rename from WebSocketsServer/node_modules/ws/lib/validation.js rename to BackendServers/node_modules/ws/lib/validation.js index 479a7db08..32db5a570 100644 --- a/WebSocketsServer/node_modules/ws/lib/validation.js +++ b/BackendServers/node_modules/ws/lib/validation.js @@ -21,7 +21,7 @@ try { exports.isValidStatusCode = (code) => { return ( (code >= 1000 && - code <= 1013 && + code <= 1014 && code !== 1004 && code !== 1005 && code !== 1006) || diff --git a/WebSocketsServer/node_modules/ws/lib/websocket-server.js b/BackendServers/node_modules/ws/lib/websocket-server.js similarity index 100% rename from WebSocketsServer/node_modules/ws/lib/websocket-server.js rename to BackendServers/node_modules/ws/lib/websocket-server.js diff --git a/WebSocketsServer/node_modules/ws/lib/websocket.js b/BackendServers/node_modules/ws/lib/websocket.js similarity index 99% rename from WebSocketsServer/node_modules/ws/lib/websocket.js rename to BackendServers/node_modules/ws/lib/websocket.js index cd8929bdc..ca72ad76d 100644 --- a/WebSocketsServer/node_modules/ws/lib/websocket.js +++ b/BackendServers/node_modules/ws/lib/websocket.js @@ -141,6 +141,7 @@ class WebSocket extends EventEmitter { const receiver = new Receiver( this._binaryType, this._extensions, + this._isServer, maxPayload ); @@ -178,9 +179,8 @@ class WebSocket extends EventEmitter { * @private */ emitClose() { - this.readyState = WebSocket.CLOSED; - if (!this._socket) { + this.readyState = WebSocket.CLOSED; this.emit('close', this._closeCode, this._closeMessage); return; } @@ -190,6 +190,7 @@ class WebSocket extends EventEmitter { } this._receiver.removeAllListeners(); + this.readyState = WebSocket.CLOSED; this.emit('close', this._closeCode, this._closeMessage); } diff --git a/WebSocketsServer/node_modules/ws/package.json b/BackendServers/node_modules/ws/package.json similarity index 69% rename from WebSocketsServer/node_modules/ws/package.json rename to BackendServers/node_modules/ws/package.json index 1b81ee964..0d6236c58 100644 --- a/WebSocketsServer/node_modules/ws/package.json +++ b/BackendServers/node_modules/ws/package.json @@ -1,28 +1,27 @@ { - "_from": "ws", - "_id": "ws@7.1.2", + "_from": "ws@^7.1.2", + "_id": "ws@7.2.3", "_inBundle": false, - "_integrity": "sha512-gftXq3XI81cJCgkUiAVixA0raD9IVmXqsylCrjRygw4+UOOGzPoxnQ6r/CnVL9i+mDncJo94tSkyrtuuQVBmrg==", + "_integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==", "_location": "/ws", "_phantomChildren": {}, "_requested": { - "type": "tag", + "type": "range", "registry": true, - "raw": "ws", + "raw": "ws@^7.1.2", "name": "ws", "escapedName": "ws", - "rawSpec": "", + "rawSpec": "^7.1.2", "saveSpec": null, - "fetchSpec": "latest" + "fetchSpec": "^7.1.2" }, "_requiredBy": [ - "#USER", "/" ], - "_resolved": "https://registry.npmjs.org/ws/-/ws-7.1.2.tgz", - "_shasum": "c672d1629de8bb27a9699eb599be47aeeedd8f73", - "_spec": "ws", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\WebSockets-Server", + "_resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", + "_shasum": "a5411e1fb04d5ed0efee76d26d5c46d830c39b46", + "_spec": "ws@^7.1.2", + "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\BackendServers", "author": { "name": "Einar Otto Stangvik", "email": "einaros@gmail.com", @@ -33,9 +32,6 @@ "url": "https://github.com/websockets/ws/issues" }, "bundleDependencies": false, - "dependencies": { - "async-limiter": "^1.0.0" - }, "deprecated": false, "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js", "devDependencies": { @@ -45,11 +41,14 @@ "eslint": "^6.0.0", "eslint-config-prettier": "^6.0.0", "eslint-plugin-prettier": "^3.0.1", - "mocha": "^6.1.3", - "nyc": "^14.0.0", + "mocha": "^7.0.0", + "nyc": "^15.0.0", "prettier": "^1.17.0", "utf-8-validate": "^5.0.2" }, + "engines": { + "node": ">=8.3.0" + }, "files": [ "browser.js", "index.js", @@ -73,6 +72,18 @@ "license": "MIT", "main": "index.js", "name": "ws", + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + }, "repository": { "type": "git", "url": "git+https://github.com/websockets/ws.git" @@ -82,5 +93,5 @@ "lint": "eslint --ignore-path .gitignore . && prettier --check --ignore-path .gitignore \"**/*.{json,md,yaml,yml}\"", "test": "npm run lint && nyc --reporter=html --reporter=text mocha --throw-deprecation test/*.test.js" }, - "version": "7.1.2" + "version": "7.2.3" } diff --git a/BackendServers/package-lock.json b/BackendServers/package-lock.json new file mode 100644 index 000000000..1bc75af81 --- /dev/null +++ b/BackendServers/package-lock.json @@ -0,0 +1,23 @@ +{ + "name": "backend-server", + "version": "0.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "child_process": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz", + "integrity": "sha1-sffn/HPSXn/R1FWtyU4UODAYK1o=" + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, + "ws": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", + "integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==" + } + } +} diff --git a/TaskManager/package.json b/BackendServers/package.json similarity index 80% rename from TaskManager/package.json rename to BackendServers/package.json index 567884cf5..37c6ecb63 100644 --- a/TaskManager/package.json +++ b/BackendServers/package.json @@ -8,7 +8,7 @@ }, "dependencies": { "child_process": "^1.0.2", - "dotenv": "^8.1.0", - "node-ipc": "^9.1.1" + "dotenv": "^8.2.0", + "ws": "^7.1.2" } } diff --git a/BackendServers/server.js b/BackendServers/server.js new file mode 100644 index 000000000..a9636899b --- /dev/null +++ b/BackendServers/server.js @@ -0,0 +1,49 @@ + +process.on('uncaughtException', function (err) { + if (err.message.indexOf("EADDRINUSE") > 0) { + console.log("Superalgos Backend Server cannot be started. Reason: the port " + port + " is already in use by another application.") + return + } + console.log('[ERROR] Backend Server -> server -> uncaughtException -> err.message = ' + err.message) + console.log('[ERROR] Backend Server -> server -> uncaughtException -> err.stack = ' + err.stack) + process.exit(1) +}) + +process.on('unhandledRejection', (reason, p) => { + console.log('[ERROR] Backend Server -> server -> unhandledRejection -> reason = ' + JSON.stringify(reason)) + console.log('[ERROR] Backend Server -> server -> unhandledRejection -> p = ' + JSON.stringify(p)) + process.exit(1) +}) + +/* Callbacks default responses. */ + +global.DEFAULT_OK_RESPONSE = { + result: "Ok", + message: "Operation Succeeded" +}; + +global.DEFAULT_FAIL_RESPONSE = { + result: "Fail", + message: "Operation Failed" +}; + +let EVENTS_SERVER = require('./eventsServer.js'); +let WEB_SOCKETS_SERVER = require('./webSocketsServer.js'); +let TASK_MANAGER_SERVER = require('./taskManagerServer.js'); + +try { + EVENTS_SERVER = EVENTS_SERVER.newEventsServer() + EVENTS_SERVER.initialize() + EVENTS_SERVER.run() + + WEB_SOCKETS_SERVER = WEB_SOCKETS_SERVER.newWebSocketsServer(EVENTS_SERVER) + WEB_SOCKETS_SERVER.initialize() + WEB_SOCKETS_SERVER.run() + + TASK_MANAGER_SERVER = TASK_MANAGER_SERVER.newTaskManagerServer(WEB_SOCKETS_SERVER, EVENTS_SERVER) + TASK_MANAGER_SERVER.initialize() + TASK_MANAGER_SERVER.run() +} catch (err) { + console.log('[ERROR] BackendServers -> Task Manager -> server -> Error = ' + err.stack) +} + diff --git a/BackendServers/taskManagerServer.js b/BackendServers/taskManagerServer.js new file mode 100644 index 000000000..72b1d3b24 --- /dev/null +++ b/BackendServers/taskManagerServer.js @@ -0,0 +1,295 @@ +exports.newTaskManagerServer = function newTaskManagerServer(WEB_SOCKETS_SERVER, EVENTS_SERVER) { + + const MODULE = "Task Manager Server" + + let thisObject = { + initialize: initialize, + finalize: finalize, + run: run + } + + /* + + This server creates and destroys Task Servers according to what is going on at the UI. Each of these created servers will do their own + work. The responsibility of this server is to manage those children processes in order to be in sync with what the end user want and is defining + at the user interface. + + */ + + const { fork } = require('child_process') + require('dotenv').config() + tasks = new Map() + + return thisObject + + function finalize() { + + } + + function initialize() { + + } + + function run() { + + /* + + Here we will create an Event Handler for this server. After that we will listen to events happening here. Elements of the UI will raise events here, + as a way to communicate what is going on with the user interacting with UI components. That is the way this server will know for example when a new + task needs to be created or destroyed. + + */ + + let eventsServerClient = newEventsServerClient() + eventsServerClient.createEventHandler('Task Manager') + eventsServerClient.listenToEvent('Task Manager', 'Run Task', undefined, undefined, undefined, runTask) + eventsServerClient.listenToEvent('Task Manager', 'Stop Task', undefined, undefined, undefined, stopTask) + + console.log('Task Manager Server Started.') + + function runTask(message) { + //console.log('[INFO] BackendServers -> Task Manager Server -> runTask -> Entering function.') + + if (message.event === undefined) { + console.log('[WARN] BackendServers -> Task Manager Server -> runTask -> Message Received Without Event -> message = ' + JSON.stringify(message)) + return + } + + if (message.event.taskId === undefined) { + console.log('[WARN] BackendServers -> Task Manager Server -> runTask -> Message Received Without taskId -> message = ' + JSON.stringify(message)) + return + } + + if (message.event.definition === undefined) { + console.log('[WARN] BackendServers -> Task Manager Server -> runTask -> Message Received Without Definition -> message = ' + JSON.stringify(message)) + return + } + + if (tasks.get(message.event.taskId) !== undefined) { + //console.log('[WARN] BackendServers -> Task Manager Server -> runTask -> Task Already Running -> taskId = ' + message.event.taskId) + return + } + //console.log('[INFO] BackendServers -> Task Manager Server -> runTask -> Task Name = ' + message.event.taskName) + //console.log('[INFO] BackendServers -> Task Manager Server -> runTask -> Task Id = ' + message.event.taskId) + + let path = process.env.TASK_SERVER_PATH + '/server.js' + + /* Workarround to avoid having the same debug port at the forked process which makes it crash. */ + for (let i = 0; i < process.execArgv.length; i++) { + let argument = process.execArgv[i] + if (argument.indexOf('--inspect') > -1) { + process.execArgv[i] = '' + } + } + + /* Forking this process. */ + let task = { + childProcess: fork(path, [message.event.taskId], { stdio: 'inherit' }), + id: message.event.taskId, + name: message.event.taskName + } + + tasks.set(message.event.taskId, task) + + task.childProcess.on('error', (err) => { + console.log('[ERROR] BackendServers -> Task Manager Server -> runTask -> Problem with Task Name = ' + task.name) + console.log('[ERROR] BackendServers -> Task Manager Server -> runTask -> Problem with Task Id = ' + task.id) + console.log(`[ERROR] BackendServers -> Task Manager Server -> runTask -> Task Manager exited with error ${err}`) + }) + task.childProcess.on('close', (code, signal) => { + //console.log('[INFO] BackendServers -> Task Manager Server -> runTask -> Task Terminated. -> Task Name = ' + task.name) + //console.log('[INFO] BackendServers -> Task Manager Server -> runTask -> Task Terminated. -> Task Id = ' + task.id) + tasks.delete(task.id) + }) + + eventsServerClient.listenToEvent('Task Manager - ' + message.event.taskId, 'Nodejs Process Ready for Task', undefined, undefined, undefined, sendStartingEvent) + + function sendStartingEvent() { + //console.log('[INFO] BackendServers -> Task Manager Server -> runTask -> Emitting Event -> key = ' + 'Task Server - ' + task.id) + eventsServerClient.raiseEvent('Task Server - ' + task.id, 'Run Task', message.event) + } + } + + function stopTask(message) { + + //console.log('[INFO] BackendServers -> Task Manager Server -> stopTask -> Entering function.') + + if (message.event === undefined) { + console.log('[WARN] BackendServers -> Task Manager Server -> stopTask -> Message Received Without Event -> message = ' + JSON.stringify(message)) + return + } + + if (message.event.taskId === undefined) { + console.log('[WARN] BackendServers -> Task Manager Server -> stopTask -> Message Received Without taskId -> message = ' + JSON.stringify(message)) + return + } + + //console.log('[INFO] BackendServers -> Task Manager Server -> stopTask -> Task Name = ' + message.event.taskName) + //console.log('[INFO] BackendServers -> Task Manager Server -> stopTask -> Task Id = ' + message.event.taskId) + + let task = tasks.get(message.event.taskId) + + if (task) { + task.childProcess.send('Stop this Task'); + //console.log('[INFO] BackendServers -> Task Manager Server -> stopTask -> Child Process instructed to finish.') + } else { + console.log('[WARN] BackendServers -> Task Manager Server -> stopTask -> Cannot delete Task that does not exist.') + } + } + } + + function newEventsServerClient() { + let thisObject = { + initialize: initialize, + finalize: finalize, + createEventHandler: createEventHandler, + deleteEventHandler: deleteEventHandler, + listenToEvent: listenToEvent, + stopListening: stopListening, + raiseEvent: raiseEvent, + onMessage: onMessage + } + + let eventListeners = new Map() + let responseWaiters = new Map() + + return thisObject + + + function finalize() { + /* Before disconnecting we will forze all eventListeners to stop listening. */ + const eventListenersArray = [...eventListeners.values()] + for (let i = 0; i < eventListenersArray.length; i++) { + let handler = eventListenersArray[i] + let eventCommand = { + action: 'stopListening', + eventHandlerName: handler.eventHandlerName, + eventType: handler.eventType, + callerId: handler.callerId + } + sendCommand(eventCommand) + } + } + + function initialize() { + + } + + function onMessage(data) { + try { + let message = JSON.parse(data) + + if (message.action === 'Event Raised') { + let key + if (message.callerId) { + key = message.eventHandlerName + '-' + message.eventType + '-' + message.callerId + } else { + key = message.eventHandlerName + '-' + message.eventType + } + let handler = eventListeners.get(key) + if (handler) { + handler.callBack(message) + } else { + console.log(key + ' not found so could not deliver event raised.') + console.log(' Message = ' + data) + } + return + } + + if (message.action === 'Event Server Response') { + let handler = responseWaiters.get(message.callerId) + if (handler) { + handler(message) + } + return + } + } catch (err) { + console.log('[ERROR] BackendServers -> Task Manager Server -> onMessage -> Error Receiving Message from Events Server -> data = ' + JSON.stringify(data)) + console.log('[ERROR] BackendServers -> Task Manager Server -> onMessage -> Error Receiving Message from Events Server -> error = ' + err.stack) + } + } + + function sendCommand(command, responseCallBack, eventsCallBack) { + try { + if (command.action === 'listenToEvent') { + let key + if (command.callerId) { + key = command.eventHandlerName + '-' + command.eventType + '-' + command.callerId + } else { + key = command.eventHandlerName + '-' + command.eventType + } + let handler = { + eventHandlerName: command.eventHandlerName, + eventType: command.eventType, + callerId: command.callerId, + callBack: eventsCallBack + } + eventListeners.set(key, handler) + } + if (command.callerId && responseCallBack) { + responseWaiters.set(command.callerId, responseCallBack) + } + + EVENTS_SERVER.onMessage(JSON.stringify(command), thisObject.onMessage) + } catch (err) { + console.log('[ERROR] BackendServers -> Task Manager Server -> sendCommand -> Error Sending Command to Events Server -> command = ' + JSON.stringify(command)) + console.log('[ERROR] BackendServers -> Task Manager Server -> sendCommand -> Error Sending Command to Events Server -> error = ' + err.stack) + } + } + + function createEventHandler(eventHandlerName, callerId, responseCallBack) { + let eventCommand = { + action: 'createEventHandler', + eventHandlerName: eventHandlerName, + callerId: callerId + } + sendCommand(eventCommand, responseCallBack) + } + + function deleteEventHandler(eventHandlerName, callerId, responseCallBack) { + let eventCommand = { + action: 'deleteEventHandler', + eventHandlerName: eventHandlerName, + callerId: callerId + } + sendCommand(eventCommand, responseCallBack) + } + + function listenToEvent(eventHandlerName, eventType, extraData, callerId, responseCallBack, eventsCallBack) { + let eventCommand = { + action: 'listenToEvent', + eventHandlerName: eventHandlerName, + eventType: eventType, + extraData: extraData, + callerId: callerId + } + sendCommand(eventCommand, responseCallBack, eventsCallBack) + } + + function stopListening(eventHandlerName, eventType, eventSubscriptionId, callerId, responseCallBack) { + /* User either needs to specify a valid eventSubscriptionId OR the 3 params: eventHandlerName, eventType, callerId which were used when start listening to events. */ + let eventCommand = { + action: 'stopListening', + eventHandlerName: eventHandlerName, + eventType: eventType, + eventSubscriptionId: eventSubscriptionId, + callerId: callerId + } + sendCommand(eventCommand, responseCallBack) + } + + function raiseEvent(eventHandlerName, eventType, event, callerId, responseCallBack) { + let eventCommand = { + action: 'raiseEvent', + eventHandlerName: eventHandlerName, + eventType: eventType, + event: event, + callerId: callerId + } + sendCommand(eventCommand, responseCallBack) + } + } +} + + + diff --git a/BackendServers/webSocketsServer.js b/BackendServers/webSocketsServer.js new file mode 100644 index 000000000..57dbc26af --- /dev/null +++ b/BackendServers/webSocketsServer.js @@ -0,0 +1,112 @@ +exports.newWebSocketsServer = function newWebSocketsServer(EVENTS_SERVER) { + + const MODULE = "Web Sockets Server" + const LOG_INFO = false + + let thisObject = { + initialize: initialize, + finalize: finalize, + run: run + } + + require('dotenv').config() + const WEB_SOCKET = require('ws') + let socketServer + let port = process.env.WEB_SOCKETS_SERVER_PORT + + return thisObject + + function finalize() { + + } + + function initialize() { + + } + + function run() { + setUpWebSocketServer() + } + + function setUpWebSocketServer() { + try { + socketServer = new WEB_SOCKET.Server({ port: port }) + + socketServer.on('connection', onConnection) + + function onConnection(socket) { + + let lastNonce = -1 + if (LOG_INFO === true) { + console.log('New Websocket Connection.') + } + + socket.on('message', onMenssage) + + function onMenssage(message){ + + try { + if (LOG_INFO === true) { + console.log('Message Received: ' + message) + } + + let messageArray = message.split('|') + + let origin = messageArray[0] + let nonce = messageArray[1] + let messageToEventServer = messageArray[2] + + if (origin === 'Web Browser') { + if (isNaN(nonce) || nonce === "") { + console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> Nonce is not a Number. message = ' + message) + console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> Nonce is not a Number. nonce = ' + nonce) + return + } + + if (nonce === "1") { // this happens once the browser is restarted, and the server is running since a previous session. + lastNonce = 0 + } + + if (Number(nonce) < Number(lastNonce)) { + console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> Nonce received is less than Last Nonce. message = ' + message) + console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> Nonce received is less than Last Nonce. nonce = ' + nonce) + console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> Nonce received is less than Last Nonce. lastNonce = ' + lastNonce) + return + } + + lastNonce = nonce + + try { + let jsonCheck = JSON.parse(messageToEventServer) + } catch (err) { + console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> Message received from the browser is not a valid JSON. message = ' + message) + console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> Message received from the browser is not a valid JSON. messageToEventServer = ' + messageToEventServer) + return + } + + let acknowledgeMessage = { + action: 'Acknowledge', + nonce: nonce + } + + socket.send(JSON.stringify(acknowledgeMessage)) + } + + + EVENTS_SERVER.onMessage(messageToEventServer, onResponse) + + function onResponse(message) { + socket.send(message) + } + } catch (err) { + console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> Nonce received is less than Last Nonce. err = ' + err.stack) + } + } + } + + console.log('Web Sockets Server Started.') + } catch (err) { + console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> err.message = ' + err.message) + } + } +} \ No newline at end of file diff --git a/CanvasApp/Canvas.js b/CanvasApp/Canvas.js index b50e017af..7959cb344 100644 --- a/CanvasApp/Canvas.js +++ b/CanvasApp/Canvas.js @@ -131,7 +131,7 @@ function newCanvas () { thisObject.animation = animation /* Low Level Infraestructure First */ - animation.addCallBackFunction('System Event Handler Physics', systemEventHandler.physics) + animation.addCallBackFunction('System Event Handler Physics', eventsServerClient.physics) /* Spcaces Physics */ animation.addCallBackFunction('CockpitSpace Physics', thisObject.cockpitSpace.physics) diff --git a/CanvasApp/DesignSpace/Workspace/FunctionLibraries/SessionFunctions.js b/CanvasApp/DesignSpace/Workspace/FunctionLibraries/SessionFunctions.js index 33542151d..a35c3ec60 100644 --- a/CanvasApp/DesignSpace/Workspace/FunctionLibraries/SessionFunctions.js +++ b/CanvasApp/DesignSpace/Workspace/FunctionLibraries/SessionFunctions.js @@ -65,7 +65,7 @@ function newSessionFunctions () { tradingSystem: JSON.stringify(tradingSystem) } - systemEventHandler.raiseEvent(key, 'Run Session', event) + eventsServerClient.raiseEvent(key, 'Run Session', event) if (node.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode === undefined) { callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) @@ -75,7 +75,7 @@ function newSessionFunctions () { function stopSession (node, functionLibraryProtocolNode, callBackFunction) { let key = node.name + '-' + node.type + '-' + node.id - systemEventHandler.raiseEvent(key, 'Stop Session') + eventsServerClient.raiseEvent(key, 'Stop Session') node.payload.uiObject.stop(callBackFunction) } diff --git a/CanvasApp/DesignSpace/Workspace/FunctionLibraries/TaskFunctions.js b/CanvasApp/DesignSpace/Workspace/FunctionLibraries/TaskFunctions.js index 330c6d668..6c89285ed 100644 --- a/CanvasApp/DesignSpace/Workspace/FunctionLibraries/TaskFunctions.js +++ b/CanvasApp/DesignSpace/Workspace/FunctionLibraries/TaskFunctions.js @@ -68,12 +68,12 @@ function newTaskFunctions () { if (node.payload.parentNode === undefined) { callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) - systemEventHandler.raiseEvent('Task Server', 'Debug Task Started', event) + eventsServerClient.raiseEvent('Task Server', 'Debug Task Started', event) return } node.payload.uiObject.run(callBackFunction) - systemEventHandler.raiseEvent('Task Manager', 'Run Task', event) + eventsServerClient.raiseEvent('Task Manager', 'Run Task', event) } function stopTask (node, functionLibraryProtocolNode, callBackFunction) { @@ -83,7 +83,7 @@ function newTaskFunctions () { } node.payload.uiObject.stop(callBackFunction) - systemEventHandler.raiseEvent('Task Manager', 'Stop Task', event) + eventsServerClient.raiseEvent('Task Manager', 'Stop Task', event) if (node.bot === undefined) { return } if (node.bot.processes.length === 0) { return } diff --git a/CanvasApp/FloatingSpace/CircularProgressBar.js b/CanvasApp/FloatingSpace/CircularProgressBar.js index a78943473..8e6a55336 100644 --- a/CanvasApp/FloatingSpace/CircularProgressBar.js +++ b/CanvasApp/FloatingSpace/CircularProgressBar.js @@ -32,7 +32,7 @@ function newCircularProgressBar () { function finalize () { let key = thisObject.payload.node.name + '-' + thisObject.payload.node.type + '-' + thisObject.payload.node.id if (eventSubscriptionIdHeartbeat !== undefined) { - systemEventHandler.stopListening(key, eventSubscriptionIdHeartbeat) + eventsServerClient.stopListening(key, eventSubscriptionIdHeartbeat) } thisObject.container = undefined @@ -48,7 +48,7 @@ function newCircularProgressBar () { } let key = thisObject.payload.node.name + '-' + thisObject.payload.node.type + '-' + thisObject.payload.node.id - systemEventHandler.listenToEvent(key, 'Heartbeat', undefined, key, onResponse, onHeartBeat) + eventsServerClient.listenToEvent(key, 'Heartbeat', undefined, key, onResponse, onHeartBeat) function onResponse (message) { eventSubscriptionIdHeartbeat = message.eventSubscriptionId diff --git a/CanvasApp/FloatingSpace/UiObject.js b/CanvasApp/FloatingSpace/UiObject.js index 1219557a7..ba8c9abdb 100644 --- a/CanvasApp/FloatingSpace/UiObject.js +++ b/CanvasApp/FloatingSpace/UiObject.js @@ -122,10 +122,10 @@ function newUiObject () { let key = thisObject.payload.node.name + '-' + thisObject.payload.node.type + '-' + thisObject.payload.node.id if (eventSubscriptionIdOnRunning !== undefined) { - systemEventHandler.stopListening(key, eventSubscriptionIdOnRunning, 'UiObject') + eventsServerClient.stopListening(key, eventSubscriptionIdOnRunning, 'UiObject') } if (eventSubscriptionIdOnStopped !== undefined) { - systemEventHandler.stopListening(key, eventSubscriptionIdOnStopped, 'UiObject') + eventsServerClient.stopListening(key, eventSubscriptionIdOnStopped, 'UiObject') } thisObject.container.eventHandler.stopListening(selfFocusEventSubscriptionId) @@ -759,7 +759,7 @@ function newUiObject () { /* We will wait to hear the Running event in order to confirm the execution was really started */ let key = thisObject.payload.node.name + '-' + thisObject.payload.node.type + '-' + thisObject.payload.node.id - systemEventHandler.listenToEvent(key, 'Running', undefined, 'UiObject', onResponse, onRunning) + eventsServerClient.listenToEvent(key, 'Running', undefined, 'UiObject', onResponse, onRunning) onRunningCallBackFunction = callBackFunction @@ -771,7 +771,7 @@ function newUiObject () { if (thisObject.payload === undefined) { return } let key = thisObject.payload.node.name + '-' + thisObject.payload.node.type + '-' + thisObject.payload.node.id - systemEventHandler.stopListening(key, eventSubscriptionIdOnRunning, 'UiObject') + eventsServerClient.stopListening(key, eventSubscriptionIdOnRunning, 'UiObject') thisObject.isRunning = true @@ -801,7 +801,7 @@ function newUiObject () { function stop (callBackFunction, event) { /* We will wait to the event that the execution was terminated in order to call back the menu item */ let key = thisObject.payload.node.name + '-' + thisObject.payload.node.type + '-' + thisObject.payload.node.id - systemEventHandler.listenToEvent(key, 'Stopped', undefined, 'UiObject', onResponse, onStopped) + eventsServerClient.listenToEvent(key, 'Stopped', undefined, 'UiObject', onResponse, onStopped) function onResponse (message) { eventSubscriptionIdOnStopped = message.eventSubscriptionId diff --git a/CanvasApp/PostLoader.js b/CanvasApp/PostLoader.js index 567be6bdf..c0f41ee78 100644 --- a/CanvasApp/PostLoader.js +++ b/CanvasApp/PostLoader.js @@ -1,6 +1,6 @@ let canvas let markets -let systemEventHandler +let eventsServerClient let APP_SCHEMA_MAP = new Map() let APP_SCHEMA_ARRAY = [] @@ -24,8 +24,8 @@ function newDashboard () { try { setBrowserEvents() - systemEventHandler = newSystemEventHandler() - systemEventHandler.initialize(setUpAppSchema) + eventsServerClient = newEventsServerClient() + eventsServerClient.initialize(setUpAppSchema) function setUpAppSchema () { APP_SCHEMA_ARRAY = getAppSchema() diff --git a/CanvasApp/SystemEventHandler.js b/CanvasApp/SystemEventHandler.js index c14021ef0..abf08b292 100644 --- a/CanvasApp/SystemEventHandler.js +++ b/CanvasApp/SystemEventHandler.js @@ -1,5 +1,5 @@ -function newSystemEventHandler () { +function newEventsServerClient () { /* Web Sockets Connection */ const MODULE_NAME = 'System Event Handler' @@ -71,7 +71,7 @@ function newSystemEventHandler () { commandsWaitingConfirmation.set(stringNonce, command) commandsSentByTimestamp.set(stringNonce, timestamp) - let messageToWebSocketServer = stringNonce + '->' + JSON.stringify(command) + let messageToWebSocketServer = 'Web Browser|' + stringNonce + '|' + JSON.stringify(command) WEB_SOCKETS_CONNECTION.send(messageToWebSocketServer) } @@ -164,9 +164,6 @@ function newSystemEventHandler () { function setuptWebSockets (callBackFunction) { try { WEB_SOCKETS_CONNECTION = new WebSocket(WEB_SOCKETS_URL) - WEB_SOCKETS_CONNECTION.onopen = () => { - console.log('Websocket connection opened.') - } WEB_SOCKETS_CONNECTION.onerror = error => { console.log('WebSocket error:' + JSON.stringify(error)) } diff --git a/EventsServer/node_modules/easy-stack/es5.js b/EventsServer/node_modules/easy-stack/es5.js deleted file mode 100644 index a756a7bbf..000000000 --- a/EventsServer/node_modules/easy-stack/es5.js +++ /dev/null @@ -1,74 +0,0 @@ -function Stack(){ - Object.defineProperties( - this, - { - add:{ - enumerable:true, - writable:false, - value:addToStack - }, - next:{ - enumerable:true, - writable:false, - value:run - }, - clear:{ - enumerable:true, - writable:false, - value:clearStack - }, - contents:{ - enumerable:false, - get:getStack, - set:setStack - }, - autoRun:{ - enumerable:true, - writable:true, - value:true - }, - stop:{ - enumerable:true, - writable:true, - value:false - } - } - ); - - var stack=[]; - var running=false; - var stop=false; - - function clearStack(){ - stack=[]; - return stack; - } - - function getStack(){ - return stack; - } - - function setStack(val){ - stack=val; - return stack; - } - - function addToStack(){ - for(var i in arguments){ - stack.unshift(arguments[i]); - } - if(!running && !this.stop && this.autoRun){ - this.next(); - } - } - - function run(){ - running=true; - if(stack.length<1 || this.stop){ - running=false; - return; - } - - stack.shift().bind(this)(); - } -} diff --git a/EventsServer/node_modules/easy-stack/example/basic.js b/EventsServer/node_modules/easy-stack/example/basic.js deleted file mode 100644 index f0d7fbb11..000000000 --- a/EventsServer/node_modules/easy-stack/example/basic.js +++ /dev/null @@ -1,18 +0,0 @@ -var Stack=require('../stack'); -//create a new Stack instance -var stack=new Stack; -stack.autoRun=false; - -for(var i=0; i<50; i++){ - //add a bunch of stuff to the stack - stack.add(makeRequest.bind(stack,i)); -} - -stack.next(); - -function makeRequest(index){ - //do stuff - console.log(`making LIFO request ${index}`); - - this.next(); -} diff --git a/EventsServer/node_modules/easy-stack/package.json b/EventsServer/node_modules/easy-stack/package.json deleted file mode 100644 index 8ac84376a..000000000 --- a/EventsServer/node_modules/easy-stack/package.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "_from": "easy-stack@^1.0.0", - "_id": "easy-stack@1.0.0", - "_inBundle": false, - "_integrity": "sha1-EskbMIWjfwuqM26UhurEv5Tj54g=", - "_location": "/easy-stack", - "_phantomChildren": {}, - "_requested": { - "type": "range", - "registry": true, - "raw": "easy-stack@^1.0.0", - "name": "easy-stack", - "escapedName": "easy-stack", - "rawSpec": "^1.0.0", - "saveSpec": null, - "fetchSpec": "^1.0.0" - }, - "_requiredBy": [ - "/js-queue" - ], - "_resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.0.tgz", - "_shasum": "12c91b3085a37f0baa336e9486eac4bf94e3e788", - "_spec": "easy-stack@^1.0.0", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\Events-Server\\node_modules\\js-queue", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/easy-stack/issues" - }, - "bundleDependencies": false, - "deprecated": false, - "description": "Simple JS stack with auto run for node and browsers", - "engines": { - "node": ">=6.0.0" - }, - "homepage": "https://github.com/RIAEvangelist/easy-stack#readme", - "keywords": [ - "stack", - "node", - "js", - "auto", - "run", - "execute", - "browser", - "react" - ], - "license": "DBAD", - "main": "stack.js", - "name": "easy-stack", - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/easy-stack.git" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "1.0.0" -} diff --git a/EventsServer/node_modules/easy-stack/stack.js b/EventsServer/node_modules/easy-stack/stack.js deleted file mode 100644 index bfadd1dee..000000000 --- a/EventsServer/node_modules/easy-stack/stack.js +++ /dev/null @@ -1,39 +0,0 @@ -class Stack{ - constructor(){ - this.stack=[]; - this.autoRun=true; - this.running=false; - this.stop=false; - } - - clear(){ - this.stack=[]; - return this.stack; - } - - contents(val){ - if(val){ - this.stack=val; - } - return this.stack; - } - - add(...callbacks){ - this.stack.push(...callbacks); - if(!this.running && !this.stop && this.autoRun){ - this.next(); - } - } - - next(){ - this.running=true; - if(this.stack.length<1 || this.stop){ - this.running=false; - return; - } - - this.stack.pop().bind(this)(); - } -} - -module.exports=Stack; diff --git a/EventsServer/node_modules/event-pubsub/bower.json b/EventsServer/node_modules/event-pubsub/bower.json deleted file mode 100644 index a207b0a5d..000000000 --- a/EventsServer/node_modules/event-pubsub/bower.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "event-pubsub", - "description": "Super light and fast Extensible PubSub events and EventEmitters for Node and the browser with support for ES6 by default, and ES5 versions for older verions of node and older IE/Safari versions. Easy for any developer level. No frills, just high speed pubsub events!", - "main": "event-pubsub.js", - "authors": [ - "Brandon Nozaki Miller" - ], - "license": "DBAD", - "keywords": [ - "event", - "events", - "pubsub", - "node", - "browser" - ], - "homepage": "https://github.com/RIAEvangelist/event-pubsub", - "moduleType": [ - "globals", - "node" - ], - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" - ] -} diff --git a/EventsServer/node_modules/event-pubsub/es5.js b/EventsServer/node_modules/event-pubsub/es5.js deleted file mode 100644 index 7faf8b737..000000000 --- a/EventsServer/node_modules/event-pubsub/es5.js +++ /dev/null @@ -1,143 +0,0 @@ -'use strict'; - -function EventPubSub() { - this._events_={}; - this.publish=this.trigger=this.emit=emit; - this.subscribe=this.on=on; - this.once=once; - this.unSubscribe=this.off=off; - this.emit$=emit$; - - function on(type,handler,once){ - if(!handler){ - throw new ReferenceError('handler not defined.'); - } - - if(!this._events_[type]){ - this._events_[type]=[]; - } - - if(once){ - handler._once_ = once; - } - this._events_[type].push(handler); - return this; - } - - function once(type,handler){ - return this.on(type, handler, true); - } - - function off(type,handler){ - if(!this._events_[type]){ - return this; - } - - if(!handler){ - throw new ReferenceError('handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler'); - } - - if(handler=='*'){ - delete this._events_[type]; - return this; - } - - var handlers=this._events_[type]; - - while(handlers.includes(handler)){ - handlers.splice( - handlers.indexOf(handler), - 1 - ); - } - - if(handlers.length<1){ - delete this._events_[type]; - } - - return this; - } - - function emit(type){ - this.emit$.apply(this, arguments); - if(!this._events_[type]){ - return this; - } - arguments.splice=Array.prototype.splice; - arguments.splice(0,1); - - var handlers=this._events_[type]; - var onceHandled=[]; - - for(var i in handlers){ - var handler=handlers[i]; - handler.apply(this, arguments); - if(handler._once_){ - onceHandled.push(handler); - } - } - - for(var i in onceHandled){ - this.off( - type, - onceHandled[i] - ); - } - - return this; - } - - function emit$(type, args){ - if(!this._events_['*']){ - return this; - } - - var catchAll=this._events_['*']; - - args.shift=Array.prototype.shift; - args.shift(type); - - for(var handler of catchAll){ - handler.apply(this, args); - } - - return this; - } - - return this; -} - -if (!Array.prototype.includes) { - Array.prototype.includes = function(searchElement /*, fromIndex*/) { - 'use strict'; - if (this == null) { - throw new TypeError('Array.prototype.includes called on null or undefined'); - } - - var O = Object(this); - var len = parseInt(O.length, 10) || 0; - if (len === 0) { - return false; - } - var n = parseInt(arguments[1], 10) || 0; - var k; - if (n >= 0) { - k = n; - } else { - k = len + n; - if (k < 0) {k = 0;} - } - var currentElement; - while (k < len) { - currentElement = O[k]; - if (searchElement === currentElement || - (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN - return true; - } - k++; - } - return false; - }; -} - -module.exports=EventPubSub; diff --git a/EventsServer/node_modules/event-pubsub/es6.js b/EventsServer/node_modules/event-pubsub/es6.js deleted file mode 100644 index e9e859f9b..000000000 --- a/EventsServer/node_modules/event-pubsub/es6.js +++ /dev/null @@ -1,99 +0,0 @@ -'use strict'; - -class EventPubSub { - constructor( scope ) { - this._events_ = {}; - this.publish = this.trigger = this.emit; - this.subscribe = this.on; - this.unSubscribe = this.off; - } - - on( type, handler, once ) { - if ( !handler ) { - throw new ReferenceError( 'handler not defined.' ); - } - - if ( !this._events_[ type ] ) { - this._events_[ type ] = []; - } - - if(once){ - handler._once_ = once; - } - - this._events_[ type ].push( handler ); - return this; - } - - once( type, handler ) { - return this.on( type, handler, true ); - } - - off( type, handler ) { - if ( !this._events_[ type ] ) { - return this; - } - - if ( !handler ) { - throw new ReferenceError( 'handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler' ); - } - - if ( handler == '*' ) { - delete this._events_[ type ]; - return this; - } - - const handlers = this._events_[ type ]; - - while ( handlers.includes( handler ) ) { - handlers.splice( - handlers.indexOf( handler ), - 1 - ); - } - - if ( handlers.length < 1 ) { - delete this._events_[ type ]; - } - - return this; - } - - emit( type, ...args ) { - if ( !this._events_[ type ] ) { - return this.emit$( type, ...args ); - } - - const handlers = this._events_[ type ]; - const onceHandled=[]; - - for ( let handler of handlers ) { - handler.apply( this, args ); - if(handler._once_){ - onceHandled.push(handler); - } - } - - for(let handler of onceHandled){ - this.off(type,handler); - } - - return this.emit$( type, ...args ); - } - - emit$( type, ...args ) { - if ( !this._events_[ '*' ] ) { - return this; - } - - const catchAll = this._events_[ '*' ]; - - for ( let handler of catchAll ) { - handler.call( this, type, ...args ); - } - - return this; - } -} - -module.exports = EventPubSub; diff --git a/EventsServer/node_modules/event-pubsub/event-pubsub-browser-es5.js b/EventsServer/node_modules/event-pubsub/event-pubsub-browser-es5.js deleted file mode 100644 index 03f27625e..000000000 --- a/EventsServer/node_modules/event-pubsub/event-pubsub-browser-es5.js +++ /dev/null @@ -1,141 +0,0 @@ -'use strict'; - -window.EventPubSub=function EventPubSub() { - this._events_={}; - this.publish=this.trigger=this.emit=emit; - this.subscribe=this.on=on; - this.once=once; - this.unSubscribe=this.off=off; - this.emit$=emit$; - - function on(type,handler,once){ - if(!handler){ - throw new ReferenceError('handler not defined.'); - } - - if(!this._events_[type]){ - this._events_[type]=[]; - } - - if(once){ - handler._once_ = once; - } - this._events_[type].push(handler); - return this; - } - - function once(type,handler){ - return this.on(type, handler, true); - } - - function off(type,handler){ - if(!this._events_[type]){ - return this; - } - - if(!handler){ - throw new ReferenceError('handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler'); - } - - if(handler=='*'){ - delete this._events_[type]; - return this; - } - - var handlers=this._events_[type]; - - while(handlers.includes(handler)){ - handlers.splice( - handlers.indexOf(handler), - 1 - ); - } - - if(handlers.length<1){ - delete this._events_[type]; - } - - return this; - } - - function emit(type){ - this.emit$.apply(this, arguments); - if(!this._events_[type]){ - return this; - } - arguments.splice=Array.prototype.splice; - arguments.splice(0,1); - - var handlers=this._events_[type]; - var onceHandled=[]; - - for(var i in handlers){ - var handler=handlers[i]; - handler.apply(this, arguments); - if(handler._once_){ - onceHandled.push(handler); - } - } - - for(var i in onceHandled){ - this.off( - type, - onceHandled[i] - ); - } - - return this; - } - - function emit$(type, args){ - if(!this._events_['*']){ - return this; - } - - var catchAll=this._events_['*']; - - args.shift=Array.prototype.shift; - args.shift(type); - - for(var handler of catchAll){ - handler.apply(this, args); - } - - return this; - } - - return this; -} - -if (!Array.prototype.includes) { - Array.prototype.includes = function(searchElement /*, fromIndex*/) { - 'use strict'; - if (this == null) { - throw new TypeError('Array.prototype.includes called on null or undefined'); - } - - var O = Object(this); - var len = parseInt(O.length, 10) || 0; - if (len === 0) { - return false; - } - var n = parseInt(arguments[1], 10) || 0; - var k; - if (n >= 0) { - k = n; - } else { - k = len + n; - if (k < 0) {k = 0;} - } - var currentElement; - while (k < len) { - currentElement = O[k]; - if (searchElement === currentElement || - (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN - return true; - } - k++; - } - return false; - }; -} diff --git a/EventsServer/node_modules/event-pubsub/event-pubsub-browser.js b/EventsServer/node_modules/event-pubsub/event-pubsub-browser.js deleted file mode 100644 index d0bcd7b56..000000000 --- a/EventsServer/node_modules/event-pubsub/event-pubsub-browser.js +++ /dev/null @@ -1,130 +0,0 @@ -'use strict'; - -window.EventPubSub=class EventPubSub { - constructor( scope ) { - this._events_ = {}; - this.publish = this.trigger = this.emit; - this.subscribe = this.on; - this.unSubscribe = this.off; - } - - on( type, handler, once ) { - if ( !handler ) { - throw new ReferenceError( 'handler not defined.' ); - } - - if ( !this._events_[ type ] ) { - this._events_[ type ] = []; - } - - if(once){ - handler._once_ = once; - } - - this._events_[ type ].push( handler ); - return this; - } - - once( type, handler ) { - return this.on( type, handler, true ); - } - - off( type, handler ) { - if ( !this._events_[ type ] ) { - return this; - } - - if ( !handler ) { - throw new ReferenceError( 'handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler' ); - } - - if ( handler == '*' ) { - delete this._events_[ type ]; - return this; - } - - const handlers = this._events_[ type ]; - - while ( handlers.includes( handler ) ) { - handlers.splice( - handlers.indexOf( handler ), - 1 - ); - } - - if ( handlers.length < 1 ) { - delete this._events_[ type ]; - } - - return this; - } - - emit( type, ...args ) { - if ( !this._events_[ type ] ) { - return this.emit$( type, ...args ); - } - - const handlers = this._events_[ type ]; - const onceHandled=[]; - - for ( let handler of handlers ) { - handler.apply( this, args ); - if(handler._once_){ - onceHandled.push(handler); - } - } - - for(let handler of onceHandled){ - this.off(type,handler); - } - - return this.emit$( type, ...args ); - } - - emit$( type, ...args ) { - if ( !this._events_[ '*' ] ) { - return this; - } - - const catchAll = this._events_[ '*' ]; - - for ( let handler of catchAll ) { - handler.call( this, type, ...args ); - } - - return this; - } -} - -if (!Array.prototype.includes) { - Array.prototype.includes = function(searchElement /*, fromIndex*/) { - 'use strict'; - if (this == null) { - throw new TypeError('Array.prototype.includes called on null or undefined'); - } - - var O = Object(this); - var len = parseInt(O.length, 10) || 0; - if (len === 0) { - return false; - } - var n = parseInt(arguments[1], 10) || 0; - var k; - if (n >= 0) { - k = n; - } else { - k = len + n; - if (k < 0) {k = 0;} - } - var currentElement; - while (k < len) { - currentElement = O[k]; - if (searchElement === currentElement || - (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN - return true; - } - k++; - } - return false; - }; -} diff --git a/EventsServer/node_modules/event-pubsub/event-pubsub.js b/EventsServer/node_modules/event-pubsub/event-pubsub.js deleted file mode 100644 index 65bd02419..000000000 --- a/EventsServer/node_modules/event-pubsub/event-pubsub.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -let EventPubSub = require('./es5'); -if(process.version[1]>5){ - EventPubSub = require('./es6'); -} - -module.exports=EventPubSub; diff --git a/EventsServer/node_modules/event-pubsub/package.json b/EventsServer/node_modules/event-pubsub/package.json deleted file mode 100644 index d1daf8055..000000000 --- a/EventsServer/node_modules/event-pubsub/package.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "_from": "event-pubsub@4.3.0", - "_id": "event-pubsub@4.3.0", - "_inBundle": false, - "_integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==", - "_location": "/event-pubsub", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "event-pubsub@4.3.0", - "name": "event-pubsub", - "escapedName": "event-pubsub", - "rawSpec": "4.3.0", - "saveSpec": null, - "fetchSpec": "4.3.0" - }, - "_requiredBy": [ - "/node-ipc" - ], - "_resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz", - "_shasum": "f68d816bc29f1ec02c539dc58c8dd40ce72cb36e", - "_spec": "event-pubsub@4.3.0", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\Events-Server\\node_modules\\node-ipc", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/event-pubsub/issues" - }, - "bundleDependencies": false, - "deprecated": false, - "description": "Super light and fast Extensible PubSub events and EventEmitters for Node and the browser with support for ES6 by default, and ES5 versions for older verions of node and older IE/Safari versions. Easy for any developer level. No frills, just high speed pubsub events!", - "directories": { - "example": "examples" - }, - "engines": { - "node": ">=4.0.0" - }, - "homepage": "https://github.com/RIAEvangelist/event-pubsub", - "keywords": [ - "event", - "events", - "pubsub", - "node", - "browser" - ], - "license": "Unlicense", - "main": "event-pubsub.js", - "name": "event-pubsub", - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/event-pubsub.git" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "4.3.0" -} diff --git a/EventsServer/node_modules/js-message/Message.js b/EventsServer/node_modules/js-message/Message.js deleted file mode 100644 index 9a4698232..000000000 --- a/EventsServer/node_modules/js-message/Message.js +++ /dev/null @@ -1,71 +0,0 @@ -function Message() { - Object.defineProperties( - this, { - data: { - enumerable: true, - get: getData, - set: setData - }, - type: { - enumerable: true, - get: getType, - set: setType - }, - load:{ - enumarable:true, - writable:false, - value:parse - }, - JSON: { - enumerable: true, - get: getJSON - } - } - ); - - var type = ''; - var data = {}; - - function getType() { - return type; - } - - function getData() { - return data; - } - - function getJSON() { - return JSON.stringify( - { - type: type, - data: data - } - ); - } - - function setType(value) { - type = value; - } - - function setData(value) { - data = value; - } - - function parse(message){ - try{ - var message=JSON.parse(message); - type=message.type; - data=message.data; - }catch(err){ - var badMessage=message; - type='error', - data={ - message:'Invalid JSON response format', - err:err, - response:badMessage - } - } - } -} - -module.exports=Message; diff --git a/EventsServer/node_modules/js-message/js-message-vanilla.js b/EventsServer/node_modules/js-message/js-message-vanilla.js deleted file mode 100644 index 0c49c2b6c..000000000 --- a/EventsServer/node_modules/js-message/js-message-vanilla.js +++ /dev/null @@ -1,75 +0,0 @@ -( - function(){ - function Message() { - Object.defineProperties( - this, { - data: { - enumerable: true, - get: getData, - set: setData - }, - type: { - enumerable: true, - get: getType, - set: setType - }, - load:{ - enumarable:true, - writable:false, - value:parse - }, - JSON: { - enumerable: true, - get: getJSON - } - } - ); - - var type = ''; - var data = {}; - - function getType() { - return type; - } - - function getData() { - return data; - } - - function getJSON() { - return JSON.stringify( - { - type: type, - data: data - } - ); - } - - function setType(value) { - type = value; - } - - function setData(value) { - data = value; - } - - function parse(message){ - try{ - var message=JSON.parse(message); - type=message.type; - data=message.data; - }catch(err){ - var badMessage=message; - type='error', - data={ - message:'Invalid JSON response format', - err:err, - response:badMessage - } - } - } - } - - window.message=Message; - } -)(); diff --git a/EventsServer/node_modules/js-message/package.json b/EventsServer/node_modules/js-message/package.json deleted file mode 100644 index 34ca57de4..000000000 --- a/EventsServer/node_modules/js-message/package.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "_from": "js-message@1.0.5", - "_id": "js-message@1.0.5", - "_inBundle": false, - "_integrity": "sha1-IwDSSxrwjondCVvBpMnJz8uJLRU=", - "_location": "/js-message", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "js-message@1.0.5", - "name": "js-message", - "escapedName": "js-message", - "rawSpec": "1.0.5", - "saveSpec": null, - "fetchSpec": "1.0.5" - }, - "_requiredBy": [ - "/node-ipc" - ], - "_resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.5.tgz", - "_shasum": "2300d24b1af08e89dd095bc1a4c9c9cfcb892d15", - "_spec": "js-message@1.0.5", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\Events-Server\\node_modules\\node-ipc", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/js-message/issues" - }, - "bundleDependencies": false, - "dependencies": {}, - "deprecated": false, - "description": "normalized JS Object and JSON message and event protocol for node.js, vanialla js, react.js, components, actions, stores and dispatchers", - "devDependencies": {}, - "engines": { - "node": ">=0.6.0" - }, - "homepage": "https://github.com/RIAEvangelist/js-message#readme", - "keywords": [ - "message", - "normalize", - "events", - "js", - "json", - "protocol", - "ipc", - "node", - "nodejs", - "node.js", - "react", - "react.js", - "reactjs", - "websocket", - "websockets", - "web", - "socket", - "sockets", - "ws", - "flux", - "reflux", - "component", - "components", - "store", - "stores", - "action", - "actions" - ], - "license": "DBAD", - "main": "Message.js", - "name": "js-message", - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/js-message.git" - }, - "scripts": { - "start": "node devServer.js", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "1.0.5" -} diff --git a/EventsServer/node_modules/js-queue/package.json b/EventsServer/node_modules/js-queue/package.json deleted file mode 100644 index 63fdbaa7a..000000000 --- a/EventsServer/node_modules/js-queue/package.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "_from": "js-queue@2.0.0", - "_id": "js-queue@2.0.0", - "_inBundle": false, - "_integrity": "sha1-NiITz4YPRo8BJfxslqvBdCUx+Ug=", - "_location": "/js-queue", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "js-queue@2.0.0", - "name": "js-queue", - "escapedName": "js-queue", - "rawSpec": "2.0.0", - "saveSpec": null, - "fetchSpec": "2.0.0" - }, - "_requiredBy": [ - "/node-ipc" - ], - "_resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.0.tgz", - "_shasum": "362213cf860f468f0125fc6c96abc1742531f948", - "_spec": "js-queue@2.0.0", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\Events-Server\\node_modules\\node-ipc", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/js-queue/issues" - }, - "bundleDependencies": false, - "dependencies": { - "easy-stack": "^1.0.0" - }, - "deprecated": false, - "description": "Simple JS queue with auto run for node and browsers", - "engines": { - "node": ">=1.0.0" - }, - "homepage": "https://github.com/RIAEvangelist/js-queue#readme", - "keywords": [ - "queue", - "node", - "js", - "auto", - "run", - "execute", - "browser", - "react" - ], - "license": "DBAD", - "main": "queue.js", - "name": "js-queue", - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/js-queue.git" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "2.0.0" -} diff --git a/EventsServer/node_modules/js-queue/queue-vanilla.js b/EventsServer/node_modules/js-queue/queue-vanilla.js deleted file mode 100644 index 6f15495ae..000000000 --- a/EventsServer/node_modules/js-queue/queue-vanilla.js +++ /dev/null @@ -1,74 +0,0 @@ -function Queue(){ - Object.defineProperties( - this, - { - add:{ - enumerable:true, - writable:false, - value:addToQueue - }, - next:{ - enumerable:true, - writable:false, - value:run - }, - clear:{ - enumerable:true, - writable:false, - value:clearQueue - }, - contents:{ - enumerable:false, - get:getQueue, - set:setQueue - }, - autoRun:{ - enumerable:true, - writable:true, - value:true - }, - stop:{ - enumerable:true, - writable:true, - value:false - } - } - ); - - var queue=[]; - var running=false; - var stop=false; - - function clearQueue(){ - queue=[]; - return queue; - } - - function getQueue(){ - return queue; - } - - function setQueue(val){ - queue=val; - return queue; - } - - function addToQueue(){ - for(var i in arguments){ - queue.push(arguments[i]); - } - if(!running && !this.stop && this.autoRun){ - this.next(); - } - } - - function run(){ - running=true; - if(queue.length<1 || this.stop){ - running=false; - return; - } - - queue.shift().bind(this)(); - } -} diff --git a/EventsServer/node_modules/js-queue/queue.js b/EventsServer/node_modules/js-queue/queue.js deleted file mode 100644 index a8698d7e9..000000000 --- a/EventsServer/node_modules/js-queue/queue.js +++ /dev/null @@ -1,76 +0,0 @@ -function Queue(asStack){ - Object.defineProperties( - this, - { - add:{ - enumerable:true, - writable:false, - value:addToQueue - }, - next:{ - enumerable:true, - writable:false, - value:run - }, - clear:{ - enumerable:true, - writable:false, - value:clearQueue - }, - contents:{ - enumerable:false, - get:getQueue, - set:setQueue - }, - autoRun:{ - enumerable:true, - writable:true, - value:true - }, - stop:{ - enumerable:true, - writable:true, - value:false - } - } - ); - - var queue=[]; - var running=false; - var stop=false; - - function clearQueue(){ - queue=[]; - return queue; - } - - function getQueue(){ - return queue; - } - - function setQueue(val){ - queue=val; - return queue; - } - - function addToQueue(){ - for(var i in arguments){ - queue.push(arguments[i]); - } - if(!running && !this.stop && this.autoRun){ - this.next(); - } - } - - function run(){ - running=true; - if(queue.length<1 || this.stop){ - running=false; - return; - } - - queue.shift().bind(this)(); - } -} - -module.exports=Queue; diff --git a/EventsServer/node_modules/js-queue/stack.js b/EventsServer/node_modules/js-queue/stack.js deleted file mode 100644 index a9c25640e..000000000 --- a/EventsServer/node_modules/js-queue/stack.js +++ /dev/null @@ -1,3 +0,0 @@ -const Stack=require('easy-stack'); - -module.exports = Stack; diff --git a/EventsServer/node_modules/node-ipc/dao/client.js b/EventsServer/node_modules/node-ipc/dao/client.js deleted file mode 100644 index 41ce50411..000000000 --- a/EventsServer/node_modules/node-ipc/dao/client.js +++ /dev/null @@ -1,257 +0,0 @@ -'use strict'; - -const net = require('net'), - tls = require('tls'), - EventParser = require('../entities/EventParser.js'), - Message = require('js-message'), - fs = require('fs'), - Queue = require('js-queue'); - -let Events = require('event-pubsub/es5'); -if(process.version[1]>4){ - Events = require('event-pubsub'); -} - -let eventParser = new EventParser(); - -class Client extends Events{ - constructor(config,log){ - super(); - Object.assign( - this, - { - Client : Client, - config : config, - queue : new Queue, - socket : false, - connect : connect, - emit : emit, - log : log, - retriesRemaining:config.maxRetries||0, - explicitlyDisconnected: false - } - ); - - eventParser=new EventParser(this.config); - } -} - -function emit(type,data){ - this.log('dispatching event to ', this.id, this.path, ' : ', type, ',', data); - - let message=new Message; - message.type=type; - message.data=data; - - if(this.config.rawBuffer){ - message=new Buffer(type,this.config.encoding); - }else{ - message=eventParser.format(message); - } - - if(!this.config.sync){ - this.socket.write(message); - return; - } - - this.queue.add( - syncEmit.bind(this,message) - ); -} - -function syncEmit(message){ - this.log('dispatching event to ', this.id, this.path, ' : ', message); - this.socket.write(message); -} - -function connect(){ - //init client object for scope persistance especially inside of socket events. - let client=this; - - client.log('requested connection to ', client.id, client.path); - if(!this.path){ - client.log('\n\n######\nerror: ', client.id ,' client has not specified socket path it wishes to connect to.'); - return; - } - - const options={}; - - if(!client.port){ - client.log('Connecting client on Unix Socket :', client.path); - - options.path=client.path; - - if (process.platform ==='win32' && !client.path.startsWith('\\\\.\\pipe\\')){ - options.path = options.path.replace(/^\//, ''); - options.path = options.path.replace(/\//g, '-'); - options.path= `\\\\.\\pipe\\${options.path}`; - } - - client.socket = net.connect(options); - }else{ - options.host=client.path; - options.port=client.port; - - if(client.config.interface.localAddress){ - options.localAddress=client.config.interface.localAddress; - } - - if(client.config.interface.localPort){ - options.localPort=client.config.interface.localPort; - } - - if(client.config.interface.family){ - options.family=client.config.interface.family; - } - - if(client.config.interface.hints){ - options.hints=client.config.interface.hints; - } - - if(client.config.interface.lookup){ - options.lookup=client.config.interface.lookup; - } - - if(!client.config.tls){ - client.log('Connecting client via TCP to', options); - client.socket = net.connect(options); - }else{ - client.log('Connecting client via TLS to', client.path ,client.port,client.config.tls); - if(client.config.tls.private){ - client.config.tls.key=fs.readFileSync(client.config.tls.private); - } - if(client.config.tls.public){ - client.config.tls.cert=fs.readFileSync(client.config.tls.public); - } - if(client.config.tls.trustedConnections){ - if(typeof client.config.tls.trustedConnections === 'string'){ - client.config.tls.trustedConnections=[client.config.tls.trustedConnections]; - } - client.config.tls.ca=[]; - for(let i=0; i4){ - Events = require('event-pubsub'); -} - -let eventParser = new EventParser(); - -class Server extends Events{ - constructor(path,config,log,port){ - super(); - Object.assign( - this, - { - config : config, - path : path, - port : port, - udp4 : false, - udp6 : false, - log : log, - server : false, - sockets : [], - emit : emit, - broadcast : broadcast - } - ); - - eventParser=new EventParser(this.config); - - this.on( - 'close', - serverClosed.bind(this) - ); - } - - onStart(socket){ - this.trigger( - 'start', - socket - ); - } - - stop(){ - this.server.close(); - } - - start(){ - if(!this.path){ - this.log('Socket Server Path not specified, refusing to start'); - return; - } - - if(this.config.unlink){ - fs.unlink( - this.path, - startServer.bind(this) - ); - }else{ - startServer.bind(this)(); - } - } -} - -function emit(socket, type, data){ - this.log('dispatching event to socket', ' : ', type, data); - - let message=new Message; - message.type=type; - message.data=data; - - if(this.config.rawBuffer){ - this.log(this.config.encoding) - message=new Buffer(type,this.config.encoding); - }else{ - message=eventParser.format(message); - } - - if(this.udp4 || this.udp6){ - - if(!socket.address || !socket.port){ - this.log('Attempting to emit to a single UDP socket without supplying socket address or port. Redispatching event as broadcast to all connected sockets'); - this.broadcast(type,data); - return; - } - - this.server.write( - message, - socket - ); - return; - } - - socket.write(message); -} - -function broadcast(type,data){ - this.log('broadcasting event to all known sockets listening to ', this.path,' : ', ((this.port)?this.port:''), type, data); - let message=new Message; - message.type=type; - message.data=data; - - if(this.config.rawBuffer){ - message=new Buffer(type,this.config.encoding); - }else{ - message=eventParser.format(message); - } - - if(this.udp4 || this.udp6){ - for(let i=1, count=this.sockets.length; i0){ - let message=new Message; - message.load(data.shift()); - - // Only set the sock id if it is specified. - if (message.data && message.data.id){ - sock.id=message.data.id; - } - - this.log('received event of : ',message.type,message.data); - - this.publish( - message.type, - message.data, - sock - ); - } -} - -function socketClosed(socket){ - this.publish( - 'close', - socket - ); -} - -function serverCreated(socket) { - this.sockets.push(socket); - - if(socket.setEncoding){ - socket.setEncoding(this.config.encoding); - } - - this.log('## socket connection to server detected ##'); - socket.on( - 'close', - socketClosed.bind(this) - ); - - socket.on( - 'error', - function(err){ - this.log('server socket error',err); - - this.publish('error',err); - }.bind(this) - ); - - socket.on( - 'data', - gotData.bind(this,socket) - ); - - socket.on( - 'message', - function(msg,rinfo) { - if (!rinfo){ - return; - } - - this.log('Received UDP message from ', rinfo.address, rinfo.port); - let data; - - if(this.config.rawSocket){ - data=new Buffer(msg,this.config.encoding); - }else{ - data=msg.toString(); - } - socket.emit('data',data,rinfo); - }.bind(this) - ); - - this.publish( - 'connect', - socket - ); - - if(this.config.rawBuffer){ - return; - } -} - -function startServer() { - this.log( - 'starting server on ',this.path, - ((this.port)?`:${this.port}`:'') - ); - - if(!this.udp4 && !this.udp6){ - this.log('starting TLS server',this.config.tls); - if(!this.config.tls){ - this.server=net.createServer( - serverCreated.bind(this) - ); - }else{ - startTLSServer.bind(this)(); - } - }else{ - this.server=dgram.createSocket( - ((this.udp4)? 'udp4':'udp6') - ); - this.server.write=UDPWrite.bind(this); - this.server.on( - 'listening', - function UDPServerStarted() { - serverCreated.bind(this)(this.server); - }.bind(this) - ); - } - - this.server.on( - 'error', - function(err){ - this.log('server error',err); - - this.publish( - 'error', - err - ); - }.bind(this) - ); - - this.server.maxConnections=this.config.maxConnections; - - if(!this.port){ - this.log('starting server as', 'Unix || Windows Socket'); - if (process.platform ==='win32'){ - this.path = this.path.replace(/^\//, ''); - this.path = this.path.replace(/\//g, '-'); - this.path= `\\\\.\\pipe\\${this.path}`; - } - - this.server.listen( - this.path, - this.onStart.bind(this) - ); - - return; - } - - if(!this.udp4 && !this.udp6){ - this.log('starting server as', (this.config.tls?'TLS':'TCP')); - this.server.listen( - this.port, - this.path, - this.onStart.bind(this) - ); - return; - } - - this.log('starting server as',((this.udp4)? 'udp4':'udp6')); - - this.server.bind( - this.port, - this.path - ); - - this.onStart( - { - address : this.path, - port : this.port - } - ); -} - -function startTLSServer(){ - this.log('starting TLS server',this.config.tls); - if(this.config.tls.private){ - this.config.tls.key=fs.readFileSync(this.config.tls.private); - }else{ - this.config.tls.key=fs.readFileSync(`${__dirname}/../local-node-ipc-certs/private/server.key`); - } - if(this.config.tls.public){ - this.config.tls.cert=fs.readFileSync(this.config.tls.public); - }else{ - this.config.tls.cert=fs.readFileSync(`${__dirname}/../local-node-ipc-certs/server.pub`); - } - if(this.config.tls.dhparam){ - this.config.tls.dhparam=fs.readFileSync(this.config.tls.dhparam); - } - if(this.config.tls.trustedConnections){ - if(typeof this.config.tls.trustedConnections === 'string'){ - this.config.tls.trustedConnections=[this.config.tls.trustedConnections]; - } - this.config.tls.ca=[]; - for(let i=0; i 0) { - // getting the family of first network interface available - IPType = networkInterfaces [ - Object.keys( networkInterfaces )[0] - ][0].family; - } - return IPType; -} - -module.exports=Defaults; diff --git a/EventsServer/node_modules/node-ipc/entities/EventParser.js b/EventsServer/node_modules/node-ipc/entities/EventParser.js deleted file mode 100644 index 8ac1f2bda..000000000 --- a/EventsServer/node_modules/node-ipc/entities/EventParser.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -const Defaults = require('./Defaults.js'); - -class Parser{ - constructor(config){ - if(!config){ - config=new Defaults; - } - this.delimiter=config.delimiter; - } - - format(message){ - if(!message.data && message.data!==false && message.data!==0){ - message.data={}; - } - if(message.data['_maxListeners']){ - message.data={}; - } - - message=message.JSON+this.delimiter; - return message; - } - - parse(data){ - let events=data.split(this.delimiter); - events.pop(); - return events; - } -} - -module.exports=Parser; diff --git a/EventsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/goodbye-client.js b/EventsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/goodbye-client.js deleted file mode 100644 index 9d5ce05d6..000000000 --- a/EventsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/goodbye-client.js +++ /dev/null @@ -1,44 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'goodbye'; -ipc.config.retry= 1500; -ipc.config.maxRetries= 10; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'goodbye' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/hello-client.js b/EventsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/hello-client.js deleted file mode 100644 index 74136333d..000000000 --- a/EventsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/hello-client.js +++ /dev/null @@ -1,50 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.maxRetries=10; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data.message); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/world-server.js b/EventsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/world-server.js deleted file mode 100644 index 2bef44794..000000000 --- a/EventsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/world-server.js +++ /dev/null @@ -1,51 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -var messages={ - goodbye:false, - hello:false -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - ipc.log('got a message from', (data.id), (data.message)); - messages[data.id]=true; - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - - if(messages.hello && messages.goodbye){ - ipc.log('got all required events, telling clients to kill connection'); - ipc.server.broadcast( - 'kill.connection', - { - id:ipc.config.id - } - ); - } - } - ); - } -); - - - - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/TCPSocket/basic/hello-client.js b/EventsServer/node_modules/node-ipc/example/TCPSocket/basic/hello-client.js deleted file mode 100644 index 6ae692edf..000000000 --- a/EventsServer/node_modules/node-ipc/example/TCPSocket/basic/hello-client.js +++ /dev/null @@ -1,39 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/TCPSocket/basic/world-server.js b/EventsServer/node_modules/node-ipc/example/TCPSocket/basic/world-server.js deleted file mode 100644 index 6c8790170..000000000 --- a/EventsServer/node_modules/node-ipc/example/TCPSocket/basic/world-server.js +++ /dev/null @@ -1,44 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.maxConnections=1; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log('DISCONNECTED\n\n',arguments); - } - ); - } -); - -ipc.server.on( - 'error', - function(err){ - ipc.log('Got an ERROR!',err); - } -); - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/TCPSocket/basicSync/hello-client.js b/EventsServer/node_modules/node-ipc/example/TCPSocket/basicSync/hello-client.js deleted file mode 100644 index 292415053..000000000 --- a/EventsServer/node_modules/node-ipc/example/TCPSocket/basicSync/hello-client.js +++ /dev/null @@ -1,46 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.sync= true; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - - //queue up a bunch of requests to be sent synchronously - for(var i=0; i<10; i++){ - ipc.of.world.emit( - 'message', - 'hello'+i - ); - } - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data,'\n\n'); - } - ); - } -); - -console.log(ipc); diff --git a/EventsServer/node_modules/node-ipc/example/TCPSocket/basicSync/world-server.js b/EventsServer/node_modules/node-ipc/example/TCPSocket/basicSync/world-server.js deleted file mode 100644 index 3e817da13..000000000 --- a/EventsServer/node_modules/node-ipc/example/TCPSocket/basicSync/world-server.js +++ /dev/null @@ -1,45 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.sync = true; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - //fake some synch procedural code - setTimeout( - function(){ - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - }, - 3000 - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/hello-client.js b/EventsServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/hello-client.js deleted file mode 100644 index b6ac81f6b..000000000 --- a/EventsServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/hello-client.js +++ /dev/null @@ -1,35 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'hello' - ); - } - ); - - ipc.of.world.on( - 'data', - function(data){ - ipc.log('got a message from world : ', data,data.toString()); - } - ); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/world.server.js b/EventsServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/world.server.js deleted file mode 100644 index 5da4de4d5..000000000 --- a/EventsServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/world.server.js +++ /dev/null @@ -1,40 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.serveNet( - function(){ - ipc.server.on( - 'connect', - function(socket){ - ipc.server.emit( - socket, - 'hello' - ); - } - ); - - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data,data.toString()); - ipc.server.emit( - socket, - 'goodbye' - ); - } - ); - } -); - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/goodbye-client.js b/EventsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/goodbye-client.js deleted file mode 100644 index 508702d01..000000000 --- a/EventsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/goodbye-client.js +++ /dev/null @@ -1,47 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'goodbye'; -ipc.config.retry= 1500; -ipc.config.maxRetries= 10; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'goodbye' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/hello-client.js b/EventsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/hello-client.js deleted file mode 100644 index 16fd21fc3..000000000 --- a/EventsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/hello-client.js +++ /dev/null @@ -1,53 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.maxRetries=10; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data.message); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/world-server.js b/EventsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/world-server.js deleted file mode 100644 index 0c52c268d..000000000 --- a/EventsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/world-server.js +++ /dev/null @@ -1,55 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key' -}; - -var messages={ - goodbye:false, - hello:false -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - ipc.log('got a message from', (data.id), (data.message)); - messages[data.id]=true; - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - - if(messages.hello && messages.goodbye){ - ipc.log('got all required events, telling clients to kill connection'); - ipc.server.broadcast( - 'kill.connection', - { - id:ipc.config.id - } - ); - } - } - ); - } -); - - - - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/hello-client.js b/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/hello-client.js deleted file mode 100644 index 15771565b..000000000 --- a/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/hello-client.js +++ /dev/null @@ -1,42 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/world-server.js b/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/world-server.js deleted file mode 100644 index 3cbcd8e38..000000000 --- a/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/world-server.js +++ /dev/null @@ -1,42 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -//node-ipc will default to its local certs -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/hello-client.js b/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/hello-client.js deleted file mode 100644 index bda3eb701..000000000 --- a/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/hello-client.js +++ /dev/null @@ -1,47 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.tls={ - private: __dirname+'/../../../local-node-ipc-certs/private/client.key', - public: __dirname+'/../../../local-node-ipc-certs/client.pub', - rejectUnauthorized:false, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/server.pub' - ] -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/world-server.js b/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/world-server.js deleted file mode 100644 index 56eee122b..000000000 --- a/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/world-server.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key', - dhparam: __dirname+'/../../../local-node-ipc-certs/private/dhparam.pem', - requestCert: true, - rejectUnauthorized:false, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/client.pub' - ] -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/hello-client.js b/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/hello-client.js deleted file mode 100644 index 26d5b1da6..000000000 --- a/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/hello-client.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.networkHost='localhost'; -ipc.config.tls={ - private: __dirname+'/../../../local-node-ipc-certs/private/client.key', - public: __dirname+'/../../../local-node-ipc-certs/client.pub', - rejectUnauthorized:true, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/server.pub' - ] -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/world-server.js b/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/world-server.js deleted file mode 100644 index ee984a4e1..000000000 --- a/EventsServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/world-server.js +++ /dev/null @@ -1,49 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.networkHost='localhost'; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key', - dhparam: __dirname+'/../../../local-node-ipc-certs/private/dhparam.pem', - requestCert: true, - rejectUnauthorized:true, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/client.pub' - ] -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/TLSSocket/basic/hello-client.js b/EventsServer/node_modules/node-ipc/example/TLSSocket/basic/hello-client.js deleted file mode 100644 index 15771565b..000000000 --- a/EventsServer/node_modules/node-ipc/example/TLSSocket/basic/hello-client.js +++ /dev/null @@ -1,42 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/TLSSocket/basic/world-server.js b/EventsServer/node_modules/node-ipc/example/TLSSocket/basic/world-server.js deleted file mode 100644 index a52c3602a..000000000 --- a/EventsServer/node_modules/node-ipc/example/TLSSocket/basic/world-server.js +++ /dev/null @@ -1,42 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key' -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/TLSSocket/basicSync/hello-client.js b/EventsServer/node_modules/node-ipc/example/TLSSocket/basicSync/hello-client.js deleted file mode 100644 index 405db4468..000000000 --- a/EventsServer/node_modules/node-ipc/example/TLSSocket/basicSync/hello-client.js +++ /dev/null @@ -1,47 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.sync= true; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - - //queue up a bunch of requests to be sent synchronously - for(var i=0; i<10; i++){ - ipc.of.world.emit( - 'message', - 'hello'+i - ); - } - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/TLSSocket/basicSync/world-server.js b/EventsServer/node_modules/node-ipc/example/TLSSocket/basicSync/world-server.js deleted file mode 100644 index aec87c100..000000000 --- a/EventsServer/node_modules/node-ipc/example/TLSSocket/basicSync/world-server.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.sync= true; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key' -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - setTimeout( - function(){ - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - }, - 3000 - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/hello-client.js b/EventsServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/hello-client.js deleted file mode 100644 index f0c66ad22..000000000 --- a/EventsServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/hello-client.js +++ /dev/null @@ -1,45 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; -ipc.config.networkHost='localhost'; - -ipc.config.tls={ - private: __dirname+'/../../../local-node-ipc-certs/private/client.key', - public: __dirname+'/../../../local-node-ipc-certs/client.pub', - rejectUnauthorized:true, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/server.pub' - ] -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'hello' - ); - } - ); - - ipc.of.world.on( - 'data', - function(data){ - ipc.log('got a message from world : ', data,data.toString()); - } - ); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/world.server.js b/EventsServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/world.server.js deleted file mode 100644 index f0d0b29af..000000000 --- a/EventsServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/world.server.js +++ /dev/null @@ -1,53 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; -ipc.config.networkHost='localhost'; - -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key', - dhparam: __dirname+'/../../../local-node-ipc-certs/private/dhparam.pem', - requestCert: true, - rejectUnauthorized:true, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/client.pub' - ] -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'connect', - function(socket){ - console.log('connection detected'); - ipc.server.emit( - socket, - 'hello' - ); - } - ); - - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data,data.toString()); - ipc.server.emit( - socket, - 'goodbye' - ); - } - ); - } -); - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/goodbye-client.js b/EventsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/goodbye-client.js deleted file mode 100644 index d98a7b061..000000000 --- a/EventsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/goodbye-client.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * Since there is no client relationship - * with UDP sockets sockets are not kept - * open. - * - * This means the order sockets are opened - * is important. - * - * Start World first. Then you can start - * hello or goodbye in any order you - * choose. - * - * *************************************/ - -ipc.config.id = 'goodbye'; -ipc.config.retry= 1500; - -ipc.serveNet( - 8002, //we set the port here because the hello client and world server are already using the default of 8000 and the port 8001. So we can not bind to those while hello and world are connected to them. - 'udp4', - function(){ - ipc.server.on( - 'message', - function(data){ - ipc.log('got Data'); - ipc.log('got a message from ', data.id ,' : ', data.message); - } - ); - ipc.server.emit( - { - address : 'localhost', - port : ipc.config.networkPort - }, - 'message', - { - id : ipc.config.id, - message : 'Goodbye' - } - ); - } -); - - - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/hello-client.js b/EventsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/hello-client.js deleted file mode 100644 index ecc0b45a4..000000000 --- a/EventsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/hello-client.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * Since there is no client relationship - * with UDP sockets sockets are not kept - * open. - * - * This means the order sockets are opened - * is important. - * - * Start World first. Then you can start - * hello or goodbye in any order you - * choose. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; - -ipc.serveNet( - 8001, //we set the port here because the world server is already using the default of 8000. So we can not bind to 8000 while world is using it. - 'udp4', - function(){ - ipc.server.on( - 'message', - function(data){ - ipc.log('got Data'); - ipc.log('got a message from ', data.id ,' : ', data.message); - } - ); - ipc.server.emit( - { - address : 'localhost', - port : ipc.config.networkPort - }, - 'message', - { - id : ipc.config.id, - message : 'Hello' - } - ); - } -); - - - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/world-server.js b/EventsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/world-server.js deleted file mode 100644 index 97f927088..000000000 --- a/EventsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/world-server.js +++ /dev/null @@ -1,63 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * Since there is no client relationship - * with UDP sockets sockets are not kept - * open. - * - * This means the order sockets are opened - * is important. - * - * Start World first. Then you can start - * hello or goodbye in any order you - * choose. - * - ***************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -var messages={ - goodbye:false, - hello:false -}; - -ipc.serveNet( - 'udp4', - function(){ - console.log(123); - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message from ', data.id ,' : ', data.message); - messages[data.id]=true; - ipc.server.emit( - socket, - 'message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - - if(messages.hello && messages.goodbye){ - ipc.log('got all required events, telling evryone how muchg I am loved!'); - ipc.server.broadcast( - 'message', - { - id : ipc.config.id, - message : 'Everybody Loves The World! Got messages from hello and goodbye!' - } - ); - } - } - ); - - console.log(ipc.server); - } -); - - - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/UDPSocket/basic/hello-client.js b/EventsServer/node_modules/node-ipc/example/UDPSocket/basic/hello-client.js deleted file mode 100644 index f731b1ba8..000000000 --- a/EventsServer/node_modules/node-ipc/example/UDPSocket/basic/hello-client.js +++ /dev/null @@ -1,52 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * UDP Client is really a UDP server - * - * Dedicated UDP sockets on the same - * machine can not be bound to in the - * traditional client/server method - * - * Every UDP socket is it's own UDP server - * And so must have a unique port on its - * machine, unlike TCP or Unix Sockts - * which can share on the same machine. - * - * Since there is no open client server - * relationship, you should start world - * first and then hello. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; - -ipc.serveNet( - 8001, //we set the port here because the world server is already using the default of 8000. So we can not bind to 8000 while world is using it. - 'udp4', - function(){ - ipc.server.on( - 'message', - function(data){ - ipc.log('got Data'); - ipc.log('got a message from ', data.id ,' : ', data.message); - } - ); - ipc.server.emit( - { - address : 'localhost', - port : ipc.config.networkPort - }, - 'message', - { - id : ipc.config.id, - message : 'Hello' - } - ); - } -); - - - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/UDPSocket/basic/world-server.js b/EventsServer/node_modules/node-ipc/example/UDPSocket/basic/world-server.js deleted file mode 100644 index 0f7aa4543..000000000 --- a/EventsServer/node_modules/node-ipc/example/UDPSocket/basic/world-server.js +++ /dev/null @@ -1,47 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * UDP Client is really a UDP server - * - * Dedicated UDP sockets on the same - * machine can not be bound to in the - * traditional client/server method - * - * Every UDP socket is it's own UDP server - * And so must have a unique port on its - * machine, unlike TCP or Unix Sockts - * which can share on the same machine. - * - * Since there is no open client server - * relationship, you should start world - * first and then hello. - * - ***************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -ipc.serveNet( - 'udp4', - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message from ', data.id ,' : ', data.message); - ipc.server.emit( - socket, - 'message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - } - ); - } -); - - - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/hello-client.js b/EventsServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/hello-client.js deleted file mode 100644 index 73cd13ac5..000000000 --- a/EventsServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/hello-client.js +++ /dev/null @@ -1,35 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.serveNet( - 8001, //we set the port here because the world server is already using the default of 8000. So we can not bind to 8000 while world is using it. - 'udp4', - function(){ - ipc.server.on( - 'data', - function(data){ - ipc.log('got a message from world ', data, data.toString()); - } - ); - ipc.server.emit( - { - address : 'localhost', - port : ipc.config.networkPort - }, - 'hello' - ); - } -); - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/world.server.js b/EventsServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/world.server.js deleted file mode 100644 index d0c34f7e2..000000000 --- a/EventsServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/world.server.js +++ /dev/null @@ -1,43 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * UDP Client is really a UDP server - * - * Dedicated UDP sockets on the same - * machine can not be bound to in the - * traditional client/server method - * - * Every UDP socket is it's own UDP server - * And so must have a unique port on its - * machine, unlike TCP or Unix Sockts - * which can share on the same machine. - * - * Since there is no open client server - * relationship, you should start world - * first and then hello. - * - ***************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.serveNet( - 'udp4', - function(){ - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data,data.toString()); - ipc.server.emit( - socket, - 'goodbye' - ); - } - ); - } -); - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-client.js b/EventsServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-client.js deleted file mode 100644 index eca2a889c..000000000 --- a/EventsServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-client.js +++ /dev/null @@ -1,31 +0,0 @@ -const fs = require('fs'); -const ipc = require('../../node-ipc'); - -const socketPath = '/tmp/ipc.sock'; - -//loop forever so you can see the pid of the cluster sever change in the logs -setInterval( - function() { - ipc.connectTo( - 'world', - socketPath, - connecting - ); - }, - 2000 -); - -function connecting(socket) { - ipc.of.world.on( - 'connect', - function() { - ipc.of.world.emit( - 'currentDate', - { - message: new Date().toISOString() - } - ); - ipc.disconnect('world'); - } - ); -} diff --git a/EventsServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-server.js b/EventsServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-server.js deleted file mode 100644 index b0942a338..000000000 --- a/EventsServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-server.js +++ /dev/null @@ -1,32 +0,0 @@ -const fs = require('fs'); -const ipc=require('../../../node-ipc'); -const cpuCount = require('os').cpus().length; -const cluster = require('cluster'); -const socketPath = '/tmp/ipc.sock'; - -ipc.config.unlink = false; - -if (cluster.isMaster) { - if (fs.existsSync(socketPath)) { - fs.unlinkSync(socketPath); - } - - for (let i = 0; i < cpuCount; i++) { - cluster.fork(); - } -}else{ - ipc.serve( - socketPath, - function() { - ipc.server.on( - 'currentDate', - function(data,socket) { - console.log(`pid ${process.pid} got: `, data); - } - ); - } - ); - - ipc.server.start(); - console.log(`pid ${process.pid} listening on ${socketPath}`); -} diff --git a/EventsServer/node_modules/node-ipc/example/rawBuffer/hello-client.js b/EventsServer/node_modules/node-ipc/example/rawBuffer/hello-client.js deleted file mode 100644 index f22ab5376..000000000 --- a/EventsServer/node_modules/node-ipc/example/rawBuffer/hello-client.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict'; - -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='hex'; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - //make a 6 byte buffer for example - const myBuffer=new Buffer(6).fill(0); - - myBuffer.writeUInt16BE(0x02,0); - myBuffer.writeUInt32BE(0xffeecc,2); - - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - myBuffer - ); - } - ); - - ipc.of.world.on( - 'data', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/rawBuffer/world.server.js b/EventsServer/node_modules/node-ipc/example/rawBuffer/world.server.js deleted file mode 100644 index f27a02cd5..000000000 --- a/EventsServer/node_modules/node-ipc/example/rawBuffer/world.server.js +++ /dev/null @@ -1,40 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='hex'; - -ipc.serve( - function(){ - ipc.server.on( - 'connect', - function(socket){ - ipc.server.emit( - socket, - [0xaa] - ); - } - ); - - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data); - ipc.server.emit( - socket, - [0x0d,0xee] - ); - } - ); - } -); - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/goodbye-client.js b/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/goodbye-client.js deleted file mode 100644 index 57d455eec..000000000 --- a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/goodbye-client.js +++ /dev/null @@ -1,43 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'goodbye'; -ipc.config.retry= 1500; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'goodbye' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/hello-client.js b/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/hello-client.js deleted file mode 100644 index d556c4694..000000000 --- a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/hello-client.js +++ /dev/null @@ -1,49 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/world-server.js b/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/world-server.js deleted file mode 100644 index 69cfb31c0..000000000 --- a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/world-server.js +++ /dev/null @@ -1,51 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -var messages={ - goodbye:false, - hello:false -}; - -ipc.serve( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - ipc.log('got a message from', (data.id), (data.message)); - messages[data.id]=true; - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - - if(messages.hello && messages.goodbye){ - ipc.log('got all required events, telling clients to kill connection'); - ipc.server.broadcast( - 'kill.connection', - { - id:ipc.config.id - } - ); - } - } - ); - } -); - - - - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/basic/hello-client.js b/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/basic/hello-client.js deleted file mode 100644 index c6d87cb27..000000000 --- a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/basic/hello-client.js +++ /dev/null @@ -1,44 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry = 1000; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - - console.log(ipc.of.world.destroy); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/basic/world-server.js b/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/basic/world-server.js deleted file mode 100644 index 6b3052242..000000000 --- a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/basic/world-server.js +++ /dev/null @@ -1,33 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -ipc.serve( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - } - ); - } -); - - - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/hello-client.js b/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/hello-client.js deleted file mode 100644 index 3142677a2..000000000 --- a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/hello-client.js +++ /dev/null @@ -1,49 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry = 1000; -ipc.config.sync= true; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - - //queue up a bunch of requests to be sent synchronously - for(var i=0; i<10; i++){ - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello'+i - } - ); - } - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - - console.log(ipc.of.world.destroy); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/world-server.js b/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/world-server.js deleted file mode 100644 index c76e1bb6f..000000000 --- a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/world-server.js +++ /dev/null @@ -1,39 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.sync= true; - -ipc.serve( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - setTimeout( - function(){ - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - }, - 2000 - ); - } - ); - } -); - - - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/hello-client.js b/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/hello-client.js deleted file mode 100644 index 9c7042a90..000000000 --- a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/hello-client.js +++ /dev/null @@ -1,35 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'hello' - ); - } - ); - - ipc.of.world.on( - 'data', - function(data){ - ipc.log('got a message from world : ', data,data.toString()); - } - ); - } -); diff --git a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/world.server.js b/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/world.server.js deleted file mode 100644 index c3ed83c9a..000000000 --- a/EventsServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/world.server.js +++ /dev/null @@ -1,40 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.serve( - function(){ - ipc.server.on( - 'connect', - function(socket){ - ipc.server.emit( - socket, - 'hello' - ); - } - ); - - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data,data.toString()); - ipc.server.emit( - socket, - 'goodbye' - ); - } - ); - } -); - -ipc.server.start(); diff --git a/EventsServer/node_modules/node-ipc/node-ipc.js b/EventsServer/node_modules/node-ipc/node-ipc.js deleted file mode 100644 index 1c6336061..000000000 --- a/EventsServer/node_modules/node-ipc/node-ipc.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -const IPC = require('./services/IPC.js'); - -class IPCModule extends IPC{ - constructor(){ - super(); - //include IPC to make extensible - Object.defineProperty( - this, - 'IPC', - { - enumerable:true, - writable:false, - value:IPC - } - ) - } -} - -module.exports=new IPCModule; diff --git a/EventsServer/node_modules/node-ipc/package.json b/EventsServer/node_modules/node-ipc/package.json deleted file mode 100644 index 1f21a0052..000000000 --- a/EventsServer/node_modules/node-ipc/package.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "_from": "node-ipc", - "_id": "node-ipc@9.1.1", - "_inBundle": false, - "_integrity": "sha512-FAyICv0sIRJxVp3GW5fzgaf9jwwRQxAKDJlmNFUL5hOy+W4X/I5AypyHoq0DXXbo9o/gt79gj++4cMr4jVWE/w==", - "_location": "/node-ipc", - "_phantomChildren": {}, - "_requested": { - "type": "tag", - "registry": true, - "raw": "node-ipc", - "name": "node-ipc", - "escapedName": "node-ipc", - "rawSpec": "", - "saveSpec": null, - "fetchSpec": "latest" - }, - "_requiredBy": [ - "#USER", - "/" - ], - "_resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.1.1.tgz", - "_shasum": "4e245ed6938e65100e595ebc5dc34b16e8dd5d69", - "_spec": "node-ipc", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\Events-Server", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/node-ipc/issues" - }, - "bundleDependencies": false, - "dependencies": { - "event-pubsub": "4.3.0", - "js-message": "1.0.5", - "js-queue": "2.0.0" - }, - "deprecated": false, - "description": "A nodejs module for local and remote Inter Process Communication (IPC), Neural Networking, and able to facilitate machine learning.", - "devDependencies": { - "codacy-coverage": "2.0.0", - "istanbul": "0.4.1", - "jasmine": "2.4.1", - "node-cmd": "2.0.0" - }, - "directories": { - "example": "example" - }, - "engines": { - "node": ">=4.0.0" - }, - "homepage": "http://riaevangelist.github.io/node-ipc/", - "keywords": [ - "IPC", - "Neural Networking", - "Machine Learning", - "inter", - "process", - "communication", - "unix", - "windows", - "win", - "socket", - "TCP", - "UDP", - "domain", - "sockets", - "threaded", - "communication", - "multi", - "process", - "shared", - "memory" - ], - "license": "DBAD", - "main": "node-ipc.js", - "name": "node-ipc", - "pre-commit": [ - "cover" - ], - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/node-ipc.git" - }, - "scripts": { - "cover": "istanbul cover -x **/spec/** -dir ./spec/coverage jasmine", - "coverup": "cat ./spec/coverage/lcov.info | codacy-coverage", - "test": "istanbul cover -x **/spec/** -dir ./spec/coverage jasmine", - "test-windows": "istanbul cover -x **/spec/** -dir ./spec/coverage ./node_modules/jasmine/bin/jasmine.js" - }, - "version": "9.1.1" -} diff --git a/EventsServer/node_modules/node-ipc/services/IPC.js b/EventsServer/node_modules/node-ipc/services/IPC.js deleted file mode 100644 index 3a6edc7f5..000000000 --- a/EventsServer/node_modules/node-ipc/services/IPC.js +++ /dev/null @@ -1,337 +0,0 @@ -'use strict'; - -const Defaults = require('../entities/Defaults.js'), - Client = require('../dao/client.js'), - Server = require('../dao/socketServer.js'), - util = require('util'); - -class IPC{ - constructor(){ - Object.defineProperties( - this, - { - config : { - enumerable:true, - writable:true, - value:new Defaults - }, - connectTo : { - enumerable:true, - writable:false, - value:connect - }, - connectToNet: { - enumerable:true, - writable:false, - value:connectNet - }, - disconnect : { - enumerable:true, - writable:false, - value:disconnect - }, - serve : { - enumerable:true, - writable:false, - value:serve - }, - serveNet : { - enumerable:true, - writable:false, - value:serveNet - }, - of : { - enumerable:true, - writable:true, - value:{} - }, - server : { - enumerable:true, - writable:true, - configurable:true, - value:false - }, - log : { - enumerable:true, - writable:false, - value:log - } - } - ); - } -} - -function log(...args){ - if(this.config.silent){ - return; - } - - for(let i=0, count=args.length; i Got a new message : '.debug, data); - - try { - let command = JSON.parse(data) - - switch (command.action) { - case "greetings": { - sendResponse(global.DEFAULT_OK_RESPONSE) - return - } - case "createEventHandler": { - let eventHandler = eventHandlers.get(command.eventHandlerName) - if (eventHandler === undefined) { - /* - We will only create event handlers which were not created before. Remember that someone trying to listen events - at an event handler that does not exist, will create that eventhandler, so it is possible that the emitter - when trying to create the event handler in fact was late and the event handler is already there if the listener - arrived here first. An event handler created with this method is not destroyed if there are no listeners or they - all leave. - */ - eventHandler = newEventHandler() - eventHandler.deleteWhenAllListenersAreGone = false - eventHandlers.set(command.eventHandlerName, eventHandler) - } - sendResponse(global.DEFAULT_OK_RESPONSE) - return - } - case "deleteEventHandler": { - let eventHandler = eventHandlers.get(command.eventHandlerName) - if (eventHandler !== undefined) { - /* - We will only delete event handlers which have noone listening, allowing a listener to continue listening even - when the event emitter is gone, asuming that it could come back at some point in time and resume emitting. - */ - if (eventHandler.listeners.length === 0) { - eventHandlers.delete(command.eventHandlerName) - } else { - eventHandler.deleteWhenAllListenersAreGone = true - } - } - - sendResponse(global.DEFAULT_OK_RESPONSE) - return - } - case "listenToEvent": { - let eventHandler = eventHandlers.get(command.eventHandlerName) - if (eventHandler === undefined) { - /* - We will create event handlers which were not created before if a listener tries to listen to a handler that does noet - exist before the emitter comes and create it. This is to aviod syncronization problems and also problems with emitters life - cycles with higher frecuency that the ones of listeners. Created in this way, event handlers are marked for deletion if - all listeners stop listening at one point in time. - */ - eventHandler = newEventHandler() - eventHandler.deleteWhenAllListenersAreGone = true - eventHandlers.set(command.eventHandlerName, eventHandler) - } - eventSubscriptionId = eventHandler.listenToEvent(command.eventHandlerName, command.eventType, command.callerId, handlerFunction, command.extraData) - - function handlerFunction(event, extraData) { - let outputData = { - action: 'Event Raised', - eventHandlerName: command.eventHandlerName, - eventType: command.eventType, - event: event, - callerId: command.callerId, - extraData: extraData - } - ipc.server.emit( - socket, - 'message', - JSON.stringify(outputData) - ); - } - - let response = { - result: global.DEFAULT_OK_RESPONSE.result, - message: global.DEFAULT_OK_RESPONSE.message, - eventSubscriptionId: eventSubscriptionId - } - - sendResponse(response) - return - } - case "stopListening": { - let eventHandler = eventHandlers.get(command.eventHandlerName) - - if (eventHandler === undefined) { - if (ipc.config.silent !== true) { - console.log("[WARN] Events Server -> Cannot to stop listening to events at an Event Handler that does not exist. Command = "+ JSON.stringify(command)) - } - sendResponse(global.DEFAULT_FAIL_RESPONSE) - return - } - - eventHandler.stopListening(command.eventHandlerName, command.eventType, command.callerId, command.eventSubscriptionId) - - /* - We check here if there are no more listeners and the event handler original emmiter is also gone, then we need to delete - this event handlers since chances are that is not needed anymore. - */ - if (eventHandler.listeners.length === 0 && eventHandler.deleteWhenAllListenersAreGone === true) { - eventHandlers.delete(command.eventHandlerName) - } - - sendResponse(global.DEFAULT_OK_RESPONSE) - return - } - case "raiseEvent": { - let eventHandler = eventHandlers.get(command.eventHandlerName) - - if (eventHandler === undefined) { - if (ipc.config.silent !== true) { - console.log("[WARN] Events Server -> Cannot raise events at an Event Handler that does not exist. Command = " + JSON.stringify(command)) - } - sendResponse(global.DEFAULT_FAIL_RESPONSE) - return - } - //console.log("[INFO] Events Server -> Raising Event " + command.eventHandlerName + " " + command.eventType) - eventHandler.raiseEvent(command.eventType, command.event) - sendResponse(global.DEFAULT_OK_RESPONSE) - return - } - } - - console.log("[WARN] Events Server -> Unknown Command Received:" + data) - - function sendResponse(message) { - if (command.callerId) { - message.callerId = command.callerId - } - message.action = 'Event Server Response' - ipc.server.emit( - socket, - 'message', - JSON.stringify(message) - ); - } - - } catch (err) { - console.log("[ERROR] Events Server -> Bad Command Received:" + data) - console.log("[ERROR] Events Server -> An Error Happened:" + err.stack) - sendResponse(global.DEFAULT_FAIL_RESPONSE) - } - - } - ); - ipc.server.on( - 'connect', - function (socket) { - ipc.log('[INFO] Events Server -> client has connected!'); - } - ); - ipc.server.on( - 'socket.disconnected', - function (socket) { - ipc.log('[INFO] Events Server -> client has disconnected!'); - } - ); - } - - -); - -ipc.server.start(); -console.log('Events Server Started.') - -function newEventHandler() { - let thisObject = { - name: undefined, // This is for debugging purposes only. - deleteWhenAllListenersAreGone: false, - listeners: [], // Here we store all the functions we will call when an event is raiseed. - listenToEvent: listenToEvent, - stopListening: stopListening, - raiseEvent: raiseEvent, - finalize: finalize - } - - return thisObject - - function finalize() { - thisObject.listeners = [] - } - - function listenToEvent(eventHandlerName, eventType, callerId, handler, extraData) { - let eventSubscriptionId = Math.trunc(Math.random() * 1000000) - thisObject.listeners.push([eventHandlerName, eventType, callerId, handler, extraData, eventSubscriptionId]) - return eventSubscriptionId - } - - function stopListening(eventHandlerName, eventType, callerId, eventSubscriptionId) { - - if (eventSubscriptionId !== undefined) { - for (let i = 0; i < thisObject.listeners.length; i++) { - if (eventSubscriptionId === thisObject.listeners[i][5]) { - thisObject.listeners.splice(i, 1) - return - } - } - } - if (eventHandlerName !== undefined && eventType !== undefined && callerId !== undefined) { - for (let i = 0; i < thisObject.listeners.length; i++) { - if (eventHandlerName === thisObject.listeners[i][0] && eventType === thisObject.listeners[i][1] && callerId === thisObject.listeners[i][2]) { - thisObject.listeners.splice(i, 1) - return - } - } - } - } - - function raiseEvent(eventType, event) { - for (let i = 0; i < thisObject.listeners.length; i++) { - /* We will execute all the functions listening to this event type. */ - - if (thisObject.listeners[i][1] === eventType) { - let handler = thisObject.listeners[i][3] - let extraData = thisObject.listeners[i][4] - - handler(event, extraData) - } - } - } -} diff --git a/Files-Component/src/FileCursor.js b/Files-Component/src/FileCursor.js index d35cad879..d1bede545 100644 --- a/Files-Component/src/FileCursor.js +++ b/Files-Component/src/FileCursor.js @@ -44,8 +44,8 @@ function newFileCursor () { function finalize () { try { - systemEventHandler.stopListening('Dataset Updated', eventSubscriptionIdDatasetUpdated) - systemEventHandler.stopListening('Data Range Updated', eventSubscriptionIdDataRangeUpdated) + eventsServerClient.stopListening('Dataset Updated', eventSubscriptionIdDatasetUpdated) + eventsServerClient.stopListening('Data Range Updated', eventSubscriptionIdDataRangeUpdated) thisObject.eventHandler = undefined @@ -90,10 +90,10 @@ function newFileCursor () { endDateRange = pEndDateRange let key = dataMine.code.codeName + '-' + bot.code.codeName + '-' + product.code.codeName + '-' + dataset.code.codeName + '-' + exchange.name + '-' + market.baseAsset + '/' + market.quotedAsset - systemEventHandler.listenToEvent(key, 'Dataset Updated', undefined, key + '-' + periodName, onResponseDataSet, updateFiles) + eventsServerClient.listenToEvent(key, 'Dataset Updated', undefined, key + '-' + periodName, onResponseDataSet, updateFiles) key = dataMine.code.codeName + '-' + bot.code.codeName + '-' + product.code.codeName + '-' + exchange.name + '-' + market.baseAsset + '/' + market.quotedAsset - systemEventHandler.listenToEvent(key, 'Data Range Updated', undefined, key, onResponseDataRange, updateDataRange) + eventsServerClient.listenToEvent(key, 'Data Range Updated', undefined, key, onResponseDataRange, updateDataRange) callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE) diff --git a/Files-Component/src/FileSequence.js b/Files-Component/src/FileSequence.js index d06eb5bc1..feedf0b32 100644 --- a/Files-Component/src/FileSequence.js +++ b/Files-Component/src/FileSequence.js @@ -37,7 +37,7 @@ function newFileSequence () { function finalize () { try { - systemEventHandler.stopListening('Dataset Updated', eventSubscriptionIdDatasetUpdated) + eventsServerClient.stopListening('Dataset Updated', eventSubscriptionIdDatasetUpdated) thisObject.eventHandler.finalize() thisObject.eventHandler = undefined @@ -75,7 +75,7 @@ function newFileSequence () { callerId = newUniqueId() let key = dataMine.code.codeName + '-' + bot.code.codeName + '-' + product.code.codeName + '-' + dataset.code.codeName + '-' + exchange.name + '-' + market.baseAsset + '/' + market.quotedAsset - systemEventHandler.listenToEvent(key, 'Dataset Updated', undefined, callerId, onResponse, updateFiles) + eventsServerClient.listenToEvent(key, 'Dataset Updated', undefined, callerId, onResponse, updateFiles) function onResponse (message) { eventSubscriptionIdDatasetUpdated = message.eventSubscriptionId diff --git a/Files-Component/src/MarketFiles.js b/Files-Component/src/MarketFiles.js index 1954bc5e9..734314cfd 100644 --- a/Files-Component/src/MarketFiles.js +++ b/Files-Component/src/MarketFiles.js @@ -43,7 +43,7 @@ function newMarketFiles () { function finalize () { try { for (let i = 0; i < eventSubscriptionIdDatasetUpdated.length; i++) { - systemEventHandler.stopListening('Dataset Updated', eventSubscriptionIdDatasetUpdated[i]) + eventsServerClient.stopListening('Dataset Updated', eventSubscriptionIdDatasetUpdated[i]) } thisObject.eventHandler.finalize() @@ -109,7 +109,7 @@ function newMarketFiles () { if (filesLoaded + filesNotLoaded === marketFilesPeriods.length) { let key = dataMine.code.codeName + '-' + bot.code.codeName + '-' + product.code.codeName + '-' + dataset.code.codeName + '-' + exchange.name + '-' + market.baseAsset + '/' + market.quotedAsset - systemEventHandler.listenToEvent(key, 'Dataset Updated', undefined, key + '-' + periodName, onResponse, updateFiles) + eventsServerClient.listenToEvent(key, 'Dataset Updated', undefined, key + '-' + periodName, onResponse, updateFiles) callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE, thisObject) diff --git a/Legacy-Code/Masters/bots/Candles-Volumes-Indicator-Bot/Multi-Period-Daily/User.Bot.js b/Legacy-Code/Masters/bots/Candles-Volumes-Indicator-Bot/Multi-Period-Daily/User.Bot.js index 7329782c2..7ddba27e8 100644 --- a/Legacy-Code/Masters/bots/Candles-Volumes-Indicator-Bot/Multi-Period-Daily/User.Bot.js +++ b/Legacy-Code/Masters/bots/Candles-Volumes-Indicator-Bot/Multi-Period-Daily/User.Bot.js @@ -768,7 +768,7 @@ Read the candles and volumes from Exchange Raw Data and produce a file for each dateRange: dataRange } - global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Data Range Updated', event) + global.EVENT_SERVER_CLIENT.raiseEvent(key, 'Data Range Updated', event) callBack(global.DEFAULT_OK_RESPONSE); } diff --git a/Legacy-Code/Masters/bots/Stairs-Patterns-Indicator-Bot/Multi-Period-Daily/User.Bot.js b/Legacy-Code/Masters/bots/Stairs-Patterns-Indicator-Bot/Multi-Period-Daily/User.Bot.js index 7a19c75d4..3d85b8526 100644 --- a/Legacy-Code/Masters/bots/Stairs-Patterns-Indicator-Bot/Multi-Period-Daily/User.Bot.js +++ b/Legacy-Code/Masters/bots/Stairs-Patterns-Indicator-Bot/Multi-Period-Daily/User.Bot.js @@ -1606,7 +1606,7 @@ dateRange: dataRange } - global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Data Range Updated', event) + global.EVENT_SERVER_CLIENT.raiseEvent(key, 'Data Range Updated', event) callBack(global.DEFAULT_OK_RESPONSE); } diff --git a/TaskManager/.env b/TaskManager/.env deleted file mode 100644 index 65f0b300d..000000000 --- a/TaskManager/.env +++ /dev/null @@ -1,12 +0,0 @@ -TASK_SERVER_PATH=../TaskServer - - -# Task Manager Child process variables -INTER_PROCESS_FILES_PATH=../Inter-Process-Files -STORAGE_PATH=../Data-Storage -PLOTTERS_PATH=../Teams-Source-Code - -USE_KEYVAULT=false -WRITE_LOGS_TO_FILES=true -BOTS_PATH=../Teams-Source-Code -LOG_PATH=../Log-Files \ No newline at end of file diff --git a/TaskManager/SystemEventHandler.js b/TaskManager/SystemEventHandler.js deleted file mode 100644 index 7620ca72e..000000000 --- a/TaskManager/SystemEventHandler.js +++ /dev/null @@ -1,178 +0,0 @@ -exports.newSystemEventHandler = function newSystemEventHandler(ipc) { - let thisObject = { - initialize: initialize, - finalize: finalize, - createEventHandler: createEventHandler, - deleteEventHandler: deleteEventHandler, - listenToEvent: listenToEvent, - stopListening: stopListening, - raiseEvent: raiseEvent - } - - let eventListeners = new Map() - let responseWaiters = new Map() - - ipc.config.id = 'Task Server'; - ipc.config.retry = 1500; - ipc.config.silent = true; - - return thisObject - - function initialize(canllerName, callBackFunction) { - - ipc.connectTo( - 'world', - function () { - ipc.of.world.on( - 'connect', - function () { - ipc.log('## Connected to Superalgos Event Server ##'.rainbow, ipc.config.delay); - - let eventCommand = { - action: 'greetings', - from: canllerName - } - - sendCommand(eventCommand) - - callBackFunction() - } - ); - ipc.of.world.on( - 'disconnect', - function () { - ipc.log('Disconnected from Superalgos Event Server '.notice); - } - ); - ipc.of.world.on( - 'message', // here is where all incomming messages are processed. - function (data) { - ipc.log('Got a message from Superalgos Event Server: '.debug, data); - - let message = JSON.parse(data) - - if (message.action === 'Event Raised') { - let key - if (message.callerId) { - key = message.eventHandlerName + '-' + message.eventType + '-' + message.callerId - } else { - key = message.eventHandlerName + '-' + message.eventType - } - let handler = eventListeners.get(key) - if (handler) { - handler.callBack(message) - } else { - console.log(key + ' not found so could not deliver event raised.') - console.log(' Message = ' + data) - } - return - } - - if (message.action === 'Event Server Response') { - let handler = responseWaiters.get(message.callerId) - if (handler) { - handler(message) - } - return - } - } - ); - } - ); - } - - function finalize() { - /* Before disconnecting we will forze all eventListeners to stop listening. */ - const eventListenersArray = [...eventListeners.values()] - for (let i = 0; i < eventListenersArray.length; i++) { - let handler = eventListenersArray[i] - let eventCommand = { - action: 'stopListening', - eventHandlerName: handler.eventHandlerName, - eventType: handler.eventType, - callerId: handler.callerId - } - sendCommand(eventCommand) - } - ipc.disconnect('world'); - } - - function sendCommand(command, responseCallBack, eventsCallBack) { - - if (command.action === 'listenToEvent') { - let key - if (command.callerId) { - key = command.eventHandlerName + '-' + command.eventType + '-' + command.callerId - } else { - key = command.eventHandlerName + '-' + command.eventType - } - let handler = { - eventHandlerName: command.eventHandlerName, - eventType: command.eventType, - callerId: command.callerId, - callBack: eventsCallBack - } - eventListeners.set(key, handler) - } - if (command.callerId && responseCallBack) { - responseWaiters.set(command.callerId, responseCallBack) - } - - ipc.of.world.emit( - 'message', - JSON.stringify(command) - ) - } - - function createEventHandler(eventHandlerName, callerId, responseCallBack) { - let eventCommand = { - action: 'createEventHandler', - eventHandlerName: eventHandlerName, - callerId: callerId - } - sendCommand(eventCommand, responseCallBack) - } - - function deleteEventHandler(eventHandlerName, callerId, responseCallBack) { - let eventCommand = { - action: 'deleteEventHandler', - eventHandlerName: eventHandlerName, - callerId: callerId - } - sendCommand(eventCommand, responseCallBack) - } - - function listenToEvent(eventHandlerName, eventType, extraData, callerId, responseCallBack, eventsCallBack) { - let eventCommand = { - action: 'listenToEvent', - eventHandlerName: eventHandlerName, - eventType: eventType, - extraData: extraData, - callerId: callerId - } - sendCommand(eventCommand, responseCallBack, eventsCallBack) - } - - function stopListening(eventHandlerName, eventType, eventSubscriptionId, callerId, responseCallBack) { - /* User either needs to specify a valid eventSubscriptionId OR the 3 params: eventHandlerName, eventType, callerId which were used when start listening to events. */ - let eventCommand = { - action: 'stopListening', - eventHandlerName: eventHandlerName, - eventType: eventType, - eventSubscriptionId: eventSubscriptionId, - callerId: callerId - } - sendCommand(eventCommand, responseCallBack) - } - - function raiseEvent(eventHandlerName, eventType, event, callerId, responseCallBack) { - let eventCommand = { - action: 'raiseEvent', - eventHandlerName: eventHandlerName, - eventType: eventType, - event: event, - callerId: callerId - } - sendCommand(eventCommand, responseCallBack) - } -} \ No newline at end of file diff --git a/TaskManager/node_modules/dotenv/package.json b/TaskManager/node_modules/dotenv/package.json deleted file mode 100644 index bf0ee8863..000000000 --- a/TaskManager/node_modules/dotenv/package.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "_from": "dotenv", - "_id": "dotenv@8.1.0", - "_inBundle": false, - "_integrity": "sha512-GUE3gqcDCaMltj2++g6bRQ5rBJWtkWTmqmD0fo1RnnMuUqHNCt2oTPeDnS9n6fKYvlhn7AeBkb38lymBtWBQdA==", - "_location": "/dotenv", - "_phantomChildren": {}, - "_requested": { - "type": "tag", - "registry": true, - "raw": "dotenv", - "name": "dotenv", - "escapedName": "dotenv", - "rawSpec": "", - "saveSpec": null, - "fetchSpec": "latest" - }, - "_requiredBy": [ - "#USER", - "/" - ], - "_resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.1.0.tgz", - "_shasum": "d811e178652bfb8a1e593c6dd704ec7e90d85ea2", - "_spec": "dotenv", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\BackendServer", - "bugs": { - "url": "https://github.com/motdotla/dotenv/issues" - }, - "bundleDependencies": false, - "dependencies": {}, - "deprecated": false, - "description": "Loads environment variables from .env file", - "devDependencies": { - "decache": "^4.5.1", - "flow-bin": "^0.105.2", - "sinon": "^7.4.1", - "standard": "^13.1.0", - "standard-markdown": "^5.1.0", - "standard-version": "^7.0.0", - "tap": "^14.6.1" - }, - "engines": { - "node": ">=8" - }, - "homepage": "https://github.com/motdotla/dotenv#readme", - "keywords": [ - "dotenv", - "env", - ".env", - "environment", - "variables", - "config", - "settings" - ], - "license": "BSD-2-Clause", - "main": "lib/main.js", - "name": "dotenv", - "repository": { - "type": "git", - "url": "git://github.com/motdotla/dotenv.git" - }, - "scripts": { - "flow": "flow", - "lint": "standard", - "postlint": "standard-markdown", - "prerelease": "npm test", - "pretest": "npm run lint", - "release": "standard-version", - "test": "tap tests/*.js --100" - }, - "standard": { - "ignore": [ - "flow-typed/" - ] - }, - "version": "8.1.0" -} diff --git a/TaskManager/node_modules/easy-stack/es5.js b/TaskManager/node_modules/easy-stack/es5.js deleted file mode 100644 index a756a7bbf..000000000 --- a/TaskManager/node_modules/easy-stack/es5.js +++ /dev/null @@ -1,74 +0,0 @@ -function Stack(){ - Object.defineProperties( - this, - { - add:{ - enumerable:true, - writable:false, - value:addToStack - }, - next:{ - enumerable:true, - writable:false, - value:run - }, - clear:{ - enumerable:true, - writable:false, - value:clearStack - }, - contents:{ - enumerable:false, - get:getStack, - set:setStack - }, - autoRun:{ - enumerable:true, - writable:true, - value:true - }, - stop:{ - enumerable:true, - writable:true, - value:false - } - } - ); - - var stack=[]; - var running=false; - var stop=false; - - function clearStack(){ - stack=[]; - return stack; - } - - function getStack(){ - return stack; - } - - function setStack(val){ - stack=val; - return stack; - } - - function addToStack(){ - for(var i in arguments){ - stack.unshift(arguments[i]); - } - if(!running && !this.stop && this.autoRun){ - this.next(); - } - } - - function run(){ - running=true; - if(stack.length<1 || this.stop){ - running=false; - return; - } - - stack.shift().bind(this)(); - } -} diff --git a/TaskManager/node_modules/easy-stack/example/basic.js b/TaskManager/node_modules/easy-stack/example/basic.js deleted file mode 100644 index f0d7fbb11..000000000 --- a/TaskManager/node_modules/easy-stack/example/basic.js +++ /dev/null @@ -1,18 +0,0 @@ -var Stack=require('../stack'); -//create a new Stack instance -var stack=new Stack; -stack.autoRun=false; - -for(var i=0; i<50; i++){ - //add a bunch of stuff to the stack - stack.add(makeRequest.bind(stack,i)); -} - -stack.next(); - -function makeRequest(index){ - //do stuff - console.log(`making LIFO request ${index}`); - - this.next(); -} diff --git a/TaskManager/node_modules/easy-stack/package.json b/TaskManager/node_modules/easy-stack/package.json deleted file mode 100644 index 9ba6fd25f..000000000 --- a/TaskManager/node_modules/easy-stack/package.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "_from": "easy-stack@^1.0.0", - "_id": "easy-stack@1.0.0", - "_inBundle": false, - "_integrity": "sha1-EskbMIWjfwuqM26UhurEv5Tj54g=", - "_location": "/easy-stack", - "_phantomChildren": {}, - "_requested": { - "type": "range", - "registry": true, - "raw": "easy-stack@^1.0.0", - "name": "easy-stack", - "escapedName": "easy-stack", - "rawSpec": "^1.0.0", - "saveSpec": null, - "fetchSpec": "^1.0.0" - }, - "_requiredBy": [ - "/js-queue" - ], - "_resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.0.tgz", - "_shasum": "12c91b3085a37f0baa336e9486eac4bf94e3e788", - "_spec": "easy-stack@^1.0.0", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskManager\\node_modules\\js-queue", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/easy-stack/issues" - }, - "bundleDependencies": false, - "deprecated": false, - "description": "Simple JS stack with auto run for node and browsers", - "engines": { - "node": ">=6.0.0" - }, - "homepage": "https://github.com/RIAEvangelist/easy-stack#readme", - "keywords": [ - "stack", - "node", - "js", - "auto", - "run", - "execute", - "browser", - "react" - ], - "license": "DBAD", - "main": "stack.js", - "name": "easy-stack", - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/easy-stack.git" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "1.0.0" -} diff --git a/TaskManager/node_modules/easy-stack/stack.js b/TaskManager/node_modules/easy-stack/stack.js deleted file mode 100644 index bfadd1dee..000000000 --- a/TaskManager/node_modules/easy-stack/stack.js +++ /dev/null @@ -1,39 +0,0 @@ -class Stack{ - constructor(){ - this.stack=[]; - this.autoRun=true; - this.running=false; - this.stop=false; - } - - clear(){ - this.stack=[]; - return this.stack; - } - - contents(val){ - if(val){ - this.stack=val; - } - return this.stack; - } - - add(...callbacks){ - this.stack.push(...callbacks); - if(!this.running && !this.stop && this.autoRun){ - this.next(); - } - } - - next(){ - this.running=true; - if(this.stack.length<1 || this.stop){ - this.running=false; - return; - } - - this.stack.pop().bind(this)(); - } -} - -module.exports=Stack; diff --git a/TaskManager/node_modules/event-pubsub/bower.json b/TaskManager/node_modules/event-pubsub/bower.json deleted file mode 100644 index a207b0a5d..000000000 --- a/TaskManager/node_modules/event-pubsub/bower.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "event-pubsub", - "description": "Super light and fast Extensible PubSub events and EventEmitters for Node and the browser with support for ES6 by default, and ES5 versions for older verions of node and older IE/Safari versions. Easy for any developer level. No frills, just high speed pubsub events!", - "main": "event-pubsub.js", - "authors": [ - "Brandon Nozaki Miller" - ], - "license": "DBAD", - "keywords": [ - "event", - "events", - "pubsub", - "node", - "browser" - ], - "homepage": "https://github.com/RIAEvangelist/event-pubsub", - "moduleType": [ - "globals", - "node" - ], - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" - ] -} diff --git a/TaskManager/node_modules/event-pubsub/es5.js b/TaskManager/node_modules/event-pubsub/es5.js deleted file mode 100644 index 7faf8b737..000000000 --- a/TaskManager/node_modules/event-pubsub/es5.js +++ /dev/null @@ -1,143 +0,0 @@ -'use strict'; - -function EventPubSub() { - this._events_={}; - this.publish=this.trigger=this.emit=emit; - this.subscribe=this.on=on; - this.once=once; - this.unSubscribe=this.off=off; - this.emit$=emit$; - - function on(type,handler,once){ - if(!handler){ - throw new ReferenceError('handler not defined.'); - } - - if(!this._events_[type]){ - this._events_[type]=[]; - } - - if(once){ - handler._once_ = once; - } - this._events_[type].push(handler); - return this; - } - - function once(type,handler){ - return this.on(type, handler, true); - } - - function off(type,handler){ - if(!this._events_[type]){ - return this; - } - - if(!handler){ - throw new ReferenceError('handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler'); - } - - if(handler=='*'){ - delete this._events_[type]; - return this; - } - - var handlers=this._events_[type]; - - while(handlers.includes(handler)){ - handlers.splice( - handlers.indexOf(handler), - 1 - ); - } - - if(handlers.length<1){ - delete this._events_[type]; - } - - return this; - } - - function emit(type){ - this.emit$.apply(this, arguments); - if(!this._events_[type]){ - return this; - } - arguments.splice=Array.prototype.splice; - arguments.splice(0,1); - - var handlers=this._events_[type]; - var onceHandled=[]; - - for(var i in handlers){ - var handler=handlers[i]; - handler.apply(this, arguments); - if(handler._once_){ - onceHandled.push(handler); - } - } - - for(var i in onceHandled){ - this.off( - type, - onceHandled[i] - ); - } - - return this; - } - - function emit$(type, args){ - if(!this._events_['*']){ - return this; - } - - var catchAll=this._events_['*']; - - args.shift=Array.prototype.shift; - args.shift(type); - - for(var handler of catchAll){ - handler.apply(this, args); - } - - return this; - } - - return this; -} - -if (!Array.prototype.includes) { - Array.prototype.includes = function(searchElement /*, fromIndex*/) { - 'use strict'; - if (this == null) { - throw new TypeError('Array.prototype.includes called on null or undefined'); - } - - var O = Object(this); - var len = parseInt(O.length, 10) || 0; - if (len === 0) { - return false; - } - var n = parseInt(arguments[1], 10) || 0; - var k; - if (n >= 0) { - k = n; - } else { - k = len + n; - if (k < 0) {k = 0;} - } - var currentElement; - while (k < len) { - currentElement = O[k]; - if (searchElement === currentElement || - (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN - return true; - } - k++; - } - return false; - }; -} - -module.exports=EventPubSub; diff --git a/TaskManager/node_modules/event-pubsub/es6.js b/TaskManager/node_modules/event-pubsub/es6.js deleted file mode 100644 index e9e859f9b..000000000 --- a/TaskManager/node_modules/event-pubsub/es6.js +++ /dev/null @@ -1,99 +0,0 @@ -'use strict'; - -class EventPubSub { - constructor( scope ) { - this._events_ = {}; - this.publish = this.trigger = this.emit; - this.subscribe = this.on; - this.unSubscribe = this.off; - } - - on( type, handler, once ) { - if ( !handler ) { - throw new ReferenceError( 'handler not defined.' ); - } - - if ( !this._events_[ type ] ) { - this._events_[ type ] = []; - } - - if(once){ - handler._once_ = once; - } - - this._events_[ type ].push( handler ); - return this; - } - - once( type, handler ) { - return this.on( type, handler, true ); - } - - off( type, handler ) { - if ( !this._events_[ type ] ) { - return this; - } - - if ( !handler ) { - throw new ReferenceError( 'handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler' ); - } - - if ( handler == '*' ) { - delete this._events_[ type ]; - return this; - } - - const handlers = this._events_[ type ]; - - while ( handlers.includes( handler ) ) { - handlers.splice( - handlers.indexOf( handler ), - 1 - ); - } - - if ( handlers.length < 1 ) { - delete this._events_[ type ]; - } - - return this; - } - - emit( type, ...args ) { - if ( !this._events_[ type ] ) { - return this.emit$( type, ...args ); - } - - const handlers = this._events_[ type ]; - const onceHandled=[]; - - for ( let handler of handlers ) { - handler.apply( this, args ); - if(handler._once_){ - onceHandled.push(handler); - } - } - - for(let handler of onceHandled){ - this.off(type,handler); - } - - return this.emit$( type, ...args ); - } - - emit$( type, ...args ) { - if ( !this._events_[ '*' ] ) { - return this; - } - - const catchAll = this._events_[ '*' ]; - - for ( let handler of catchAll ) { - handler.call( this, type, ...args ); - } - - return this; - } -} - -module.exports = EventPubSub; diff --git a/TaskManager/node_modules/event-pubsub/event-pubsub-browser-es5.js b/TaskManager/node_modules/event-pubsub/event-pubsub-browser-es5.js deleted file mode 100644 index 03f27625e..000000000 --- a/TaskManager/node_modules/event-pubsub/event-pubsub-browser-es5.js +++ /dev/null @@ -1,141 +0,0 @@ -'use strict'; - -window.EventPubSub=function EventPubSub() { - this._events_={}; - this.publish=this.trigger=this.emit=emit; - this.subscribe=this.on=on; - this.once=once; - this.unSubscribe=this.off=off; - this.emit$=emit$; - - function on(type,handler,once){ - if(!handler){ - throw new ReferenceError('handler not defined.'); - } - - if(!this._events_[type]){ - this._events_[type]=[]; - } - - if(once){ - handler._once_ = once; - } - this._events_[type].push(handler); - return this; - } - - function once(type,handler){ - return this.on(type, handler, true); - } - - function off(type,handler){ - if(!this._events_[type]){ - return this; - } - - if(!handler){ - throw new ReferenceError('handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler'); - } - - if(handler=='*'){ - delete this._events_[type]; - return this; - } - - var handlers=this._events_[type]; - - while(handlers.includes(handler)){ - handlers.splice( - handlers.indexOf(handler), - 1 - ); - } - - if(handlers.length<1){ - delete this._events_[type]; - } - - return this; - } - - function emit(type){ - this.emit$.apply(this, arguments); - if(!this._events_[type]){ - return this; - } - arguments.splice=Array.prototype.splice; - arguments.splice(0,1); - - var handlers=this._events_[type]; - var onceHandled=[]; - - for(var i in handlers){ - var handler=handlers[i]; - handler.apply(this, arguments); - if(handler._once_){ - onceHandled.push(handler); - } - } - - for(var i in onceHandled){ - this.off( - type, - onceHandled[i] - ); - } - - return this; - } - - function emit$(type, args){ - if(!this._events_['*']){ - return this; - } - - var catchAll=this._events_['*']; - - args.shift=Array.prototype.shift; - args.shift(type); - - for(var handler of catchAll){ - handler.apply(this, args); - } - - return this; - } - - return this; -} - -if (!Array.prototype.includes) { - Array.prototype.includes = function(searchElement /*, fromIndex*/) { - 'use strict'; - if (this == null) { - throw new TypeError('Array.prototype.includes called on null or undefined'); - } - - var O = Object(this); - var len = parseInt(O.length, 10) || 0; - if (len === 0) { - return false; - } - var n = parseInt(arguments[1], 10) || 0; - var k; - if (n >= 0) { - k = n; - } else { - k = len + n; - if (k < 0) {k = 0;} - } - var currentElement; - while (k < len) { - currentElement = O[k]; - if (searchElement === currentElement || - (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN - return true; - } - k++; - } - return false; - }; -} diff --git a/TaskManager/node_modules/event-pubsub/event-pubsub-browser.js b/TaskManager/node_modules/event-pubsub/event-pubsub-browser.js deleted file mode 100644 index d0bcd7b56..000000000 --- a/TaskManager/node_modules/event-pubsub/event-pubsub-browser.js +++ /dev/null @@ -1,130 +0,0 @@ -'use strict'; - -window.EventPubSub=class EventPubSub { - constructor( scope ) { - this._events_ = {}; - this.publish = this.trigger = this.emit; - this.subscribe = this.on; - this.unSubscribe = this.off; - } - - on( type, handler, once ) { - if ( !handler ) { - throw new ReferenceError( 'handler not defined.' ); - } - - if ( !this._events_[ type ] ) { - this._events_[ type ] = []; - } - - if(once){ - handler._once_ = once; - } - - this._events_[ type ].push( handler ); - return this; - } - - once( type, handler ) { - return this.on( type, handler, true ); - } - - off( type, handler ) { - if ( !this._events_[ type ] ) { - return this; - } - - if ( !handler ) { - throw new ReferenceError( 'handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler' ); - } - - if ( handler == '*' ) { - delete this._events_[ type ]; - return this; - } - - const handlers = this._events_[ type ]; - - while ( handlers.includes( handler ) ) { - handlers.splice( - handlers.indexOf( handler ), - 1 - ); - } - - if ( handlers.length < 1 ) { - delete this._events_[ type ]; - } - - return this; - } - - emit( type, ...args ) { - if ( !this._events_[ type ] ) { - return this.emit$( type, ...args ); - } - - const handlers = this._events_[ type ]; - const onceHandled=[]; - - for ( let handler of handlers ) { - handler.apply( this, args ); - if(handler._once_){ - onceHandled.push(handler); - } - } - - for(let handler of onceHandled){ - this.off(type,handler); - } - - return this.emit$( type, ...args ); - } - - emit$( type, ...args ) { - if ( !this._events_[ '*' ] ) { - return this; - } - - const catchAll = this._events_[ '*' ]; - - for ( let handler of catchAll ) { - handler.call( this, type, ...args ); - } - - return this; - } -} - -if (!Array.prototype.includes) { - Array.prototype.includes = function(searchElement /*, fromIndex*/) { - 'use strict'; - if (this == null) { - throw new TypeError('Array.prototype.includes called on null or undefined'); - } - - var O = Object(this); - var len = parseInt(O.length, 10) || 0; - if (len === 0) { - return false; - } - var n = parseInt(arguments[1], 10) || 0; - var k; - if (n >= 0) { - k = n; - } else { - k = len + n; - if (k < 0) {k = 0;} - } - var currentElement; - while (k < len) { - currentElement = O[k]; - if (searchElement === currentElement || - (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN - return true; - } - k++; - } - return false; - }; -} diff --git a/TaskManager/node_modules/event-pubsub/event-pubsub.js b/TaskManager/node_modules/event-pubsub/event-pubsub.js deleted file mode 100644 index 65bd02419..000000000 --- a/TaskManager/node_modules/event-pubsub/event-pubsub.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -let EventPubSub = require('./es5'); -if(process.version[1]>5){ - EventPubSub = require('./es6'); -} - -module.exports=EventPubSub; diff --git a/TaskManager/node_modules/event-pubsub/package.json b/TaskManager/node_modules/event-pubsub/package.json deleted file mode 100644 index 0d216088c..000000000 --- a/TaskManager/node_modules/event-pubsub/package.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "_from": "event-pubsub@4.3.0", - "_id": "event-pubsub@4.3.0", - "_inBundle": false, - "_integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==", - "_location": "/event-pubsub", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "event-pubsub@4.3.0", - "name": "event-pubsub", - "escapedName": "event-pubsub", - "rawSpec": "4.3.0", - "saveSpec": null, - "fetchSpec": "4.3.0" - }, - "_requiredBy": [ - "/node-ipc" - ], - "_resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz", - "_shasum": "f68d816bc29f1ec02c539dc58c8dd40ce72cb36e", - "_spec": "event-pubsub@4.3.0", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskManager\\node_modules\\node-ipc", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/event-pubsub/issues" - }, - "bundleDependencies": false, - "deprecated": false, - "description": "Super light and fast Extensible PubSub events and EventEmitters for Node and the browser with support for ES6 by default, and ES5 versions for older verions of node and older IE/Safari versions. Easy for any developer level. No frills, just high speed pubsub events!", - "directories": { - "example": "examples" - }, - "engines": { - "node": ">=4.0.0" - }, - "homepage": "https://github.com/RIAEvangelist/event-pubsub", - "keywords": [ - "event", - "events", - "pubsub", - "node", - "browser" - ], - "license": "Unlicense", - "main": "event-pubsub.js", - "name": "event-pubsub", - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/event-pubsub.git" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "4.3.0" -} diff --git a/TaskManager/node_modules/js-message/Message.js b/TaskManager/node_modules/js-message/Message.js deleted file mode 100644 index 9a4698232..000000000 --- a/TaskManager/node_modules/js-message/Message.js +++ /dev/null @@ -1,71 +0,0 @@ -function Message() { - Object.defineProperties( - this, { - data: { - enumerable: true, - get: getData, - set: setData - }, - type: { - enumerable: true, - get: getType, - set: setType - }, - load:{ - enumarable:true, - writable:false, - value:parse - }, - JSON: { - enumerable: true, - get: getJSON - } - } - ); - - var type = ''; - var data = {}; - - function getType() { - return type; - } - - function getData() { - return data; - } - - function getJSON() { - return JSON.stringify( - { - type: type, - data: data - } - ); - } - - function setType(value) { - type = value; - } - - function setData(value) { - data = value; - } - - function parse(message){ - try{ - var message=JSON.parse(message); - type=message.type; - data=message.data; - }catch(err){ - var badMessage=message; - type='error', - data={ - message:'Invalid JSON response format', - err:err, - response:badMessage - } - } - } -} - -module.exports=Message; diff --git a/TaskManager/node_modules/js-message/js-message-vanilla.js b/TaskManager/node_modules/js-message/js-message-vanilla.js deleted file mode 100644 index 0c49c2b6c..000000000 --- a/TaskManager/node_modules/js-message/js-message-vanilla.js +++ /dev/null @@ -1,75 +0,0 @@ -( - function(){ - function Message() { - Object.defineProperties( - this, { - data: { - enumerable: true, - get: getData, - set: setData - }, - type: { - enumerable: true, - get: getType, - set: setType - }, - load:{ - enumarable:true, - writable:false, - value:parse - }, - JSON: { - enumerable: true, - get: getJSON - } - } - ); - - var type = ''; - var data = {}; - - function getType() { - return type; - } - - function getData() { - return data; - } - - function getJSON() { - return JSON.stringify( - { - type: type, - data: data - } - ); - } - - function setType(value) { - type = value; - } - - function setData(value) { - data = value; - } - - function parse(message){ - try{ - var message=JSON.parse(message); - type=message.type; - data=message.data; - }catch(err){ - var badMessage=message; - type='error', - data={ - message:'Invalid JSON response format', - err:err, - response:badMessage - } - } - } - } - - window.message=Message; - } -)(); diff --git a/TaskManager/node_modules/js-message/package.json b/TaskManager/node_modules/js-message/package.json deleted file mode 100644 index 8a9abd0bb..000000000 --- a/TaskManager/node_modules/js-message/package.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "_from": "js-message@1.0.5", - "_id": "js-message@1.0.5", - "_inBundle": false, - "_integrity": "sha1-IwDSSxrwjondCVvBpMnJz8uJLRU=", - "_location": "/js-message", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "js-message@1.0.5", - "name": "js-message", - "escapedName": "js-message", - "rawSpec": "1.0.5", - "saveSpec": null, - "fetchSpec": "1.0.5" - }, - "_requiredBy": [ - "/node-ipc" - ], - "_resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.5.tgz", - "_shasum": "2300d24b1af08e89dd095bc1a4c9c9cfcb892d15", - "_spec": "js-message@1.0.5", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskManager\\node_modules\\node-ipc", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/js-message/issues" - }, - "bundleDependencies": false, - "dependencies": {}, - "deprecated": false, - "description": "normalized JS Object and JSON message and event protocol for node.js, vanialla js, react.js, components, actions, stores and dispatchers", - "devDependencies": {}, - "engines": { - "node": ">=0.6.0" - }, - "homepage": "https://github.com/RIAEvangelist/js-message#readme", - "keywords": [ - "message", - "normalize", - "events", - "js", - "json", - "protocol", - "ipc", - "node", - "nodejs", - "node.js", - "react", - "react.js", - "reactjs", - "websocket", - "websockets", - "web", - "socket", - "sockets", - "ws", - "flux", - "reflux", - "component", - "components", - "store", - "stores", - "action", - "actions" - ], - "license": "DBAD", - "main": "Message.js", - "name": "js-message", - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/js-message.git" - }, - "scripts": { - "start": "node devServer.js", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "1.0.5" -} diff --git a/TaskManager/node_modules/js-queue/package.json b/TaskManager/node_modules/js-queue/package.json deleted file mode 100644 index 94ecd47a5..000000000 --- a/TaskManager/node_modules/js-queue/package.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "_from": "js-queue@2.0.0", - "_id": "js-queue@2.0.0", - "_inBundle": false, - "_integrity": "sha1-NiITz4YPRo8BJfxslqvBdCUx+Ug=", - "_location": "/js-queue", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "js-queue@2.0.0", - "name": "js-queue", - "escapedName": "js-queue", - "rawSpec": "2.0.0", - "saveSpec": null, - "fetchSpec": "2.0.0" - }, - "_requiredBy": [ - "/node-ipc" - ], - "_resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.0.tgz", - "_shasum": "362213cf860f468f0125fc6c96abc1742531f948", - "_spec": "js-queue@2.0.0", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskManager\\node_modules\\node-ipc", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/js-queue/issues" - }, - "bundleDependencies": false, - "dependencies": { - "easy-stack": "^1.0.0" - }, - "deprecated": false, - "description": "Simple JS queue with auto run for node and browsers", - "engines": { - "node": ">=1.0.0" - }, - "homepage": "https://github.com/RIAEvangelist/js-queue#readme", - "keywords": [ - "queue", - "node", - "js", - "auto", - "run", - "execute", - "browser", - "react" - ], - "license": "DBAD", - "main": "queue.js", - "name": "js-queue", - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/js-queue.git" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "2.0.0" -} diff --git a/TaskManager/node_modules/js-queue/queue-vanilla.js b/TaskManager/node_modules/js-queue/queue-vanilla.js deleted file mode 100644 index 6f15495ae..000000000 --- a/TaskManager/node_modules/js-queue/queue-vanilla.js +++ /dev/null @@ -1,74 +0,0 @@ -function Queue(){ - Object.defineProperties( - this, - { - add:{ - enumerable:true, - writable:false, - value:addToQueue - }, - next:{ - enumerable:true, - writable:false, - value:run - }, - clear:{ - enumerable:true, - writable:false, - value:clearQueue - }, - contents:{ - enumerable:false, - get:getQueue, - set:setQueue - }, - autoRun:{ - enumerable:true, - writable:true, - value:true - }, - stop:{ - enumerable:true, - writable:true, - value:false - } - } - ); - - var queue=[]; - var running=false; - var stop=false; - - function clearQueue(){ - queue=[]; - return queue; - } - - function getQueue(){ - return queue; - } - - function setQueue(val){ - queue=val; - return queue; - } - - function addToQueue(){ - for(var i in arguments){ - queue.push(arguments[i]); - } - if(!running && !this.stop && this.autoRun){ - this.next(); - } - } - - function run(){ - running=true; - if(queue.length<1 || this.stop){ - running=false; - return; - } - - queue.shift().bind(this)(); - } -} diff --git a/TaskManager/node_modules/js-queue/queue.js b/TaskManager/node_modules/js-queue/queue.js deleted file mode 100644 index a8698d7e9..000000000 --- a/TaskManager/node_modules/js-queue/queue.js +++ /dev/null @@ -1,76 +0,0 @@ -function Queue(asStack){ - Object.defineProperties( - this, - { - add:{ - enumerable:true, - writable:false, - value:addToQueue - }, - next:{ - enumerable:true, - writable:false, - value:run - }, - clear:{ - enumerable:true, - writable:false, - value:clearQueue - }, - contents:{ - enumerable:false, - get:getQueue, - set:setQueue - }, - autoRun:{ - enumerable:true, - writable:true, - value:true - }, - stop:{ - enumerable:true, - writable:true, - value:false - } - } - ); - - var queue=[]; - var running=false; - var stop=false; - - function clearQueue(){ - queue=[]; - return queue; - } - - function getQueue(){ - return queue; - } - - function setQueue(val){ - queue=val; - return queue; - } - - function addToQueue(){ - for(var i in arguments){ - queue.push(arguments[i]); - } - if(!running && !this.stop && this.autoRun){ - this.next(); - } - } - - function run(){ - running=true; - if(queue.length<1 || this.stop){ - running=false; - return; - } - - queue.shift().bind(this)(); - } -} - -module.exports=Queue; diff --git a/TaskManager/node_modules/js-queue/stack.js b/TaskManager/node_modules/js-queue/stack.js deleted file mode 100644 index a9c25640e..000000000 --- a/TaskManager/node_modules/js-queue/stack.js +++ /dev/null @@ -1,3 +0,0 @@ -const Stack=require('easy-stack'); - -module.exports = Stack; diff --git a/TaskManager/node_modules/node-ipc/dao/client.js b/TaskManager/node_modules/node-ipc/dao/client.js deleted file mode 100644 index 41ce50411..000000000 --- a/TaskManager/node_modules/node-ipc/dao/client.js +++ /dev/null @@ -1,257 +0,0 @@ -'use strict'; - -const net = require('net'), - tls = require('tls'), - EventParser = require('../entities/EventParser.js'), - Message = require('js-message'), - fs = require('fs'), - Queue = require('js-queue'); - -let Events = require('event-pubsub/es5'); -if(process.version[1]>4){ - Events = require('event-pubsub'); -} - -let eventParser = new EventParser(); - -class Client extends Events{ - constructor(config,log){ - super(); - Object.assign( - this, - { - Client : Client, - config : config, - queue : new Queue, - socket : false, - connect : connect, - emit : emit, - log : log, - retriesRemaining:config.maxRetries||0, - explicitlyDisconnected: false - } - ); - - eventParser=new EventParser(this.config); - } -} - -function emit(type,data){ - this.log('dispatching event to ', this.id, this.path, ' : ', type, ',', data); - - let message=new Message; - message.type=type; - message.data=data; - - if(this.config.rawBuffer){ - message=new Buffer(type,this.config.encoding); - }else{ - message=eventParser.format(message); - } - - if(!this.config.sync){ - this.socket.write(message); - return; - } - - this.queue.add( - syncEmit.bind(this,message) - ); -} - -function syncEmit(message){ - this.log('dispatching event to ', this.id, this.path, ' : ', message); - this.socket.write(message); -} - -function connect(){ - //init client object for scope persistance especially inside of socket events. - let client=this; - - client.log('requested connection to ', client.id, client.path); - if(!this.path){ - client.log('\n\n######\nerror: ', client.id ,' client has not specified socket path it wishes to connect to.'); - return; - } - - const options={}; - - if(!client.port){ - client.log('Connecting client on Unix Socket :', client.path); - - options.path=client.path; - - if (process.platform ==='win32' && !client.path.startsWith('\\\\.\\pipe\\')){ - options.path = options.path.replace(/^\//, ''); - options.path = options.path.replace(/\//g, '-'); - options.path= `\\\\.\\pipe\\${options.path}`; - } - - client.socket = net.connect(options); - }else{ - options.host=client.path; - options.port=client.port; - - if(client.config.interface.localAddress){ - options.localAddress=client.config.interface.localAddress; - } - - if(client.config.interface.localPort){ - options.localPort=client.config.interface.localPort; - } - - if(client.config.interface.family){ - options.family=client.config.interface.family; - } - - if(client.config.interface.hints){ - options.hints=client.config.interface.hints; - } - - if(client.config.interface.lookup){ - options.lookup=client.config.interface.lookup; - } - - if(!client.config.tls){ - client.log('Connecting client via TCP to', options); - client.socket = net.connect(options); - }else{ - client.log('Connecting client via TLS to', client.path ,client.port,client.config.tls); - if(client.config.tls.private){ - client.config.tls.key=fs.readFileSync(client.config.tls.private); - } - if(client.config.tls.public){ - client.config.tls.cert=fs.readFileSync(client.config.tls.public); - } - if(client.config.tls.trustedConnections){ - if(typeof client.config.tls.trustedConnections === 'string'){ - client.config.tls.trustedConnections=[client.config.tls.trustedConnections]; - } - client.config.tls.ca=[]; - for(let i=0; i4){ - Events = require('event-pubsub'); -} - -let eventParser = new EventParser(); - -class Server extends Events{ - constructor(path,config,log,port){ - super(); - Object.assign( - this, - { - config : config, - path : path, - port : port, - udp4 : false, - udp6 : false, - log : log, - server : false, - sockets : [], - emit : emit, - broadcast : broadcast - } - ); - - eventParser=new EventParser(this.config); - - this.on( - 'close', - serverClosed.bind(this) - ); - } - - onStart(socket){ - this.trigger( - 'start', - socket - ); - } - - stop(){ - this.server.close(); - } - - start(){ - if(!this.path){ - this.log('Socket Server Path not specified, refusing to start'); - return; - } - - if(this.config.unlink){ - fs.unlink( - this.path, - startServer.bind(this) - ); - }else{ - startServer.bind(this)(); - } - } -} - -function emit(socket, type, data){ - this.log('dispatching event to socket', ' : ', type, data); - - let message=new Message; - message.type=type; - message.data=data; - - if(this.config.rawBuffer){ - this.log(this.config.encoding) - message=new Buffer(type,this.config.encoding); - }else{ - message=eventParser.format(message); - } - - if(this.udp4 || this.udp6){ - - if(!socket.address || !socket.port){ - this.log('Attempting to emit to a single UDP socket without supplying socket address or port. Redispatching event as broadcast to all connected sockets'); - this.broadcast(type,data); - return; - } - - this.server.write( - message, - socket - ); - return; - } - - socket.write(message); -} - -function broadcast(type,data){ - this.log('broadcasting event to all known sockets listening to ', this.path,' : ', ((this.port)?this.port:''), type, data); - let message=new Message; - message.type=type; - message.data=data; - - if(this.config.rawBuffer){ - message=new Buffer(type,this.config.encoding); - }else{ - message=eventParser.format(message); - } - - if(this.udp4 || this.udp6){ - for(let i=1, count=this.sockets.length; i0){ - let message=new Message; - message.load(data.shift()); - - // Only set the sock id if it is specified. - if (message.data && message.data.id){ - sock.id=message.data.id; - } - - this.log('received event of : ',message.type,message.data); - - this.publish( - message.type, - message.data, - sock - ); - } -} - -function socketClosed(socket){ - this.publish( - 'close', - socket - ); -} - -function serverCreated(socket) { - this.sockets.push(socket); - - if(socket.setEncoding){ - socket.setEncoding(this.config.encoding); - } - - this.log('## socket connection to server detected ##'); - socket.on( - 'close', - socketClosed.bind(this) - ); - - socket.on( - 'error', - function(err){ - this.log('server socket error',err); - - this.publish('error',err); - }.bind(this) - ); - - socket.on( - 'data', - gotData.bind(this,socket) - ); - - socket.on( - 'message', - function(msg,rinfo) { - if (!rinfo){ - return; - } - - this.log('Received UDP message from ', rinfo.address, rinfo.port); - let data; - - if(this.config.rawSocket){ - data=new Buffer(msg,this.config.encoding); - }else{ - data=msg.toString(); - } - socket.emit('data',data,rinfo); - }.bind(this) - ); - - this.publish( - 'connect', - socket - ); - - if(this.config.rawBuffer){ - return; - } -} - -function startServer() { - this.log( - 'starting server on ',this.path, - ((this.port)?`:${this.port}`:'') - ); - - if(!this.udp4 && !this.udp6){ - this.log('starting TLS server',this.config.tls); - if(!this.config.tls){ - this.server=net.createServer( - serverCreated.bind(this) - ); - }else{ - startTLSServer.bind(this)(); - } - }else{ - this.server=dgram.createSocket( - ((this.udp4)? 'udp4':'udp6') - ); - this.server.write=UDPWrite.bind(this); - this.server.on( - 'listening', - function UDPServerStarted() { - serverCreated.bind(this)(this.server); - }.bind(this) - ); - } - - this.server.on( - 'error', - function(err){ - this.log('server error',err); - - this.publish( - 'error', - err - ); - }.bind(this) - ); - - this.server.maxConnections=this.config.maxConnections; - - if(!this.port){ - this.log('starting server as', 'Unix || Windows Socket'); - if (process.platform ==='win32'){ - this.path = this.path.replace(/^\//, ''); - this.path = this.path.replace(/\//g, '-'); - this.path= `\\\\.\\pipe\\${this.path}`; - } - - this.server.listen( - this.path, - this.onStart.bind(this) - ); - - return; - } - - if(!this.udp4 && !this.udp6){ - this.log('starting server as', (this.config.tls?'TLS':'TCP')); - this.server.listen( - this.port, - this.path, - this.onStart.bind(this) - ); - return; - } - - this.log('starting server as',((this.udp4)? 'udp4':'udp6')); - - this.server.bind( - this.port, - this.path - ); - - this.onStart( - { - address : this.path, - port : this.port - } - ); -} - -function startTLSServer(){ - this.log('starting TLS server',this.config.tls); - if(this.config.tls.private){ - this.config.tls.key=fs.readFileSync(this.config.tls.private); - }else{ - this.config.tls.key=fs.readFileSync(`${__dirname}/../local-node-ipc-certs/private/server.key`); - } - if(this.config.tls.public){ - this.config.tls.cert=fs.readFileSync(this.config.tls.public); - }else{ - this.config.tls.cert=fs.readFileSync(`${__dirname}/../local-node-ipc-certs/server.pub`); - } - if(this.config.tls.dhparam){ - this.config.tls.dhparam=fs.readFileSync(this.config.tls.dhparam); - } - if(this.config.tls.trustedConnections){ - if(typeof this.config.tls.trustedConnections === 'string'){ - this.config.tls.trustedConnections=[this.config.tls.trustedConnections]; - } - this.config.tls.ca=[]; - for(let i=0; i 0) { - // getting the family of first network interface available - IPType = networkInterfaces [ - Object.keys( networkInterfaces )[0] - ][0].family; - } - return IPType; -} - -module.exports=Defaults; diff --git a/TaskManager/node_modules/node-ipc/entities/EventParser.js b/TaskManager/node_modules/node-ipc/entities/EventParser.js deleted file mode 100644 index 8ac1f2bda..000000000 --- a/TaskManager/node_modules/node-ipc/entities/EventParser.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -const Defaults = require('./Defaults.js'); - -class Parser{ - constructor(config){ - if(!config){ - config=new Defaults; - } - this.delimiter=config.delimiter; - } - - format(message){ - if(!message.data && message.data!==false && message.data!==0){ - message.data={}; - } - if(message.data['_maxListeners']){ - message.data={}; - } - - message=message.JSON+this.delimiter; - return message; - } - - parse(data){ - let events=data.split(this.delimiter); - events.pop(); - return events; - } -} - -module.exports=Parser; diff --git a/TaskManager/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/goodbye-client.js b/TaskManager/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/goodbye-client.js deleted file mode 100644 index 9d5ce05d6..000000000 --- a/TaskManager/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/goodbye-client.js +++ /dev/null @@ -1,44 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'goodbye'; -ipc.config.retry= 1500; -ipc.config.maxRetries= 10; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'goodbye' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/hello-client.js b/TaskManager/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/hello-client.js deleted file mode 100644 index 74136333d..000000000 --- a/TaskManager/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/hello-client.js +++ /dev/null @@ -1,50 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.maxRetries=10; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data.message); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/world-server.js b/TaskManager/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/world-server.js deleted file mode 100644 index 2bef44794..000000000 --- a/TaskManager/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/world-server.js +++ /dev/null @@ -1,51 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -var messages={ - goodbye:false, - hello:false -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - ipc.log('got a message from', (data.id), (data.message)); - messages[data.id]=true; - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - - if(messages.hello && messages.goodbye){ - ipc.log('got all required events, telling clients to kill connection'); - ipc.server.broadcast( - 'kill.connection', - { - id:ipc.config.id - } - ); - } - } - ); - } -); - - - - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/TCPSocket/basic/hello-client.js b/TaskManager/node_modules/node-ipc/example/TCPSocket/basic/hello-client.js deleted file mode 100644 index 6ae692edf..000000000 --- a/TaskManager/node_modules/node-ipc/example/TCPSocket/basic/hello-client.js +++ /dev/null @@ -1,39 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/TCPSocket/basic/world-server.js b/TaskManager/node_modules/node-ipc/example/TCPSocket/basic/world-server.js deleted file mode 100644 index 6c8790170..000000000 --- a/TaskManager/node_modules/node-ipc/example/TCPSocket/basic/world-server.js +++ /dev/null @@ -1,44 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.maxConnections=1; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log('DISCONNECTED\n\n',arguments); - } - ); - } -); - -ipc.server.on( - 'error', - function(err){ - ipc.log('Got an ERROR!',err); - } -); - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/TCPSocket/basicSync/hello-client.js b/TaskManager/node_modules/node-ipc/example/TCPSocket/basicSync/hello-client.js deleted file mode 100644 index 292415053..000000000 --- a/TaskManager/node_modules/node-ipc/example/TCPSocket/basicSync/hello-client.js +++ /dev/null @@ -1,46 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.sync= true; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - - //queue up a bunch of requests to be sent synchronously - for(var i=0; i<10; i++){ - ipc.of.world.emit( - 'message', - 'hello'+i - ); - } - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data,'\n\n'); - } - ); - } -); - -console.log(ipc); diff --git a/TaskManager/node_modules/node-ipc/example/TCPSocket/basicSync/world-server.js b/TaskManager/node_modules/node-ipc/example/TCPSocket/basicSync/world-server.js deleted file mode 100644 index 3e817da13..000000000 --- a/TaskManager/node_modules/node-ipc/example/TCPSocket/basicSync/world-server.js +++ /dev/null @@ -1,45 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.sync = true; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - //fake some synch procedural code - setTimeout( - function(){ - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - }, - 3000 - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/TCPSocket/rawBuffer/hello-client.js b/TaskManager/node_modules/node-ipc/example/TCPSocket/rawBuffer/hello-client.js deleted file mode 100644 index b6ac81f6b..000000000 --- a/TaskManager/node_modules/node-ipc/example/TCPSocket/rawBuffer/hello-client.js +++ /dev/null @@ -1,35 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'hello' - ); - } - ); - - ipc.of.world.on( - 'data', - function(data){ - ipc.log('got a message from world : ', data,data.toString()); - } - ); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/TCPSocket/rawBuffer/world.server.js b/TaskManager/node_modules/node-ipc/example/TCPSocket/rawBuffer/world.server.js deleted file mode 100644 index 5da4de4d5..000000000 --- a/TaskManager/node_modules/node-ipc/example/TCPSocket/rawBuffer/world.server.js +++ /dev/null @@ -1,40 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.serveNet( - function(){ - ipc.server.on( - 'connect', - function(socket){ - ipc.server.emit( - socket, - 'hello' - ); - } - ); - - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data,data.toString()); - ipc.server.emit( - socket, - 'goodbye' - ); - } - ); - } -); - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/goodbye-client.js b/TaskManager/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/goodbye-client.js deleted file mode 100644 index 508702d01..000000000 --- a/TaskManager/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/goodbye-client.js +++ /dev/null @@ -1,47 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'goodbye'; -ipc.config.retry= 1500; -ipc.config.maxRetries= 10; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'goodbye' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/hello-client.js b/TaskManager/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/hello-client.js deleted file mode 100644 index 16fd21fc3..000000000 --- a/TaskManager/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/hello-client.js +++ /dev/null @@ -1,53 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.maxRetries=10; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data.message); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/world-server.js b/TaskManager/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/world-server.js deleted file mode 100644 index 0c52c268d..000000000 --- a/TaskManager/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/world-server.js +++ /dev/null @@ -1,55 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key' -}; - -var messages={ - goodbye:false, - hello:false -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - ipc.log('got a message from', (data.id), (data.message)); - messages[data.id]=true; - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - - if(messages.hello && messages.goodbye){ - ipc.log('got all required events, telling clients to kill connection'); - ipc.server.broadcast( - 'kill.connection', - { - id:ipc.config.id - } - ); - } - } - ); - } -); - - - - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-local-only/hello-client.js b/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-local-only/hello-client.js deleted file mode 100644 index 15771565b..000000000 --- a/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-local-only/hello-client.js +++ /dev/null @@ -1,42 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-local-only/world-server.js b/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-local-only/world-server.js deleted file mode 100644 index 3cbcd8e38..000000000 --- a/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-local-only/world-server.js +++ /dev/null @@ -1,42 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -//node-ipc will default to its local certs -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-more-secure/hello-client.js b/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-more-secure/hello-client.js deleted file mode 100644 index bda3eb701..000000000 --- a/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-more-secure/hello-client.js +++ /dev/null @@ -1,47 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.tls={ - private: __dirname+'/../../../local-node-ipc-certs/private/client.key', - public: __dirname+'/../../../local-node-ipc-certs/client.pub', - rejectUnauthorized:false, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/server.pub' - ] -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-more-secure/world-server.js b/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-more-secure/world-server.js deleted file mode 100644 index 56eee122b..000000000 --- a/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-more-secure/world-server.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key', - dhparam: __dirname+'/../../../local-node-ipc-certs/private/dhparam.pem', - requestCert: true, - rejectUnauthorized:false, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/client.pub' - ] -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-most-secure/hello-client.js b/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-most-secure/hello-client.js deleted file mode 100644 index 26d5b1da6..000000000 --- a/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-most-secure/hello-client.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.networkHost='localhost'; -ipc.config.tls={ - private: __dirname+'/../../../local-node-ipc-certs/private/client.key', - public: __dirname+'/../../../local-node-ipc-certs/client.pub', - rejectUnauthorized:true, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/server.pub' - ] -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-most-secure/world-server.js b/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-most-secure/world-server.js deleted file mode 100644 index ee984a4e1..000000000 --- a/TaskManager/node_modules/node-ipc/example/TLSSocket/basic-most-secure/world-server.js +++ /dev/null @@ -1,49 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.networkHost='localhost'; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key', - dhparam: __dirname+'/../../../local-node-ipc-certs/private/dhparam.pem', - requestCert: true, - rejectUnauthorized:true, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/client.pub' - ] -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/TLSSocket/basic/hello-client.js b/TaskManager/node_modules/node-ipc/example/TLSSocket/basic/hello-client.js deleted file mode 100644 index 15771565b..000000000 --- a/TaskManager/node_modules/node-ipc/example/TLSSocket/basic/hello-client.js +++ /dev/null @@ -1,42 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/TLSSocket/basic/world-server.js b/TaskManager/node_modules/node-ipc/example/TLSSocket/basic/world-server.js deleted file mode 100644 index a52c3602a..000000000 --- a/TaskManager/node_modules/node-ipc/example/TLSSocket/basic/world-server.js +++ /dev/null @@ -1,42 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key' -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/TLSSocket/basicSync/hello-client.js b/TaskManager/node_modules/node-ipc/example/TLSSocket/basicSync/hello-client.js deleted file mode 100644 index 405db4468..000000000 --- a/TaskManager/node_modules/node-ipc/example/TLSSocket/basicSync/hello-client.js +++ /dev/null @@ -1,47 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.sync= true; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - - //queue up a bunch of requests to be sent synchronously - for(var i=0; i<10; i++){ - ipc.of.world.emit( - 'message', - 'hello'+i - ); - } - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/TLSSocket/basicSync/world-server.js b/TaskManager/node_modules/node-ipc/example/TLSSocket/basicSync/world-server.js deleted file mode 100644 index aec87c100..000000000 --- a/TaskManager/node_modules/node-ipc/example/TLSSocket/basicSync/world-server.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.sync= true; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key' -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - setTimeout( - function(){ - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - }, - 3000 - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/hello-client.js b/TaskManager/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/hello-client.js deleted file mode 100644 index f0c66ad22..000000000 --- a/TaskManager/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/hello-client.js +++ /dev/null @@ -1,45 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; -ipc.config.networkHost='localhost'; - -ipc.config.tls={ - private: __dirname+'/../../../local-node-ipc-certs/private/client.key', - public: __dirname+'/../../../local-node-ipc-certs/client.pub', - rejectUnauthorized:true, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/server.pub' - ] -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'hello' - ); - } - ); - - ipc.of.world.on( - 'data', - function(data){ - ipc.log('got a message from world : ', data,data.toString()); - } - ); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/world.server.js b/TaskManager/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/world.server.js deleted file mode 100644 index f0d0b29af..000000000 --- a/TaskManager/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/world.server.js +++ /dev/null @@ -1,53 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; -ipc.config.networkHost='localhost'; - -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key', - dhparam: __dirname+'/../../../local-node-ipc-certs/private/dhparam.pem', - requestCert: true, - rejectUnauthorized:true, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/client.pub' - ] -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'connect', - function(socket){ - console.log('connection detected'); - ipc.server.emit( - socket, - 'hello' - ); - } - ); - - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data,data.toString()); - ipc.server.emit( - socket, - 'goodbye' - ); - } - ); - } -); - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/goodbye-client.js b/TaskManager/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/goodbye-client.js deleted file mode 100644 index d98a7b061..000000000 --- a/TaskManager/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/goodbye-client.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * Since there is no client relationship - * with UDP sockets sockets are not kept - * open. - * - * This means the order sockets are opened - * is important. - * - * Start World first. Then you can start - * hello or goodbye in any order you - * choose. - * - * *************************************/ - -ipc.config.id = 'goodbye'; -ipc.config.retry= 1500; - -ipc.serveNet( - 8002, //we set the port here because the hello client and world server are already using the default of 8000 and the port 8001. So we can not bind to those while hello and world are connected to them. - 'udp4', - function(){ - ipc.server.on( - 'message', - function(data){ - ipc.log('got Data'); - ipc.log('got a message from ', data.id ,' : ', data.message); - } - ); - ipc.server.emit( - { - address : 'localhost', - port : ipc.config.networkPort - }, - 'message', - { - id : ipc.config.id, - message : 'Goodbye' - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/hello-client.js b/TaskManager/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/hello-client.js deleted file mode 100644 index ecc0b45a4..000000000 --- a/TaskManager/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/hello-client.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * Since there is no client relationship - * with UDP sockets sockets are not kept - * open. - * - * This means the order sockets are opened - * is important. - * - * Start World first. Then you can start - * hello or goodbye in any order you - * choose. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; - -ipc.serveNet( - 8001, //we set the port here because the world server is already using the default of 8000. So we can not bind to 8000 while world is using it. - 'udp4', - function(){ - ipc.server.on( - 'message', - function(data){ - ipc.log('got Data'); - ipc.log('got a message from ', data.id ,' : ', data.message); - } - ); - ipc.server.emit( - { - address : 'localhost', - port : ipc.config.networkPort - }, - 'message', - { - id : ipc.config.id, - message : 'Hello' - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/world-server.js b/TaskManager/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/world-server.js deleted file mode 100644 index 97f927088..000000000 --- a/TaskManager/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/world-server.js +++ /dev/null @@ -1,63 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * Since there is no client relationship - * with UDP sockets sockets are not kept - * open. - * - * This means the order sockets are opened - * is important. - * - * Start World first. Then you can start - * hello or goodbye in any order you - * choose. - * - ***************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -var messages={ - goodbye:false, - hello:false -}; - -ipc.serveNet( - 'udp4', - function(){ - console.log(123); - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message from ', data.id ,' : ', data.message); - messages[data.id]=true; - ipc.server.emit( - socket, - 'message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - - if(messages.hello && messages.goodbye){ - ipc.log('got all required events, telling evryone how muchg I am loved!'); - ipc.server.broadcast( - 'message', - { - id : ipc.config.id, - message : 'Everybody Loves The World! Got messages from hello and goodbye!' - } - ); - } - } - ); - - console.log(ipc.server); - } -); - - - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/UDPSocket/basic/hello-client.js b/TaskManager/node_modules/node-ipc/example/UDPSocket/basic/hello-client.js deleted file mode 100644 index f731b1ba8..000000000 --- a/TaskManager/node_modules/node-ipc/example/UDPSocket/basic/hello-client.js +++ /dev/null @@ -1,52 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * UDP Client is really a UDP server - * - * Dedicated UDP sockets on the same - * machine can not be bound to in the - * traditional client/server method - * - * Every UDP socket is it's own UDP server - * And so must have a unique port on its - * machine, unlike TCP or Unix Sockts - * which can share on the same machine. - * - * Since there is no open client server - * relationship, you should start world - * first and then hello. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; - -ipc.serveNet( - 8001, //we set the port here because the world server is already using the default of 8000. So we can not bind to 8000 while world is using it. - 'udp4', - function(){ - ipc.server.on( - 'message', - function(data){ - ipc.log('got Data'); - ipc.log('got a message from ', data.id ,' : ', data.message); - } - ); - ipc.server.emit( - { - address : 'localhost', - port : ipc.config.networkPort - }, - 'message', - { - id : ipc.config.id, - message : 'Hello' - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/UDPSocket/basic/world-server.js b/TaskManager/node_modules/node-ipc/example/UDPSocket/basic/world-server.js deleted file mode 100644 index 0f7aa4543..000000000 --- a/TaskManager/node_modules/node-ipc/example/UDPSocket/basic/world-server.js +++ /dev/null @@ -1,47 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * UDP Client is really a UDP server - * - * Dedicated UDP sockets on the same - * machine can not be bound to in the - * traditional client/server method - * - * Every UDP socket is it's own UDP server - * And so must have a unique port on its - * machine, unlike TCP or Unix Sockts - * which can share on the same machine. - * - * Since there is no open client server - * relationship, you should start world - * first and then hello. - * - ***************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -ipc.serveNet( - 'udp4', - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message from ', data.id ,' : ', data.message); - ipc.server.emit( - socket, - 'message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/UDPSocket/rawBuffer/hello-client.js b/TaskManager/node_modules/node-ipc/example/UDPSocket/rawBuffer/hello-client.js deleted file mode 100644 index 73cd13ac5..000000000 --- a/TaskManager/node_modules/node-ipc/example/UDPSocket/rawBuffer/hello-client.js +++ /dev/null @@ -1,35 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.serveNet( - 8001, //we set the port here because the world server is already using the default of 8000. So we can not bind to 8000 while world is using it. - 'udp4', - function(){ - ipc.server.on( - 'data', - function(data){ - ipc.log('got a message from world ', data, data.toString()); - } - ); - ipc.server.emit( - { - address : 'localhost', - port : ipc.config.networkPort - }, - 'hello' - ); - } -); - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/UDPSocket/rawBuffer/world.server.js b/TaskManager/node_modules/node-ipc/example/UDPSocket/rawBuffer/world.server.js deleted file mode 100644 index d0c34f7e2..000000000 --- a/TaskManager/node_modules/node-ipc/example/UDPSocket/rawBuffer/world.server.js +++ /dev/null @@ -1,43 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * UDP Client is really a UDP server - * - * Dedicated UDP sockets on the same - * machine can not be bound to in the - * traditional client/server method - * - * Every UDP socket is it's own UDP server - * And so must have a unique port on its - * machine, unlike TCP or Unix Sockts - * which can share on the same machine. - * - * Since there is no open client server - * relationship, you should start world - * first and then hello. - * - ***************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.serveNet( - 'udp4', - function(){ - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data,data.toString()); - ipc.server.emit( - socket, - 'goodbye' - ); - } - ); - } -); - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/clusterUnixSocket/cluster-client.js b/TaskManager/node_modules/node-ipc/example/clusterUnixSocket/cluster-client.js deleted file mode 100644 index eca2a889c..000000000 --- a/TaskManager/node_modules/node-ipc/example/clusterUnixSocket/cluster-client.js +++ /dev/null @@ -1,31 +0,0 @@ -const fs = require('fs'); -const ipc = require('../../node-ipc'); - -const socketPath = '/tmp/ipc.sock'; - -//loop forever so you can see the pid of the cluster sever change in the logs -setInterval( - function() { - ipc.connectTo( - 'world', - socketPath, - connecting - ); - }, - 2000 -); - -function connecting(socket) { - ipc.of.world.on( - 'connect', - function() { - ipc.of.world.emit( - 'currentDate', - { - message: new Date().toISOString() - } - ); - ipc.disconnect('world'); - } - ); -} diff --git a/TaskManager/node_modules/node-ipc/example/clusterUnixSocket/cluster-server.js b/TaskManager/node_modules/node-ipc/example/clusterUnixSocket/cluster-server.js deleted file mode 100644 index b0942a338..000000000 --- a/TaskManager/node_modules/node-ipc/example/clusterUnixSocket/cluster-server.js +++ /dev/null @@ -1,32 +0,0 @@ -const fs = require('fs'); -const ipc=require('../../../node-ipc'); -const cpuCount = require('os').cpus().length; -const cluster = require('cluster'); -const socketPath = '/tmp/ipc.sock'; - -ipc.config.unlink = false; - -if (cluster.isMaster) { - if (fs.existsSync(socketPath)) { - fs.unlinkSync(socketPath); - } - - for (let i = 0; i < cpuCount; i++) { - cluster.fork(); - } -}else{ - ipc.serve( - socketPath, - function() { - ipc.server.on( - 'currentDate', - function(data,socket) { - console.log(`pid ${process.pid} got: `, data); - } - ); - } - ); - - ipc.server.start(); - console.log(`pid ${process.pid} listening on ${socketPath}`); -} diff --git a/TaskManager/node_modules/node-ipc/example/rawBuffer/hello-client.js b/TaskManager/node_modules/node-ipc/example/rawBuffer/hello-client.js deleted file mode 100644 index f22ab5376..000000000 --- a/TaskManager/node_modules/node-ipc/example/rawBuffer/hello-client.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict'; - -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='hex'; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - //make a 6 byte buffer for example - const myBuffer=new Buffer(6).fill(0); - - myBuffer.writeUInt16BE(0x02,0); - myBuffer.writeUInt32BE(0xffeecc,2); - - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - myBuffer - ); - } - ); - - ipc.of.world.on( - 'data', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/rawBuffer/world.server.js b/TaskManager/node_modules/node-ipc/example/rawBuffer/world.server.js deleted file mode 100644 index f27a02cd5..000000000 --- a/TaskManager/node_modules/node-ipc/example/rawBuffer/world.server.js +++ /dev/null @@ -1,40 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='hex'; - -ipc.serve( - function(){ - ipc.server.on( - 'connect', - function(socket){ - ipc.server.emit( - socket, - [0xaa] - ); - } - ); - - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data); - ipc.server.emit( - socket, - [0x0d,0xee] - ); - } - ); - } -); - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/goodbye-client.js b/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/goodbye-client.js deleted file mode 100644 index 57d455eec..000000000 --- a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/goodbye-client.js +++ /dev/null @@ -1,43 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'goodbye'; -ipc.config.retry= 1500; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'goodbye' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/hello-client.js b/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/hello-client.js deleted file mode 100644 index d556c4694..000000000 --- a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/hello-client.js +++ /dev/null @@ -1,49 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/world-server.js b/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/world-server.js deleted file mode 100644 index 69cfb31c0..000000000 --- a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/world-server.js +++ /dev/null @@ -1,51 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -var messages={ - goodbye:false, - hello:false -}; - -ipc.serve( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - ipc.log('got a message from', (data.id), (data.message)); - messages[data.id]=true; - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - - if(messages.hello && messages.goodbye){ - ipc.log('got all required events, telling clients to kill connection'); - ipc.server.broadcast( - 'kill.connection', - { - id:ipc.config.id - } - ); - } - } - ); - } -); - - - - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/basic/hello-client.js b/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/basic/hello-client.js deleted file mode 100644 index c6d87cb27..000000000 --- a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/basic/hello-client.js +++ /dev/null @@ -1,44 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry = 1000; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - - console.log(ipc.of.world.destroy); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/basic/world-server.js b/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/basic/world-server.js deleted file mode 100644 index 6b3052242..000000000 --- a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/basic/world-server.js +++ /dev/null @@ -1,33 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -ipc.serve( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/basicSync/hello-client.js b/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/basicSync/hello-client.js deleted file mode 100644 index 3142677a2..000000000 --- a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/basicSync/hello-client.js +++ /dev/null @@ -1,49 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry = 1000; -ipc.config.sync= true; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - - //queue up a bunch of requests to be sent synchronously - for(var i=0; i<10; i++){ - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello'+i - } - ); - } - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - - console.log(ipc.of.world.destroy); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/basicSync/world-server.js b/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/basicSync/world-server.js deleted file mode 100644 index c76e1bb6f..000000000 --- a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/basicSync/world-server.js +++ /dev/null @@ -1,39 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.sync= true; - -ipc.serve( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - setTimeout( - function(){ - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - }, - 2000 - ); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/hello-client.js b/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/hello-client.js deleted file mode 100644 index 9c7042a90..000000000 --- a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/hello-client.js +++ /dev/null @@ -1,35 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'hello' - ); - } - ); - - ipc.of.world.on( - 'data', - function(data){ - ipc.log('got a message from world : ', data,data.toString()); - } - ); - } -); diff --git a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/world.server.js b/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/world.server.js deleted file mode 100644 index c3ed83c9a..000000000 --- a/TaskManager/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/world.server.js +++ /dev/null @@ -1,40 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.serve( - function(){ - ipc.server.on( - 'connect', - function(socket){ - ipc.server.emit( - socket, - 'hello' - ); - } - ); - - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data,data.toString()); - ipc.server.emit( - socket, - 'goodbye' - ); - } - ); - } -); - -ipc.server.start(); diff --git a/TaskManager/node_modules/node-ipc/node-ipc.js b/TaskManager/node_modules/node-ipc/node-ipc.js deleted file mode 100644 index 1c6336061..000000000 --- a/TaskManager/node_modules/node-ipc/node-ipc.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -const IPC = require('./services/IPC.js'); - -class IPCModule extends IPC{ - constructor(){ - super(); - //include IPC to make extensible - Object.defineProperty( - this, - 'IPC', - { - enumerable:true, - writable:false, - value:IPC - } - ) - } -} - -module.exports=new IPCModule; diff --git a/TaskManager/node_modules/node-ipc/package.json b/TaskManager/node_modules/node-ipc/package.json deleted file mode 100644 index 4a7634127..000000000 --- a/TaskManager/node_modules/node-ipc/package.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "_from": "node-ipc", - "_id": "node-ipc@9.1.1", - "_inBundle": false, - "_integrity": "sha512-FAyICv0sIRJxVp3GW5fzgaf9jwwRQxAKDJlmNFUL5hOy+W4X/I5AypyHoq0DXXbo9o/gt79gj++4cMr4jVWE/w==", - "_location": "/node-ipc", - "_phantomChildren": {}, - "_requested": { - "type": "tag", - "registry": true, - "raw": "node-ipc", - "name": "node-ipc", - "escapedName": "node-ipc", - "rawSpec": "", - "saveSpec": null, - "fetchSpec": "latest" - }, - "_requiredBy": [ - "#USER", - "/" - ], - "_resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.1.1.tgz", - "_shasum": "4e245ed6938e65100e595ebc5dc34b16e8dd5d69", - "_spec": "node-ipc", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskManager", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/node-ipc/issues" - }, - "bundleDependencies": false, - "dependencies": { - "event-pubsub": "4.3.0", - "js-message": "1.0.5", - "js-queue": "2.0.0" - }, - "deprecated": false, - "description": "A nodejs module for local and remote Inter Process Communication (IPC), Neural Networking, and able to facilitate machine learning.", - "devDependencies": { - "codacy-coverage": "2.0.0", - "istanbul": "0.4.1", - "jasmine": "2.4.1", - "node-cmd": "2.0.0" - }, - "directories": { - "example": "example" - }, - "engines": { - "node": ">=4.0.0" - }, - "homepage": "http://riaevangelist.github.io/node-ipc/", - "keywords": [ - "IPC", - "Neural Networking", - "Machine Learning", - "inter", - "process", - "communication", - "unix", - "windows", - "win", - "socket", - "TCP", - "UDP", - "domain", - "sockets", - "threaded", - "communication", - "multi", - "process", - "shared", - "memory" - ], - "license": "DBAD", - "main": "node-ipc.js", - "name": "node-ipc", - "pre-commit": [ - "cover" - ], - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/node-ipc.git" - }, - "scripts": { - "cover": "istanbul cover -x **/spec/** -dir ./spec/coverage jasmine", - "coverup": "cat ./spec/coverage/lcov.info | codacy-coverage", - "test": "istanbul cover -x **/spec/** -dir ./spec/coverage jasmine", - "test-windows": "istanbul cover -x **/spec/** -dir ./spec/coverage ./node_modules/jasmine/bin/jasmine.js" - }, - "version": "9.1.1" -} diff --git a/TaskManager/node_modules/node-ipc/services/IPC.js b/TaskManager/node_modules/node-ipc/services/IPC.js deleted file mode 100644 index 3a6edc7f5..000000000 --- a/TaskManager/node_modules/node-ipc/services/IPC.js +++ /dev/null @@ -1,337 +0,0 @@ -'use strict'; - -const Defaults = require('../entities/Defaults.js'), - Client = require('../dao/client.js'), - Server = require('../dao/socketServer.js'), - util = require('util'); - -class IPC{ - constructor(){ - Object.defineProperties( - this, - { - config : { - enumerable:true, - writable:true, - value:new Defaults - }, - connectTo : { - enumerable:true, - writable:false, - value:connect - }, - connectToNet: { - enumerable:true, - writable:false, - value:connectNet - }, - disconnect : { - enumerable:true, - writable:false, - value:disconnect - }, - serve : { - enumerable:true, - writable:false, - value:serve - }, - serveNet : { - enumerable:true, - writable:false, - value:serveNet - }, - of : { - enumerable:true, - writable:true, - value:{} - }, - server : { - enumerable:true, - writable:true, - configurable:true, - value:false - }, - log : { - enumerable:true, - writable:false, - value:log - } - } - ); - } -} - -function log(...args){ - if(this.config.silent){ - return; - } - - for(let i=0, count=args.length; i server -> runTask -> Entering function.') - - if (message.event === undefined) { - console.log('[WARN] Task Manager -> server -> runTask -> Message Received Without Event -> message = ' + JSON.stringify(message)) - return - } - - if (message.event.taskId === undefined) { - console.log('[WARN] Task Manager -> server -> runTask -> Message Received Without taskId -> message = ' + JSON.stringify(message)) - return - } - - if (message.event.definition === undefined) { - console.log('[WARN] Task Manager -> server -> runTask -> Message Received Without Definition -> message = ' + JSON.stringify(message)) - return - } - - if (tasks.get(message.event.taskId) !== undefined) { - //console.log('[WARN] Task Manager -> server -> runTask -> Task Already Running -> taskId = ' + message.event.taskId) - return - } - //console.log('[INFO] Task Manager -> server -> runTask -> Task Name = ' + message.event.taskName) - //console.log('[INFO] Task Manager -> server -> runTask -> Task Id = ' + message.event.taskId) - - let path = process.env.TASK_SERVER_PATH + '/server.js' - - /* Workarround to avoid having the same debug port at the forked process which makes it crash. */ - for (let i = 0; i < process.execArgv.length; i++) { - let argument = process.execArgv[i] - if (argument.indexOf('--inspect') > -1) { - process.execArgv[i] = '' - } - } - - /* Forking this process. */ - let task = { - childProcess: fork(path, [message.event.taskId], { stdio: 'inherit' }), - id: message.event.taskId, - name: message.event.taskName - } - - tasks.set(message.event.taskId, task) - - task.childProcess.on('error', (err) => { - console.log('[ERROR] Task Manager -> server -> runTask -> Problem with Task Name = ' + task.name) - console.log('[ERROR] Task Manager -> server -> runTask -> Problem with Task Id = ' + task.id) - console.log(`[ERROR] Task Manager -> server -> runTask -> Task Manager exited with error ${err}`) - }) - task.childProcess.on('close', (code, signal) => { - //console.log('[INFO] Task Manager -> server -> runTask -> Task Terminated. -> Task Name = ' + task.name) - //console.log('[INFO] Task Manager -> server -> runTask -> Task Terminated. -> Task Id = ' + task.id) - tasks.delete(task.id) - }) - - global.SYSTEM_EVENT_HANDLER.listenToEvent('Task Manager - ' + message.event.taskId, 'Nodejs Process Ready for Task', undefined, undefined, undefined, sendStartingEvent) - - function sendStartingEvent() { - //console.log('[INFO] Task Manager -> server -> runTask -> Emitting Event -> key = ' + 'Task Server - ' + task.id) - global.SYSTEM_EVENT_HANDLER.raiseEvent('Task Server - ' + task.id, 'Run Task', message.event) - } -} - -function stopTask(message) { - - //console.log('[INFO] Task Manager -> server -> stopTask -> Entering function.') - - if (message.event === undefined) { - console.log('[WARN] Task Manager -> server -> stopTask -> Message Received Without Event -> message = ' + JSON.stringify(message)) - return - } - - if (message.event.taskId === undefined) { - console.log('[WARN] Task Manager -> server -> stopTask -> Message Received Without taskId -> message = ' + JSON.stringify(message)) - return - } - - //console.log('[INFO] Task Manager -> server -> stopTask -> Task Name = ' + message.event.taskName) - //console.log('[INFO] Task Manager -> server -> stopTask -> Task Id = ' + message.event.taskId) - - let task = tasks.get(message.event.taskId) - - if (task) { - task.childProcess.send('Stop this Task'); - //console.log('[INFO] Task Manager -> server -> stopTask -> Child Process instructed to finish.') - } else { - console.log('[WARN] Task Manager -> server -> stopTask -> Cannot delete Task that does not exist.') - } -} \ No newline at end of file diff --git a/TaskServer/.env b/TaskServer/.env index 4bc79e391..471650a5a 100644 --- a/TaskServer/.env +++ b/TaskServer/.env @@ -8,3 +8,5 @@ WRITE_LOGS_TO_FILES=true BOTS_PATH=../Legacy-Code LOG_PATH=../Log-Files +WEB_SOCKETS_SERVER_PORT=8080 + diff --git a/TaskServer/SystemEventHandler.js b/TaskServer/EventServerClient.js similarity index 57% rename from TaskServer/SystemEventHandler.js rename to TaskServer/EventServerClient.js index 6071dbfea..5f275996b 100644 --- a/TaskServer/SystemEventHandler.js +++ b/TaskServer/EventServerClient.js @@ -1,6 +1,8 @@ -exports.newSystemEventHandler = function newSystemEventHandler(ipc) { +exports.newEventsServerClient = function newEventsServerClient() { - const MODULE = "Task Server -> System Event Handler -> " + const MODULE = "Task Server " + const ERROR_LOG = true + const INFO_LOG = false let thisObject = { initialize: initialize, @@ -15,74 +17,72 @@ let eventListeners = new Map() let responseWaiters = new Map() - ipc.config.id = 'Task Server'; - ipc.config.retry = 1500; - ipc.config.silent = true; + let WEB_SOCKETS_CLIENT + const WEB_SOCKET = require('ws') + let port = process.env.WEB_SOCKETS_SERVER_PORT return thisObject - function initialize(canllerName, callBackFunction) { + function initialize(callBackFunction) { - ipc.connectTo( - 'world', - function () { - ipc.of.world.on( - 'connect', - function () { - ipc.log(MODULE + '## Connected to Superalgos Event Server ##'.rainbow, ipc.config.delay); + setuptWebSockets(callBackFunction) - let eventCommand = { - action: 'greetings', - from: canllerName - } + } - sendCommand(eventCommand) + function setuptWebSockets(callBackFunction) { + try { - callBackFunction() - } - ); - ipc.of.world.on( - 'disconnect', - function () { - ipc.log(MODULE + 'Disconnected from Superalgos Event Server '.notice); - } - ); - ipc.of.world.on( - 'message', // here is where all incomming messages are processed. - function (data) { - ipc.log('Got a message from Superalgos Event Server: '.debug, data); - - let message = JSON.parse(data) + WEB_SOCKETS_CLIENT = new WEB_SOCKET('ws://localhost:' + port ) - if (message.action === 'Event Raised') { - - let key - if (message.callerId) { - key = message.eventHandlerName + '-' + message.eventType + '-' + message.callerId - } else { - key = message.eventHandlerName + '-' + message.eventType - } - let handler = eventListeners.get(key) - if (handler) { - handler.callBack(message) - } else { - console.log(MODULE + key + ' not found so could not deliver event raised.') - console.log(MODULE + ' Message = ' + data) - } - return - } - - if (message.action === 'Event Server Response') { - let handler = responseWaiters.get(message.callerId) - if (handler) { - handler(message) - } - return - } - } - ); + WEB_SOCKETS_CLIENT.onerror = error => { + console.log('[ERROR] Task Server -> Event Server Client -> setuptWebSockets -> On connection error -> error = ' + JSON.stringify(error)) } - ); + WEB_SOCKETS_CLIENT.onopen = () => { + if (INFO_LOG === true) { + console.log('Websocket connection opened.') + } + + if (callBackFunction !== undefined) { + callBackFunction() + } + } + WEB_SOCKETS_CLIENT.onmessage = e => { + + try { + if (INFO_LOG === true) { + console.log('Websocket Message Received: ' + e.data) + } + + let message = JSON.parse(e.data) + + if (message.action === 'Event Raised') { + let key + if (message.callerId !== undefined) { + key = message.eventHandlerName + '-' + message.eventType + '-' + message.callerId + } else { + key = message.eventHandlerName + '-' + message.eventType + } + let handler = eventListeners.get(key) + if (handler) { + handler.callBack(message) + } + return + } + + if (message.action === 'Event Server Response') { + let handler = responseWaiters.get(message.callerId) + if (handler) { + handler(message) + } + return + } + } catch (err) { + if (ERROR_LOG === true) { logger.write('[ERROR] Task Server -> Event Server Client -> setuptWebSockets -> onmessage -> err = ' + err.stack) } + } + } + } catch (err) { + if (ERROR_LOG === true) { logger.write('[ERROR] Task Server -> Event Server Client -> setuptWebSockets -> err = ' + err.stack) } + } } function finalize() { @@ -98,7 +98,7 @@ } sendCommand(eventCommand) } - ipc.disconnect('world'); + WEB_SOCKETS_CLIENT.close(); } function sendCommand(command, responseCallBack, eventsCallBack) { @@ -122,10 +122,11 @@ responseWaiters.set(command.callerId, responseCallBack) } - ipc.of.world.emit( - 'message', - JSON.stringify(command) - ) + if (WEB_SOCKETS_CLIENT.readyState === 1) { // 1 means connected and ready. + WEB_SOCKETS_CLIENT.send("Task Server||" + JSON.stringify(command)) + } else { + console.log('[ERROR] Task Server -> Event Server Client -> setuptWebSockets -> sendCommand -> WebSocket message could not be sent because the connection was not ready. Message = ' + JSON.stringify(command)) + } } function createEventHandler(eventHandlerName, callerId, responseCallBack) { diff --git a/TaskServer/IndicatorBotProcessMainLoop.js b/TaskServer/IndicatorBotProcessMainLoop.js index a99c9e97b..d24bf9bf9 100644 --- a/TaskServer/IndicatorBotProcessMainLoop.js +++ b/TaskServer/IndicatorBotProcessMainLoop.js @@ -1088,11 +1088,11 @@ percentage: percentage, status: status } - global.SYSTEM_EVENT_HANDLER.raiseEvent(bot.processKey, 'Heartbeat', event) + global.EVENT_SERVER_CLIENT.raiseEvent(bot.processKey, 'Heartbeat', event) } function processStopped() { - global.SYSTEM_EVENT_HANDLER.raiseEvent(bot.processKey, 'Stopped') + global.EVENT_SERVER_CLIENT.raiseEvent(bot.processKey, 'Stopped') } } catch (err) { diff --git a/TaskServer/MultiPeriod.js b/TaskServer/MultiPeriod.js index 09d54057a..67ed3d365 100644 --- a/TaskServer/MultiPeriod.js +++ b/TaskServer/MultiPeriod.js @@ -1009,7 +1009,7 @@ dateRange: dataRange } - global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Data Range Updated', event) + global.EVENT_SERVER_CLIENT.raiseEvent(key, 'Data Range Updated', event) callBack(global.DEFAULT_OK_RESPONSE); } diff --git a/TaskServer/MultiPeriodDaily.js b/TaskServer/MultiPeriodDaily.js index 516737d4c..01850e771 100644 --- a/TaskServer/MultiPeriodDaily.js +++ b/TaskServer/MultiPeriodDaily.js @@ -787,7 +787,7 @@ dateRange: dataRange } - global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Data Range Updated', event) + global.EVENT_SERVER_CLIENT.raiseEvent(key, 'Data Range Updated', event) callBack(global.DEFAULT_OK_RESPONSE); } diff --git a/TaskServer/ProcessExecutionEvents.js b/TaskServer/ProcessExecutionEvents.js index 72741eba4..18ff8a70b 100644 --- a/TaskServer/ProcessExecutionEvents.js +++ b/TaskServer/ProcessExecutionEvents.js @@ -81,7 +81,7 @@ if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] start -> waitForDependantProcess -> key = " + key); } if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] start -> waitForDependantProcess -> callerId = " + callerId); } - global.SYSTEM_EVENT_HANDLER.listenToEvent(key, 'Process Execution Finished', undefined, callerId, responseCallBack, eventsCallBack) + global.EVENT_SERVER_CLIENT.listenToEvent(key, 'Process Execution Finished', undefined, callerId, responseCallBack, eventsCallBack) bot.processHeartBeat(undefined, undefined, "Waiting for " + processThisDependsOn.parentNode.parentNode.name + "->" + processThisDependsOn.parentNode.code.codeName + "->" + processThisDependsOn.code.codeName) @@ -102,15 +102,15 @@ /* We continue the normal flow after we learn the dependent process has finished its execution. */ if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] start -> eventsCallBack -> stopListening to Process Execution Finished. "); } if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] start -> eventsCallBack -> subscriptionId = " + subscriptionId); } - global.SYSTEM_EVENT_HANDLER.stopListening(key, 'Process Execution Finished', subscriptionId) + global.EVENT_SERVER_CLIENT.stopListening(key, 'Process Execution Finished', subscriptionId) if (message.event.err.result === global.DEFAULT_OK_RESPONSE.result) { /* We emit our own event that the process started. */ let event = { err: global.DEFAULT_OK_RESPONSE } - global.SYSTEM_EVENT_HANDLER.createEventHandler(currentProcessKey, 'Process Execution Started') - global.SYSTEM_EVENT_HANDLER.raiseEvent(currentProcessKey, 'Process Execution Started', event) + global.EVENT_SERVER_CLIENT.createEventHandler(currentProcessKey, 'Process Execution Started') + global.EVENT_SERVER_CLIENT.raiseEvent(currentProcessKey, 'Process Execution Started', event) bot.processHeartBeat(undefined, undefined,"Running...") @@ -125,8 +125,8 @@ let event = { err: global.DEFAULT_OK_RESPONSE } - global.SYSTEM_EVENT_HANDLER.createEventHandler(currentProcessKey, 'Process Execution Started') - global.SYSTEM_EVENT_HANDLER.raiseEvent(currentProcessKey, 'Process Execution Started', event) + global.EVENT_SERVER_CLIENT.createEventHandler(currentProcessKey, 'Process Execution Started') + global.EVENT_SERVER_CLIENT.raiseEvent(currentProcessKey, 'Process Execution Started', event) if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] start -> " + currentProcessKey + " Process Execution Started " ); } @@ -149,8 +149,8 @@ err: global.DEFAULT_OK_RESPONSE } - global.SYSTEM_EVENT_HANDLER.createEventHandler(currentProcessKey, 'Process Execution Finished') - global.SYSTEM_EVENT_HANDLER.raiseEvent(currentProcessKey, 'Process Execution Finished', event) + global.EVENT_SERVER_CLIENT.createEventHandler(currentProcessKey, 'Process Execution Finished') + global.EVENT_SERVER_CLIENT.raiseEvent(currentProcessKey, 'Process Execution Finished', event) if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] finish -> " + currentProcessKey + " Process Execution Finished " ); } diff --git a/TaskServer/ProcessOutput.js b/TaskServer/ProcessOutput.js index 4d2369ece..7bbdfff10 100644 --- a/TaskServer/ProcessOutput.js +++ b/TaskServer/ProcessOutput.js @@ -85,8 +85,8 @@ let event = { lastFile: lastFile } - global.SYSTEM_EVENT_HANDLER.createEventHandler(key, 'Dataset Updated') - global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Dataset Updated', event) + global.EVENT_SERVER_CLIENT.createEventHandler(key, 'Dataset Updated') + global.EVENT_SERVER_CLIENT.raiseEvent(key, 'Dataset Updated', event) } } diff --git a/TaskServer/SensorBotProcessMainLoop.js b/TaskServer/SensorBotProcessMainLoop.js index f73961f20..dbcc04b3f 100644 --- a/TaskServer/SensorBotProcessMainLoop.js +++ b/TaskServer/SensorBotProcessMainLoop.js @@ -810,11 +810,11 @@ percentage: percentage, status: status } - global.SYSTEM_EVENT_HANDLER.raiseEvent(bot.processKey, 'Heartbeat', event) + global.EVENT_SERVER_CLIENT.raiseEvent(bot.processKey, 'Heartbeat', event) } function processStopped() { - global.SYSTEM_EVENT_HANDLER.raiseEvent(bot.processKey, 'Stopped') + global.EVENT_SERVER_CLIENT.raiseEvent(bot.processKey, 'Stopped') } } diff --git a/TaskServer/Session.js b/TaskServer/Session.js index 0d6685f89..1a15af6d8 100644 --- a/TaskServer/Session.js +++ b/TaskServer/Session.js @@ -38,8 +38,8 @@ /* Listen to event to start or stop the session. */ bot.sessionKey = bot.processNode.session.name + '-' + bot.processNode.session.type + '-' + bot.processNode.session.id - global.SYSTEM_EVENT_HANDLER.listenToEvent(bot.sessionKey, 'Run Session', undefined, undefined, undefined, runSession) - global.SYSTEM_EVENT_HANDLER.listenToEvent(bot.sessionKey, 'Stop Session', undefined, undefined, undefined, stopSession) + global.EVENT_SERVER_CLIENT.listenToEvent(bot.sessionKey, 'Run Session', undefined, undefined, undefined, runSession) + global.EVENT_SERVER_CLIENT.listenToEvent(bot.sessionKey, 'Stop Session', undefined, undefined, undefined, stopSession) callBackFunction(global.DEFAULT_OK_RESPONSE) return diff --git a/TaskServer/TradingBotProcessMainLoop.js b/TaskServer/TradingBotProcessMainLoop.js index 3820e6d33..81fb60613 100644 --- a/TaskServer/TradingBotProcessMainLoop.js +++ b/TaskServer/TradingBotProcessMainLoop.js @@ -164,12 +164,12 @@ /* Checking if we need to need to emit any event */ if (bot.SESSION_STATUS === 'Idle' && bot.STOP_SESSION === false) { - global.SYSTEM_EVENT_HANDLER.raiseEvent(bot.sessionKey, 'Running') + global.EVENT_SERVER_CLIENT.raiseEvent(bot.sessionKey, 'Running') bot.SESSION_STATUS = 'Running' } if (bot.SESSION_STATUS === 'Running' && bot.STOP_SESSION === true) { - global.SYSTEM_EVENT_HANDLER.raiseEvent(bot.sessionKey, 'Stopped') + global.EVENT_SERVER_CLIENT.raiseEvent(bot.sessionKey, 'Stopped') bot.SESSION_STATUS = 'Stopped' } @@ -880,7 +880,7 @@ logger.persist(); } - global.SYSTEM_EVENT_HANDLER.raiseEvent(bot.sessionKey, 'Stopped') + global.EVENT_SERVER_CLIENT.raiseEvent(bot.sessionKey, 'Stopped') processStopped() callBackFunction(global.DEFAULT_OK_RESPONSE); return; @@ -1013,7 +1013,7 @@ percentage: percentage, status: status } - global.SYSTEM_EVENT_HANDLER.raiseEvent(bot.processKey, 'Heartbeat', event) + global.EVENT_SERVER_CLIENT.raiseEvent(bot.processKey, 'Heartbeat', event) } function sessionHeartBeat(processingDate) { @@ -1021,7 +1021,7 @@ seconds: (new Date()).getSeconds(), processingDate: processingDate } - global.SYSTEM_EVENT_HANDLER.raiseEvent(bot.sessionKey, 'Heartbeat', event) + global.EVENT_SERVER_CLIENT.raiseEvent(bot.sessionKey, 'Heartbeat', event) if (global.STOP_TASK_GRACEFULLY === true) { bot.STOP_SESSION = true @@ -1029,12 +1029,12 @@ } function processStopped() { - global.SYSTEM_EVENT_HANDLER.raiseEvent(bot.processKey, 'Stopped') + global.EVENT_SERVER_CLIENT.raiseEvent(bot.processKey, 'Stopped') } function sessionStopped() { if (bot.SESSION_STATUS === 'Running') { - global.SYSTEM_EVENT_HANDLER.raiseEvent(bot.sessionKey, 'Stopped') + global.EVENT_SERVER_CLIENT.raiseEvent(bot.sessionKey, 'Stopped') bot.SESSION_STATUS = 'Stopped' } } diff --git a/TaskServer/node_modules/@types/node/package.json b/TaskServer/node_modules/@types/node/package.json deleted file mode 100644 index 695ce2c04..000000000 --- a/TaskServer/node_modules/@types/node/package.json +++ /dev/null @@ -1,220 +0,0 @@ -{ - "_from": "@types/node@^13.1.0", - "_id": "@types/node@13.7.0", - "_inBundle": false, - "_integrity": "sha512-GnZbirvmqZUzMgkFn70c74OQpTTUcCzlhQliTzYjQMqg+hVKcDnxdL19Ne3UdYzdMA/+W3eb646FWn/ZaT1NfQ==", - "_location": "/@types/node", - "_phantomChildren": {}, - "_requested": { - "type": "range", - "registry": true, - "raw": "@types/node@^13.1.0", - "name": "@types/node", - "escapedName": "@types%2fnode", - "scope": "@types", - "rawSpec": "^13.1.0", - "saveSpec": null, - "fetchSpec": "^13.1.0" - }, - "_requiredBy": [ - "/telegraf" - ], - "_resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.0.tgz", - "_shasum": "b417deda18cf8400f278733499ad5547ed1abec4", - "_spec": "@types/node@^13.1.0", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer\\node_modules\\telegraf", - "bugs": { - "url": "https://github.com/DefinitelyTyped/DefinitelyTyped/issues" - }, - "bundleDependencies": false, - "contributors": [ - { - "name": "Microsoft TypeScript", - "url": "https://github.com/Microsoft" - }, - { - "name": "DefinitelyTyped", - "url": "https://github.com/DefinitelyTyped" - }, - { - "name": "Alberto Schiabel", - "url": "https://github.com/jkomyno" - }, - { - "name": "Alexander T.", - "url": "https://github.com/a-tarasyuk" - }, - { - "name": "Alvis HT Tang", - "url": "https://github.com/alvis" - }, - { - "name": "Andrew Makarov", - "url": "https://github.com/r3nya" - }, - { - "name": "Benjamin Toueg", - "url": "https://github.com/btoueg" - }, - { - "name": "Bruno Scheufler", - "url": "https://github.com/brunoscheufler" - }, - { - "name": "Chigozirim C.", - "url": "https://github.com/smac89" - }, - { - "name": "Christian Vaagland Tellnes", - "url": "https://github.com/tellnes" - }, - { - "name": "David Junger", - "url": "https://github.com/touffy" - }, - { - "name": "Deividas Bakanas", - "url": "https://github.com/DeividasBakanas" - }, - { - "name": "Eugene Y. Q. Shen", - "url": "https://github.com/eyqs" - }, - { - "name": "Flarna", - "url": "https://github.com/Flarna" - }, - { - "name": "Hannes Magnusson", - "url": "https://github.com/Hannes-Magnusson-CK" - }, - { - "name": "Hoàng Văn Khải", - "url": "https://github.com/KSXGitHub" - }, - { - "name": "Huw", - "url": "https://github.com/hoo29" - }, - { - "name": "Kelvin Jin", - "url": "https://github.com/kjin" - }, - { - "name": "Klaus Meinhardt", - "url": "https://github.com/ajafff" - }, - { - "name": "Lishude", - "url": "https://github.com/islishude" - }, - { - "name": "Mariusz Wiktorczyk", - "url": "https://github.com/mwiktorczyk" - }, - { - "name": "Mohsen Azimi", - "url": "https://github.com/mohsen1" - }, - { - "name": "Nicolas Even", - "url": "https://github.com/n-e" - }, - { - "name": "Nicolas Voigt", - "url": "https://github.com/octo-sniffle" - }, - { - "name": "Nikita Galkin", - "url": "https://github.com/galkin" - }, - { - "name": "Parambir Singh", - "url": "https://github.com/parambirs" - }, - { - "name": "Sebastian Silbermann", - "url": "https://github.com/eps1lon" - }, - { - "name": "Simon Schick", - "url": "https://github.com/SimonSchick" - }, - { - "name": "Thomas den Hollander", - "url": "https://github.com/ThomasdenH" - }, - { - "name": "Wilco Bakker", - "url": "https://github.com/WilcoBakker" - }, - { - "name": "wwwy3y3", - "url": "https://github.com/wwwy3y3" - }, - { - "name": "Zane Hannan AU", - "url": "https://github.com/ZaneHannanAU" - }, - { - "name": "Samuel Ainsworth", - "url": "https://github.com/samuela" - }, - { - "name": "Kyle Uehlein", - "url": "https://github.com/kuehlein" - }, - { - "name": "Jordi Oliveras Rovira", - "url": "https://github.com/j-oliveras" - }, - { - "name": "Thanik Bhongbhibhat", - "url": "https://github.com/bhongy" - }, - { - "name": "Marcin Kopacz", - "url": "https://github.com/chyzwar" - }, - { - "name": "Trivikram Kamat", - "url": "https://github.com/trivikr" - }, - { - "name": "Minh Son Nguyen", - "url": "https://github.com/nguymin4" - }, - { - "name": "Junxiao Shi", - "url": "https://github.com/yoursunny" - }, - { - "name": "Ilia Baryshnikov", - "url": "https://github.com/qwelias" - } - ], - "dependencies": {}, - "deprecated": false, - "description": "TypeScript definitions for Node.js", - "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped#readme", - "license": "MIT", - "main": "", - "name": "@types/node", - "repository": { - "type": "git", - "url": "git+https://github.com/DefinitelyTyped/DefinitelyTyped.git", - "directory": "types/node" - }, - "scripts": {}, - "typeScriptVersion": "2.8", - "types": "index.d.ts", - "typesPublisherContentHash": "b0cd8dccd6d2eca8bb1de5a05bebf13796984567eb809f63164972122c4ddbaf", - "typesVersions": { - ">=3.5.0-0": { - "*": [ - "ts3.5/*" - ] - } - }, - "version": "13.7.0" -} diff --git a/TaskServer/node_modules/ccxt/build/cleanup-old-tags.js b/TaskServer/node_modules/ccxt/build/cleanup-old-tags.js index d807ab18a..d304afd1d 100644 --- a/TaskServer/node_modules/ccxt/build/cleanup-old-tags.js +++ b/TaskServer/node_modules/ccxt/build/cleanup-old-tags.js @@ -26,9 +26,9 @@ function cleanupOldTags () { const tagsByMajorMinor = values (groupBy (tags, 'key')).sort ((a, b) => a[0].key - b[0].key) - // Preserve all tags for first 3 minor versions + // Preserve all tags for first 5 minor versions - for (let i = 0; i < 3; i++) { + for (let i = 0; i < 5; i++) { const tags = tagsByMajorMinor.pop () diff --git a/TaskServer/node_modules/ccxt/build/export-exchanges.js b/TaskServer/node_modules/ccxt/build/export-exchanges.js index cee147922..6ed8fd0cd 100644 --- a/TaskServer/node_modules/ccxt/build/export-exchanges.js +++ b/TaskServer/node_modules/ccxt/build/export-exchanges.js @@ -93,49 +93,51 @@ function createExchanges (ids) { // ---------------------------------------------------------------------------- // TODO: REWRITE THIS ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ -function exportSupportedAndCertifiedExchanges (exchanges, wikiPath) { +function exportSupportedAndCertifiedExchanges (exchanges, { allExchangesPaths, certifiedExchangesPaths, exchangesByCountriesPaths, proExchangesPaths }) { // ............................................................................ // markup constants and helper functions const countryName = (code) => countries[code] || code - const ccxtCertifiedBadge = '[![CCXT Certified](https://img.shields.io/badge/CCXT-certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification)' + const ccxtCertifiedBadge = '[![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification)' + const ccxtProBadge = '[![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro)' const logoHeading = ' '.repeat (7) + 'logo' + ' '.repeat (7) - const tableHeadings = [ logoHeading, 'id', 'name', 'ver', 'doc', 'certified', ] - const exchangesByCountryHeading = [ 'country / region', ... tableHeadings ] + const tableHeadings = [ logoHeading, 'id', 'name', 'ver', 'doc', 'certified', 'pro' ] + const exchangesByCountryHeading = [ 'country / region', ... tableHeadings.slice (0, 5) ] // ---------------------------------------------------------------------------- // list all supported exchanges - const exchangesNotListedInDocs = [] + const exchangesNotListedInDocs = [ 'hitbtc2' ] - let tableData = values (exchanges) - .filter (exchange => !exchangesNotListedInDocs.includes (exchange.id)) - .map (exchange => { - let logo = exchange.urls['logo'] - let website = Array.isArray (exchange.urls.www) ? exchange.urls.www[0] : exchange.urls.www - let url = exchange.urls.referral || website - let countries = Array.isArray (exchange.countries) ? exchange.countries.map (countryName).join (', ') : countryName (exchange.countries) - let doc = Array.isArray (exchange.urls.doc) ? exchange.urls.doc[0] : exchange.urls.doc - let version = exchange.version ? exchange.version : '\*' - let matches = version.match (/[^0-9]*([0-9].*)/) - if (matches) { - version = matches[1]; - } - return [ - '[![' + exchange.id + '](' + logo + ')](' + url + ')', - exchange.id, - '[' + exchange.name + '](' + url + ')', - version, - '[API](' + doc + ')', - exchange.certified ? ccxtCertifiedBadge : '', - countries, - ] - }) + function makeTableData (exchanges) { + return ( + values (exchanges) + .filter (exchange => !exchangesNotListedInDocs.includes (exchange.id)) + .map (exchange => { + let logo = exchange.urls['logo'] + let website = Array.isArray (exchange.urls.www) ? exchange.urls.www[0] : exchange.urls.www + let url = exchange.urls.referral || website + let doc = Array.isArray (exchange.urls.doc) ? exchange.urls.doc[0] : exchange.urls.doc + let version = exchange.version ? exchange.version : '\*' + let matches = version.match (/[^0-9]*([0-9].*)/) + if (matches) { + version = matches[1]; + } + return [ + '[![' + exchange.id + '](' + logo + ')](' + url + ')', + exchange.id, + '[' + exchange.name + '](' + url + ')', + version, + '[API](' + doc + ')', + exchange.certified ? ccxtCertifiedBadge : '', + exchange.pro ? ccxtProBadge : '', + ] + }) + ) + } - // prepend the table header - tableData.splice (0, 0, tableHeadings) function makeTable (jsonArray) { let table = asTable.configure ({ 'delimiter': ' | ' }) (jsonArray) @@ -148,88 +150,128 @@ function exportSupportedAndCertifiedExchanges (exchanges, wikiPath) { return lines.map (line => '|' + line + '|').join ("\n") } - const exchangesTable = makeTable (tableData) - const numExchanges = keys (exchanges).length - const beginning = "The ccxt library currently supports the following " - const ending = " cryptocurrency exchange markets and trading APIs:\n\n" - const totalString = beginning + numExchanges + ending - const allExchanges = totalString + exchangesTable + "$1" - const allExchangesRegex = new RegExp ("[^\n]+[\n]{2}\\|[^`]+\\|([\n][\n]|[\n]$|$)", 'm') - logExportExchanges ('README.md', allExchangesRegex, allExchanges) - logExportExchanges (wikiPath + '/Manual.md', allExchangesRegex, allExchanges) - logExportExchanges (wikiPath + '/Exchange-Markets.md', allExchangesRegex, allExchanges) + if (allExchangesPaths) { - const certifiedFieldIndex = tableHeadings.indexOf ('certified') - const certified = tableData.filter ((x) => x[certifiedFieldIndex] !== '' ) - const certifiedExchangesRegex = new RegExp ("^(## Certified Cryptocurrency Exchanges\n{3})(?:\\|.+\\|$\n)+", 'm') - const certifiedExchangesTable = makeTable (certified) - const certifiedExchanges = '$1' + certifiedExchangesTable + "\n" - logExportExchanges ('README.md', certifiedExchangesRegex, certifiedExchanges) + const tableData = makeTableData (exchanges) + const numExchanges = tableData.length + // prepend the table header + tableData.splice (0, 0, tableHeadings) + const exchangesTable = makeTable (tableData) + const beginning = "The CCXT library currently supports the following " + const ending = " cryptocurrency exchange markets and trading APIs:\n\n" + const totalString = beginning + numExchanges + ending + const allExchanges = totalString + exchangesTable + "$1" + const allExchangesRegex = new RegExp ("[^\n]+[\n]{2}\\|[^`]+\\|([\n][\n]|[\n]$|$)", 'm') + for (const path of allExchangesPaths) { + logExportExchanges (path, allExchangesRegex, allExchanges) + } - let exchangesByCountries = [] - keys (countries).forEach (code => { - let country = countries[code] - let result = [] - keys (exchanges).forEach (id => { - let exchange = exchanges[id] - let logo = exchange.urls['logo'] - let website = Array.isArray (exchange.urls.www) ? exchange.urls.www[0] : exchange.urls.www - let url = exchange.urls.referral || website - let doc = Array.isArray (exchange.urls.doc) ? exchange.urls.doc[0] : exchange.urls.doc - let version = exchange.version ? exchange.version : '\*' - let matches = version.match (/[^0-9]*([0-9].*)/) - if (matches) - version = matches[1]; - let shouldInclude = false - if (Array.isArray (exchange.countries)) { - if (exchange.countries.indexOf (code) > -1) - shouldInclude = true + // logExportExchanges ('README.md', allExchangesRegex, allExchanges) + // logExportExchanges (wikiPath + '/Manual.md', allExchangesRegex, allExchanges) + // logExportExchanges (wikiPath + '/Exchange-Markets.md', allExchangesRegex, allExchanges) + } + + if (proExchangesPaths) { + const pro = values (exchanges).filter (exchange => exchange.pro) + const tableData = makeTableData (pro) + const numExchanges = tableData.length + // prepend the table header + tableData.splice (0, 0, tableHeadings) + const exchangesTable = makeTable (tableData) + const beginning = "The CCXT Pro library currently supports the following " + const ending = " cryptocurrency exchange markets and WebSocket trading APIs:\n\n" + const totalString = beginning + numExchanges + ending + const proExchanges = totalString + exchangesTable + "$1" + const proExchangesRegex = new RegExp ("[^\n]+[\n]{2}\\|[^`]+\\|([\n][\n]|[\n]$|$)", 'm') + + for (const path of proExchangesPaths) { + logExportExchanges (path, proExchangesRegex, proExchanges) + } + } + + if (certifiedExchangesPaths) { + const certified = values (exchanges).filter (exchange => exchange.certified) + const tableData = makeTableData (certified) + // prepend the table header + tableData.splice (0, 0, tableHeadings) + const certifiedExchangesRegex = new RegExp ("^(## Certified Cryptocurrency Exchanges\n{3})(?:\\|.+\\|$\n)+", 'm') + const certifiedExchangesTable = makeTable (tableData) + const certifiedExchanges = '$1' + certifiedExchangesTable + "\n" + + for (const path of certifiedExchangesPaths) { + logExportExchanges (path, certifiedExchangesRegex, certifiedExchanges) + } + + // logExportExchanges ('README.md', certifiedExchangesRegex, certifiedExchanges) + } + + if (exchangesByCountriesPaths) { + let exchangesByCountries = [] + keys (countries).forEach (code => { + let country = countries[code] + let result = [] + keys (exchanges).forEach (id => { + let exchange = exchanges[id] + let logo = exchange.urls['logo'] + let website = Array.isArray (exchange.urls.www) ? exchange.urls.www[0] : exchange.urls.www + let url = exchange.urls.referral || website + let doc = Array.isArray (exchange.urls.doc) ? exchange.urls.doc[0] : exchange.urls.doc + let version = exchange.version ? exchange.version : '\*' + let matches = version.match (/[^0-9]*([0-9].*)/) + if (matches) + version = matches[1]; + let shouldInclude = false + if (Array.isArray (exchange.countries)) { + if (exchange.countries.indexOf (code) > -1) + shouldInclude = true + } else { + if (code == exchange.countries) + shouldInclude = true + } + if (shouldInclude) { + let entry = [ + country, + '[![' + exchange.id + '](' + logo + ')](' + url + ')', + exchange.id, + '[' + exchange.name + '](' + url + ')', + version, + '[API](' + doc + ')', + // doesn't fit in width + // exchange.certified ? ccxtCertifiedBadge : '', + ] + result.push (entry) + } + }) + exchangesByCountries = exchangesByCountries.concat (result) + }); + + const countryKeyIndex = exchangesByCountryHeading.indexOf ('country / region') + exchangesByCountries = exchangesByCountries.sort ((a, b) => { + const countryA = a[countryKeyIndex].toLowerCase () + const countryB = b[countryKeyIndex].toLowerCase () + if (countryA > countryB) { + return 1 + } else if (countryA < countryB) { + return -1; } else { - if (code == exchange.countries) - shouldInclude = true - } - if (shouldInclude) { - let entry = [ - country, - '[![' + exchange.id + '](' + logo + ')](' + url + ')', - exchange.id, - '[' + exchange.name + '](' + url + ')', - version, - '[API](' + doc + ')', - // doesn't fit in width - // exchange.certified ? ccxtCertifiedBadge : '', - ] - result.push (entry) + if (a['id'] > b['id']) + return 1; + else if (a['id'] < b['id']) + return -1; + else + return 0; } }) - exchangesByCountries = exchangesByCountries.concat (result) - }); - let countryKeyIndex = exchangesByCountryHeading.indexOf ('country / region') - exchangesByCountries = exchangesByCountries.sort ((a, b) => { - let countryA = a[countryKeyIndex].toLowerCase () - let countryB = b[countryKeyIndex].toLowerCase () - if (countryA > countryB) { - return 1 - } else if (countryA < countryB) { - return -1; - } else { - if (a['id'] > b['id']) - return 1; - else if (a['id'] < b['id']) - return -1; - else - return 0; + exchangesByCountries.splice (0, 0, exchangesByCountryHeading) + const lines = makeTable (exchangesByCountries) + const result = "# Exchanges By Country\n\nThe ccxt library currently supports the following cryptocurrency exchange markets and trading APIs:\n\n" + lines + "\n\n" + for (const path of exchangesByCountriesPaths) { + fs.truncateSync (path) + fs.writeFileSync (path, result) } - }) - - exchangesByCountries.splice (0, 0, exchangesByCountryHeading) - let lines = makeTable (exchangesByCountries) - let result = "# Exchanges By Country\n\nThe ccxt library currently supports the following cryptocurrency exchange markets and trading APIs:\n\n" + lines + "\n\n" - let filename = wikiPath + '/Exchange-Markets-By-Country.md' - fs.truncateSync (filename) - fs.writeFileSync (filename, result) + } } // TODO: REWRITE THIS ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ @@ -237,7 +279,9 @@ function exportSupportedAndCertifiedExchanges (exchanges, wikiPath) { function exportExchangeIdsToExchangesJson (exchanges) { log.bright ('Exporting exchange ids to'.cyan, 'exchanges.json'.yellow) - fs.writeFileSync ('exchanges.json', JSON.stringify ({ ids: keys (exchanges) }, null, 4)) + const ids = keys (exchanges) + console.log (ids) + fs.writeFileSync ('exchanges.json', JSON.stringify ({ ids }, null, 4)) } // ---------------------------------------------------------------------------- @@ -252,6 +296,9 @@ function exportWikiToGitHub (wikiPath, gitWikiPath) { 'Manual.md': 'Manual.md', 'Exchange-Markets.md': 'Exchange-Markets.md', 'Exchange-Markets-By-Country.md': 'Exchange-Markets-By-Country.md', + 'ccxt.pro.md': 'ccxt.pro.md', + 'ccxt.pro.install.md': 'ccxt.pro.install.md', + 'ccxt.pro.manual.md': 'ccxt.pro.manual.md', } for (const [ sourceFile, destinationFile ] of entries (ccxtWikiFiles)) { @@ -281,18 +328,13 @@ function exportKeywordsToPackageJson (exchanges) { } packageJSON.keywords = [...keywords] - fs.writeFileSync ('./package.json', JSON.stringify (packageJSON, null, 2)) + fs.writeFileSync ('./package.json', JSON.stringify (packageJSON, null, 2) + "\n") } // ---------------------------------------------------------------------------- function exportEverything () { - const wikiPath = 'wiki' - , gitWikiPath = 'build/ccxt.wiki' - - cloneGitHubWiki (gitWikiPath) - const ids = getIncludedExchangeIds () const replacements = [ @@ -333,7 +375,28 @@ function exportEverything () { // strategically placed exactly here (we can require it AFTER the export) const exchanges = createExchanges (ids) - exportSupportedAndCertifiedExchanges (exchanges, wikiPath) + const wikiPath = 'wiki' + , gitWikiPath = 'build/ccxt.wiki' + + cloneGitHubWiki (gitWikiPath) + + exportSupportedAndCertifiedExchanges (exchanges, { + allExchangesPaths: [ + 'README.md', + wikiPath + '/Manual.md', + wikiPath + '/Exchange-Markets.md' + ], + certifiedExchangesPaths: [ + 'README.md', + ], + exchangesByCountriesPaths: [ + wikiPath + '/Exchange-Markets-By-Country.md' + ], + proExchangesPaths: [ + wikiPath + '/ccxt.pro.manual.md', + ], + }) + exportExchangeIdsToExchangesJson (exchanges) exportWikiToGitHub (wikiPath, gitWikiPath) exportKeywordsToPackageJson (exchanges) diff --git a/TaskServer/node_modules/ccxt/build/transpile.js b/TaskServer/node_modules/ccxt/build/transpile.js index 64bf249cd..b55ffae59 100644 --- a/TaskServer/node_modules/ccxt/build/transpile.js +++ b/TaskServer/node_modules/ccxt/build/transpile.js @@ -5,16 +5,23 @@ "use strict"; const fs = require ('fs') - , log = require ('ololog') + , log = require ('ololog').unlimited , _ = require ('ansicolor').nice , errors = require ('../js/base/errors.js') - , { unCamelCase, precisionConstants, safeString } = require ('../js/base/functions.js') + , functions = require ('../js/base/functions.js') + , { + unCamelCase, + precisionConstants, + safeString, + unique, + } = functions , { basename } = require ('path') , { createFolderRecursively, replaceInFile, overwriteFile, } = require ('./fs.js') + , Exchange = require ('../js/base/Exchange.js') class Transpiler { @@ -60,6 +67,7 @@ class Transpiler { [ /\.parseTrades\s/g, '.parse_trades'], [ /\.parseTrade\s/g, '.parse_trade'], [ /\.parseTradingViewOHLCV\s/g, '.parse_trading_view_ohlcv'], + [ /\.convertTradingViewToOHLCV\s/g, '.convert_trading_view_to_ohlcv'], [ /\.parseTransaction\s/g, '.parse_transaction'], [ /\.parseTransactions\s/g, '.parse_transactions'], [ /\.parseOrderBook\s/g, '.parse_order_book'], @@ -299,7 +307,9 @@ class Transpiler { [ /this\.stringToBase64\s/g, 'base64_encode' ], [ /this\.binaryToBase16\s/g, 'bin2hex' ], [ /this\.base64ToBinary\s/g, 'base64_decode' ], - [ /this\.deepExtend\s/g, 'array_replace_recursive'], + // deepExtend is commented for PHP because it does not overwrite linear arrays + // a proper \ccxt\Exchange::deep_extend() base method is implemented instead + // [ /this\.deepExtend\s/g, 'array_replace_recursive'], [ /(\w+)\.shift\s*\(\)/g, 'array_shift($1)' ], [ /(\w+)\.pop\s*\(\)/g, 'array_pop($1)' ], [ /Number\.MAX_SAFE_INTEGER/g, 'PHP_INT_MAX' ], @@ -382,12 +392,27 @@ class Transpiler { ]) } + getBaseClass () { + return new Exchange () + } + + getBaseMethods () { + const baseExchange = this.getBaseClass () + let object = baseExchange + let properties = [] + while (object !== Object.prototype) { + properties = properties.concat (Object.getOwnPropertyNames (object)) + object = Object.getPrototypeOf (object) + } + return properties.filter (x => typeof baseExchange[x] === 'function') + } + getPythonBaseMethods () { - return [] + return this.getBaseMethods () } getPHPBaseMethods () { - return [] + return this.getBaseMethods () } //------------------------------------------------------------------------- @@ -589,10 +614,10 @@ class Transpiler { methods = methods.concat (this.getPHPBaseMethods ()) for (let method of methods) { - const regex = new RegExp ('\\$this->(' + method + ')(\\s\\(|[^a-zA-Z0-9_])', 'g') + const regex = new RegExp ('\\$this->(' + method + ')\\s?(\\(|[^a-zA-Z0-9_])', 'g') bodyAsString = bodyAsString.replace (regex, (match, p1, p2) => { - return ((p2 === ' (') ? + return ((p2 === '(') ? ('$this->' + unCamelCase (p1) + p2) : // support direct php calls ("array($this, '" + unCamelCase (p1) + "')" + p2)) // as well as passing instance methods as callables }) @@ -748,7 +773,7 @@ class Transpiler { // ------------------------------------------------------------------------ - transpileDerivedExchangeClass (contents) { + transpileDerivedExchangeClass (contents, methodNames = undefined) { let exchangeClassDeclarationMatches = contents.match (/^module\.exports\s*=\s*class\s+([\S]+)\s+extends\s+([\S]+)\s+{([\s\S]+?)^};*/m) @@ -763,7 +788,7 @@ class Transpiler { let python3 = [] let php = [] - let methodNames = [] + methodNames = [] // methodNames || [] // run through all methods for (let i = 0; i < methods.length; i++) { @@ -839,7 +864,7 @@ class Transpiler { // compile signature + body for PHP php.push (''); - php.push (' public function ' + method + ' (' + phpArgs + ') {'); + php.push (' public function ' + method + '(' + phpArgs + ') {'); php.push (phpBody); php.push (' }') @@ -866,8 +891,25 @@ class Transpiler { try { const { python2Folder, python3Folder, phpFolder } = options - const contents = fs.readFileSync (jsFolder + filename, 'utf8') - const { python2, python3, php, className, baseClass } = this.transpileDerivedExchangeClass (contents) + const path = jsFolder + filename + const contents = fs.readFileSync (path, 'utf8') + + // function getMethodNames (object) { + // let functions = [] + // let o = object + // do { + // functions = functions.concat (Object.getOwnPropertyNames (o)) + // } while (o = Object.getPrototypeOf (o)) + // return unique (functions.filter (f => (typeof object[f] === 'function'))) + // } + // const exchangeClass = require ('.' + path) + // const exchange = new exchangeClass () + // const methodNames = getMethodNames (exchange) + // const { python2, python3, php, className, baseClass } = + // this.transpileDerivedExchangeClass (contents, methodNames) + + const { python2, python3, php, className, baseClass } = + this.transpileDerivedExchangeClass (contents) log.cyan ('Transpiling from', filename.yellow) @@ -943,11 +985,12 @@ class Transpiler { // ======================================================================== - exportTypeScriptDeclarations (classes) { + exportTypeScriptDeclarations (file, classes) { - const file = './ccxt.d.ts' - const regex = /(?: export class [^\s]+ extends [^\s]+ \{\}[\r]?[\n])+/ - const replacement = Object.keys (classes).map (className => { + log.bright.cyan ('Exporting TypeScript declarations →', file.yellow) + + const regex = /\/[\n]{2}(?: export class [^\s]+ extends [^\s]+ \{\}[\r]?[\n])+/ + const replacement = "/\n\n" + Object.keys (classes).map (className => { const baseClass = classes[className] return ' export class ' + className + ' extends ' + baseClass + " {}" }).join ("\n") + "\n" @@ -968,34 +1011,91 @@ class Transpiler { [ /module\.exports = [^\;]+\;\n/s, '' ], ]).trim () + const message = 'Transpiling error hierachy →' + const root = errorHierarchy['BaseError'] + const { python3Body, phpBody } = this.transpileJavaScriptToPythonAndPHP ({ js }) - const python3BodyIntellisense = python3Body + '\n\n' + Array.from (function* intellisense (map) { - for (const key in map) { - yield key + ' = Exception' - yield* intellisense (map[key]) + // a helper to generate a list of exception class declarations + // properly derived from corresponding parent classes according + // to the error hierarchy + + function intellisense (map, parent, generate, classes) { + function* generator(map, parent, generate, classes) { + for (const key in map) { + yield generate (key, parent, classes) + yield* generator (map[key], key, generate, classes) + } } - } (errorHierarchy['BaseError'])).join ('\n') - - const message = 'Transpiling error hierachy →' - - const python = { - filename: './python/ccxt/base/errors.py', - regex: /error_hierarchy = [\S\s]+= Exception/s, - replacement: python3BodyIntellisense, + return Array.from (generator (map, parent, generate, classes)) } - log.bright.cyan (message, python.filename.yellow) - replaceInFile (... Object.values (python)) + // Python ------------------------------------------------------------- - const php = { - filename:'./php/base/errors.php', - regex: /\$error_hierarchy = .+?\n\)\;/s, - replacement: phpBody, + function pythonDeclareErrorClass (name, parent, classes) { + classes.push (name) + return [ + 'class ' + name + '(' + parent + '):', + ' pass', + '', + '', + ].join ('\n'); } - log.bright.cyan (message, php.filename.yellow) - replaceInFile (... Object.values (php)) + const pythonBaseError = [ + 'class BaseError(Exception):', + ' pass', + '', + '', + ].join ('\n'); + + const quote = (s) => "'" + s + "'" // helper to add quotes around class names + + const pythonExports = [ 'error_hierarchy' ] + const pythonErrors = intellisense (root, 'BaseError', pythonDeclareErrorClass, pythonExports) + const pythonAll = '__all__ = [\n ' + pythonExports.map (quote).join (',\n ') + '\n]' + + const python3BodyIntellisense = python3Body + '\n\n\n' + pythonBaseError + '\n' + pythonErrors.join ('\n') + '\n' + pythonAll + '\n' + + const pythonFilename = './python/ccxt/base/errors.py' + log.bright.cyan (message, pythonFilename.yellow) + fs.writeFileSync (pythonFilename, python3BodyIntellisense) + + // PHP ---------------------------------------------------------------- + + function phpDeclareErrorClass (name, parent) { + return 'class ' + name + ' extends ' + parent + ' {};' + } + + const phpHeader = ' 0) { + vwap = parseFloat (this.priceToPrecision (symbol, quoteVolume / baseVolume)); + } + } + } + return { + 'symbol': symbol, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'high': this.safeFloat (ticker, 'high'), + 'low': this.safeFloat (ticker, 'low'), + 'bid': undefined, + 'bidVolume': undefined, + 'ask': undefined, + 'askVolume': undefined, + 'vwap': vwap, + 'open': open, + 'close': last, + 'last': last, + 'previousClose': undefined, + 'change': change, + 'percentage': percentage, + 'average': average, + 'baseVolume': baseVolume, + 'quoteVolume': quoteVolume, + 'info': ticker, + }; + } + + async fetchTickers (symbols = undefined, params = {}) { + await this.loadMarkets (); + const request = {}; + if (symbols !== undefined) { + const ids = this.marketIds (symbols); + request['symbol'] = ids.join (','); + } + const response = await this.publicGetMarket24kline (this.extend (request, params)); + // + // { + // errno: 0, + // errmsg: "success", + // result: [ + // { + // symbol: "HB-AQ", + // data: { + // id: 1584893403, + // amount: "4753751.243400354852648809", + // count: 4724, + // open: "6.3497", + // close: "6.3318", + // low: "6.011", + // high: "6.5", + // vol: "29538384.7873528796542891343493" + // } + // }, + // ] + // } + // + const tickers = this.safeValue (response, 'result', []); + const result = {}; + for (let i = 0; i < tickers.length; i++) { + const marketId = this.safeString (tickers[i], 'symbol'); + let market = undefined; + let symbol = marketId; + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + const [ baseId, quoteId ] = marketId.split ('-'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + } + const data = this.safeValue (tickers[i], 'data', {}); + const ticker = this.parseTicker (data, market); + ticker['symbol'] = symbol; + result[symbol] = ticker; + } + return this.filterByArray (result, 'symbol', symbols); + } + + async fetchTicker (symbol, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.publicGetMarketDetail (this.extend (request, params)); + // + // { + // errno: 0, + // errmsg: 'success', + // result: { + // id: 1584890087, + // amount: '150032.919', + // count: 134538, + // open: '0.021394', + // close: '0.021177', + // low: '0.021053', + // high: '0.021595', + // vol: '3201.72451442' + // } + // } + // + const result = this.safeValue (response, 'result', {}); + return this.parseTicker (result, market); + } + + parseTrade (trade, market = undefined) { + // + // fetchTrades (public) + // + // { + // id: 1584948803298490, + // amount: "2.737", + // price: "0.021209", + // direction: "sell", + // ts: 1584948803 + // } + // + // fetchOrder trades + // + // { + // "id":null, + // "ctime":"2020-03-23 20:07:17", + // "price":"123.9", + // "number":"0.010688626311541565", + // "total_price":"1.324320799999999903", + // "fee":"0.000021377252623083" + // } + // + const id = this.safeString (trade, 'id'); + const ctime = this.parse8601 (this.safeString (trade, 'ctime')); + const timestamp = this.safeTimestamp (trade, 'ts', ctime); + let symbol = undefined; + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const side = this.safeString (trade, 'direction'); + const price = this.safeFloat (trade, 'price'); + const amount = this.safeFloat2 (trade, 'amount', 'number'); + let cost = this.safeFloat (trade, 'total_price'); + if ((cost === undefined) && (price !== undefined) && (amount !== undefined)) { + cost = price * amount; + } + const feeCost = this.safeFloat (trade, 'fee'); + let fee = undefined; + if (feeCost !== undefined) { + let feeCurrencyCode = undefined; + if (market !== undefined) { + if (side === 'buy') { + feeCurrencyCode = market['base']; + } else if (side === 'sell') { + feeCurrencyCode = market['quote']; + } + } + fee = { + 'cost': feeCost, + 'currency': feeCurrencyCode, + }; + } + return { + 'id': id, + 'info': trade, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'symbol': symbol, + 'order': undefined, + 'type': undefined, + 'side': side, + 'takerOrMaker': undefined, + 'price': price, + 'amount': amount, + 'cost': cost, + 'fee': fee, + }; + } + + async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.publicGetMarketTrade (this.extend (request, params)); + // + // { + // errno: 0, + // errmsg: "success", + // result: { + // symbol: "ETH-BTC", + // ts: 1584948805439, + // data: [ + // { + // id: 1584948803300883, + // amount: "0.583", + // price: "0.021209", + // direction: "buy", + // ts: 1584948803 + // }, + // { + // id: 1584948803298490, + // amount: "2.737", + // price: "0.021209", + // direction: "sell", + // ts: 1584948803 + // }, + // ] + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const data = this.safeValue (result, 'data', []); + return this.parseTrades (data, market, since, limit); + } + + parseOrderStatus (status) { + const statuses = { + '1': 'open', + '2': 'open', // partially filled + '3': 'closed', + '4': 'canceled', // canceling + '5': 'canceled', // partially canceled + '6': 'canceled', + }; + return this.safeString (statuses, status, status); + } + + parseOrder (order, market = undefined) { + // + // createOrder + // + // { order_sn: 'BM7442641584965237751ZMAKJ5' } + // + // fetchOpenOrders, fetchClosedOrders + // + // { + // "order_sn": "BL74426415849672087836G48N1", + // "symbol": "ETH-USDT", + // "ctime": "2020-03-23 20:40:08", + // "type": 2, + // "side": "buy", + // "price": "90", // undefined for market orders + // "number": "0.1", + // "total_price": "9.0", // 0 for market orders + // "deal_number": null, + // "deal_price": null, + // "status": 1, + // } + // + // fetchOrder + // + // { + // order_sn: 'BM7442641584965237751ZMAKJ5', + // symbol: 'ETH-USDT', + // ctime: '2020-03-23 20:07:17', + // type: 1, + // side: 'buy', + // price: '0', + // number: '10', + // total_price: '0', + // deal_number: '0.080718626311541565', + // deal_price: '123.890000000000000000', + // status: 3, + // // the trades field is injected by fetchOrder + // trades: [ + // { + // id: null, + // ctime: '2020-03-23 20:07:17', + // price: '123.9', + // number: '0.010688626311541565', + // total_price: '1.324320799999999903', + // fee: '0.000021377252623083' + // } + // ] + // } + // + const id = this.safeString (order, 'order_sn'); + const orderStatus = this.safeString (order, 'status'); + const status = this.parseOrderStatus (orderStatus); + let symbol = undefined; + const marketId = this.safeString (order, 'symbol'); + let base = undefined; + let quote = undefined; + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } else { + const [ baseId, quoteId ] = marketId.split ('-'); + base = this.safeCurrencyCode (baseId); + quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + base = market['base']; + quote = market['quote']; + } + const timestamp = this.parse8601 (this.safeString (order, 'ctime')); + const orderType = this.safeString (order, 'type'); + const type = (orderType === '2') ? 'limit' : 'market'; + const side = this.safeString (order, 'side'); + // const amount = this.safeFloat (order, 'number'); + // const price = this.safeFloat (order, 'price'); + let cost = undefined; + let price = undefined; + let amount = undefined; + let average = undefined; + const number = this.safeFloat (order, 'number'); + const totalPrice = this.safeFloat (order, 'total_price'); + if (type === 'limit') { + amount = number; + price = this.safeFloat (order, 'price'); + } else { + average = this.safeFloat (order, 'deal_price'); + if (side === 'buy') { + amount = this.safeFloat (order, 'deal_number'); + } else { + amount = number; + } + } + let fee = undefined; + let trades = undefined; + let filled = undefined; + let feeCost = undefined; + let remaining = undefined; + let lastTradeTimestamp = undefined; + // all orders except new orders and canceled orders + if ((orderStatus !== '1') && (orderStatus !== '6')) { + const rawTrades = this.safeValue (order, 'trades'); + if (rawTrades !== undefined) { + for (let i = 0; i < rawTrades.length; i++) { + rawTrades[i]['direction'] = side; + } + trades = this.parseTrades (rawTrades, market, undefined, undefined, { + 'symbol': market['symbol'], + 'order': id, + 'side': side, + 'type': type, + }); + const tradesLength = trades.length; + if (tradesLength > 0) { + const firstTrade = trades[0]; + feeCost = firstTrade['fee']['cost']; + lastTradeTimestamp = firstTrade['timestamp']; + filled = firstTrade['amount']; + cost = firstTrade['cost']; + for (let i = 1; i < trades.length; i++) { + const trade = trades[i]; + feeCost = this.sum (feeCost, trade['fee']['cost']); + filled = this.sum (filled, trade['amount']); + cost = this.sum (cost, trade['cost']); + lastTradeTimestamp = Math.max (lastTradeTimestamp, trade['timestamp']); + } + if (amount !== undefined) { + filled = Math.min (amount, filled); + } + if (filled > 0) { + average = cost / filled; + } + } + if (feeCost !== undefined) { + const feeCurrencyCode = (side === 'buy') ? base : quote; + fee = { + 'cost': feeCost, + 'currency': feeCurrencyCode, + }; + } + } + } else { + filled = 0; + cost = 0; + } + if (cost === undefined) { + if (type === 'limit') { + cost = totalPrice; + } else if (side === 'buy') { + cost = number; + } + } + if (filled === undefined) { + if ((type === 'limit') && (orderStatus === '3')) { + filled = amount; + } + } + if (filled !== undefined) { + if (amount !== undefined) { + remaining = Math.max (amount - filled, 0); + } + } + return { + 'info': order, + 'id': id, + 'clientOrderId': undefined, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': lastTradeTimestamp, + 'status': status, + 'symbol': symbol, + 'type': type, + 'side': side, + 'price': price, + 'cost': cost, + 'average': average, + 'amount': amount, + 'filled': filled, + 'remaining': remaining, + 'trades': trades, + 'fee': fee, + }; + } + + async fetchClosedOrder (id, symbol = undefined, params = {}) { + await this.loadMarkets (); + const request = { + 'order_sn': id, + }; + const response = await this.privateGetEntrustDetail (this.extend (request, params)); + // + // { + // "errno": 0, + // "errmsg": "success", + // "result": { + // "trades": [ + // { + // "id":null, + // "ctime":"2020-03-23 20:07:17", + // "price":"123.9", + // "number":"0.010688626311541565", + // "total_price":"1.324320799999999903", + // "fee":"0.000021377252623083" + // }, + // ], + // "entrust":{ + // "order_sn":"BM7442641584965237751ZMAKJ5", + // "symbol":"ETH-USDT", + // "ctime":"2020-03-23 20:07:17", + // "type":1, + // "side":"buy", + // "price":"0", + // "number":"10", + // "total_price":"0", + // "deal_number":"0.080718626311541565", + // "deal_price":"123.890000000000000000", + // "status":3 + // } + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const trades = this.safeValue (result, 'trades', []); + const order = this.safeValue (result, 'entrust', {}); + order['trades'] = trades; + return this.parseOrder (order); + } + + async fetchOrdersWithMethod (method, symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'from': 'BM7442641584965237751ZMAKJ5', // query start order_sn + // 'direct': 'prev', // next + }; + let market = undefined; + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + } + if (limit !== undefined) { + request['limit'] = limit; // default 20, max 100 + } + const response = await this[method] (this.extend (request, params)); + // + // { + // "errno": 0, + // "errmsg": "success", + // "result": [ + // { + // "order_sn": "BL74426415849672087836G48N1", + // "symbol": "ETH-USDT", + // "ctime": "2020-03-23 20:40:08", + // "type": 2, + // "side": "buy", + // "price": "90", + // "number": "0.1", + // "total_price": "9.0", + // "deal_number": null, + // "deal_price": null, + // "status": 1, + // } + // ] + // } + // + const result = this.safeValue (response, 'result', []); + return this.parseOrders (result, market, since, limit); + } + + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + return await this.fetchOrdersWithMethod ('privateGetEntrustCurrentList', symbol, since, limit, params); + } + + async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + return await this.fetchOrdersWithMethod ('privateGetEntrustHistoryList', symbol, since, limit, params); + } + + async createOrder (symbol, type, side, amount, price = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const orderType = side + '-' + type; + const request = { + 'symbol': market['id'], + 'type': orderType, + }; + if (type === 'limit') { + request['amount'] = this.amountToPrecision (symbol, amount); + request['price'] = this.priceToPrecision (symbol, price); + } else if (type === 'market') { + // for market buy it requires the amount of quote currency to spend + if (side === 'buy') { + const createMarketBuyOrderRequiresPrice = this.safeValue (this.options, 'createMarketBuyOrderRequiresPrice', true); + let cost = amount; + if (createMarketBuyOrderRequiresPrice) { + if (price !== undefined) { + cost = amount * price; + } else { + throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'amount' argument"); + } + } + const precision = market['precision']['price']; + request['amount'] = this.decimalToPrecision (cost, TRUNCATE, precision, this.precisionMode); + } else { + request['amount'] = this.amountToPrecision (symbol, amount); + } + } + const response = await this.privatePostEntrustAdd (this.extend (request, params)); + // + // { + // errno: 0, + // errmsg: 'success', + // result: { order_sn: 'BM7442641584965237751ZMAKJ5' } + // } + // + const result = this.safeValue (response, 'result', {}); + const order = this.parseOrder (result, market); + const timestamp = this.milliseconds (); + return this.extend (order, { + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'amount': amount, + 'price': price, + 'type': type, + 'side': side, + }); + } + + async cancelOrder (id, symbol = undefined, params = {}) { + await this.loadMarkets (); + const request = { + 'order_ids': id, + }; + const response = await this.privatePostEntrustCancel (this.extend (request, params)); + // + // { + // "errno": 0, + // "errmsg": "success", + // "result": { + // "success": [ "avl12121", "bl3123123" ], + // "failed": [ "sd24564", "sdf6564564" ] + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const success = this.safeValue (result, 'success', []); + if (!this.inArray (id, success)) { + throw new OrderNotFound (this.id + ' order id ' + id + ' not found in successfully canceled orders: ' + this.json (response)); + } + const timestamp = undefined; + return { + 'info': response, + 'id': id, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': undefined, + 'status': 'canceled', + 'symbol': symbol, + 'type': undefined, + 'side': undefined, + 'price': undefined, + 'cost': undefined, + 'average': undefined, + 'amount': undefined, + 'filled': undefined, + 'remaining': undefined, + 'trades': undefined, + 'fee': undefined, + 'clientOrderId': undefined, + }; + } + + async cancelAllOrders (symbol = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' cancelAllOrders() requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.privatePostEntrustCancel (this.extend (request, params)); + // + // { + // "errno": 0, + // "errmsg": "success", + // "result": { + // "success": [ "avl12121", "bl3123123" ], + // "failed": [ "sd24564", "sdf6564564" ] + // } + // } + // + return response; + } + + nonce () { + return this.milliseconds (); + } + + sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { + let url = this.urls['api'][api] + '/' + path; + let keys = Object.keys (params); + const keysLength = keys.length; + if (api === 'public') { + if (keysLength > 0) { + url += '?' + this.urlencode (params); + } + } else { + const nonce = this.nonce ().toString (); + const uuid = this.uuid (); + const randomString = uuid.slice (0, 5); + const nonceString = nonce + '_' + randomString; + const auth = {}; + auth[this.apiKey] = this.apiKey; + auth[this.secret] = this.secret; + auth[nonceString] = nonceString; + for (let i = 0; i < keysLength; i++) { + const key = keys[i]; + auth[key] = key + '=' + params[key]; + } + const keysorted = this.keysort (auth); + let stringToSign = ''; + keys = Object.keys (keysorted); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + stringToSign += keysorted[key]; + } + const signature = this.hash (this.encode (stringToSign), 'sha1'); + headers = { + 'Nonce': nonceString, + 'Token': this.apiKey, + 'Signature': signature, + }; + if (method === 'POST') { + headers['Content-Type'] = 'application/x-www-form-urlencoded'; + if (keysLength > 0) { + body = this.urlencode (params); + } + } else { + if (keysLength > 0) { + url += '?' + this.urlencode (params); + } + } + } + return { 'url': url, 'method': method, 'body': body, 'headers': headers }; + } + + handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (response === undefined) { + return; + } + // + // {"errno":20501,"errmsg":"base symbol error"} + // + const error = this.safeString (response, 'errno'); + if ((error !== undefined) && (error !== '0')) { + const message = this.safeString (response, 'errmsg'); + const feedback = this.id + ' ' + body; + this.throwExactlyMatchedException (this.exceptions['exact'], error, feedback); + this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback); + throw new ExchangeError (feedback); // unknown message + } + } +}; + +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],8:[function(require,module,exports){ (function (Buffer){ "use strict"; @@ -3472,17 +4613,13 @@ const BN = require ('../static_dependencies/BN/bn') // ---------------------------------------------------------------------------- // web3 / 0x imports -let Web3 = undefined - , ethAbi = undefined +let ethAbi = undefined , ethUtil = undefined - , BigNumber = undefined try { const requireFunction = require; - Web3 = requireFunction ('web3') // eslint-disable-line global-require ethAbi = requireFunction ('ethereumjs-abi') // eslint-disable-line global-require ethUtil = requireFunction ('ethereumjs-util') // eslint-disable-line global-require - BigNumber = requireFunction ('bignumber.js') // eslint-disable-line global-require // we prefer bignumber.js over BN.js // BN = requireFunction ('bn.js') // eslint-disable-line global-require } catch (e) { @@ -3501,6 +4638,7 @@ module.exports = class Exchange { 'enableRateLimit': false, 'rateLimit': 2000, // milliseconds = seconds * 1000 'certified': false, + 'pro': false, 'has': { 'cancelAllOrders': false, 'cancelOrder': true, @@ -3593,6 +4731,7 @@ module.exports = class Exchange { '429': RateLimitExceeded, '404': ExchangeNotAvailable, '409': ExchangeNotAvailable, + '410': ExchangeNotAvailable, '500': ExchangeNotAvailable, '501': ExchangeNotAvailable, '502': ExchangeNotAvailable, @@ -3700,8 +4839,6 @@ module.exports = class Exchange { this.last_json_response = undefined this.last_response_headers = undefined - this.arrayConcat = (a, b) => a.concat (b) - const unCamelCaseProperties = (obj = this) => { if (obj !== null) { for (const k of Object.getOwnPropertyNames (obj)) { @@ -3739,11 +4876,6 @@ module.exports = class Exchange { if (this.markets) this.setMarkets (this.markets) - - if (this.requiresWeb3 && !this.web3 && Web3) { - const provider = (this.web3ProviderURL) ? new Web3.providers.HttpProvider (this.web3ProviderURL) : new Web3.providers.HttpProvider () - this.web3 = new Web3 (Web3.givenProvider || provider) - } } defaults () { @@ -3791,7 +4923,6 @@ module.exports = class Exchange { throw new Error (this.id + '.rateLimit property is not configured') this.tokenBucket = this.extend ({ - refillRate: 1 / this.rateLimit, delay: 1, capacity: 1, defaultCost: 1, @@ -3896,42 +5027,50 @@ module.exports = class Exchange { } } + print (... args) { + console.log (... args) + } + fetch (url, method = 'GET', headers = undefined, body = undefined) { if (isNode && this.userAgent) { - if (typeof this.userAgent === 'string') + if (typeof this.userAgent === 'string') { headers = extend ({ 'User-Agent': this.userAgent }, headers) - else if ((typeof this.userAgent === 'object') && ('User-Agent' in this.userAgent)) + } else if ((typeof this.userAgent === 'object') && ('User-Agent' in this.userAgent)) { headers = extend (this.userAgent, headers) + } } if (typeof this.proxy === 'function') { url = this.proxy (url) - if (isNode) + if (isNode) { headers = extend ({ 'Origin': this.origin }, headers) + } } else if (typeof this.proxy === 'string') { - if (this.proxy.length) - if (isNode) - headers = extend ({ 'Origin': this.origin }, headers) + if (this.proxy.length && isNode) { + headers = extend ({ 'Origin': this.origin }, headers) + } url = this.proxy + url } headers = extend (this.headers, headers) - if (this.verbose) - console.log ("fetch:\n", this.id, method, url, "\nRequest:\n", headers, "\n", body, "\n") + if (this.verbose) { + this.print ("fetch:\n", this.id, method, url, "\nRequest:\n", headers, "\n", body, "\n") + } return this.executeRestRequest (url, method, headers, body) } async fetch2 (path, type = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - if (this.enableRateLimit) - await this.throttle () + if (this.enableRateLimit) { + await this.throttle (this.rateLimit) + } const request = this.sign (path, type, method, params, headers, body) return this.fetch (request.url, request.method, request.headers, request.body) @@ -4046,8 +5185,9 @@ module.exports = class Exchange { this.last_json_response = json // FIXME: for those classes that haven't switched to handleErrors yet } - if (this.verbose) - console.log ("handleRestResponse:\n", this.id, method, url, response.status, response.statusText, "\nResponse:\n", responseHeaders, "\n", responseBody, "\n") + if (this.verbose) { + this.print ("handleRestResponse:\n", this.id, method, url, response.status, response.statusText, "\nResponse:\n", responseHeaders, "\n", responseBody, "\n") + } this.handleErrors (response.status, response.statusText, url, method, responseHeaders, responseBody, json, requestHeaders, requestBody) this.defaultErrorHandler (response.status, response.statusText, url, method, responseHeaders, responseBody, json) @@ -4069,7 +5209,7 @@ module.exports = class Exchange { if (currencies) { this.currencies = deepExtend (currencies, this.currencies) } else { - const baseCurrencies = + let baseCurrencies = values.filter (market => 'base' in market) .map (market => ({ id: market.baseId || market.base, @@ -4077,7 +5217,7 @@ module.exports = class Exchange { code: market.base, precision: market.precision ? (market.precision.base || market.precision.amount) : 8, })) - const quoteCurrencies = + let quoteCurrencies = values.filter (market => 'quote' in market) .map (market => ({ id: market.quoteId || market.quote, @@ -4085,6 +5225,10 @@ module.exports = class Exchange { code: market.quote, precision: market.precision ? (market.precision.quote || market.precision.price) : 8, })) + baseCurrencies = sortBy (baseCurrencies, 'code') + quoteCurrencies = sortBy (quoteCurrencies, 'code') + this.baseCurrencies = indexBy (baseCurrencies, 'code') + this.quoteCurrencies = indexBy (quoteCurrencies, 'code') const allCurrencies = baseCurrencies.concat (quoteCurrencies) const groupedCurrencies = groupBy (allCurrencies, 'code') const currencies = Object.keys (groupedCurrencies).map (code => @@ -4097,7 +5241,7 @@ module.exports = class Exchange { return this.markets } - async loadMarkets (reload = false, params = {}) { + async loadMarketsHelper (reload = false, params = {}) { if (!reload && this.markets) { if (!this.markets_by_id) { return this.setMarkets (this.markets) @@ -4112,6 +5256,21 @@ module.exports = class Exchange { return this.setMarkets (markets, currencies) } + // is async (returns a promise) + loadMarkets (reload = false, params = {}) { + if ((reload && !this.reloadingMarkets) || !this.marketsLoading) { + this.reloadingMarkets = true + this.marketsLoading = this.loadMarketsHelper (reload, params).then ((resolved) => { + this.reloadingMarkets = false + return resolved + }, (error) => { + this.reloadingMarkets = false + throw error + }) + } + return this.marketsLoading + } + async loadAccounts (reload = false, params = {}) { if (reload) { this.accounts = await this.fetchAccounts (params) @@ -4149,43 +5308,42 @@ module.exports = class Exchange { } parseTradingViewOHLCV (ohlcvs, market = undefined, timeframe = '1m', since = undefined, limit = undefined) { - const result = this.convertTradingViewToOHLCV (ohlcvs); - return this.parseOHLCVs (result, market, timeframe, since, limit); + const result = this.convertTradingViewToOHLCV (ohlcvs) + return this.parseOHLCVs (result, market, timeframe, since, limit) } - convertTradingViewToOHLCV (ohlcvs) { + convertTradingViewToOHLCV (ohlcvs, t = 't', o = 'o', h = 'h', l = 'l', c = 'c', v = 'v', ms = false) { const result = []; - for (let i = 0; i < ohlcvs['t'].length; i++) { + for (let i = 0; i < ohlcvs[t].length; i++) { result.push ([ - ohlcvs['t'][i] * 1000, - ohlcvs['o'][i], - ohlcvs['h'][i], - ohlcvs['l'][i], - ohlcvs['c'][i], - ohlcvs['v'][i], - ]); + ms ? ohlcvs[t][i] : (ohlcvs[t][i] * 1000), + ohlcvs[o][i], + ohlcvs[h][i], + ohlcvs[l][i], + ohlcvs[c][i], + ohlcvs[v][i], + ]) } - return result; + return result } - convertOHLCVToTradingView (ohlcvs) { - const result = { - 't': [], - 'o': [], - 'h': [], - 'l': [], - 'c': [], - 'v': [], - }; + convertOHLCVToTradingView (ohlcvs, t = 't', o = 'o', h = 'h', l = 'l', c = 'c', v = 'v', ms = false) { + const result = {} + result[t] = [] + result[o] = [] + result[h] = [] + result[l] = [] + result[c] = [] + result[v] = [] for (let i = 0; i < ohlcvs.length; i++) { - result['t'].push (parseInt (ohlcvs[i][0] / 1000)); - result['o'].push (ohlcvs[i][1]); - result['h'].push (ohlcvs[i][2]); - result['l'].push (ohlcvs[i][3]); - result['c'].push (ohlcvs[i][4]); - result['v'].push (ohlcvs[i][5]); + result[t].push (ms ? ohlcvs[i][0] : parseInt (ohlcvs[i][0] / 1000)) + result[o].push (ohlcvs[i][1]) + result[h].push (ohlcvs[i][2]) + result[l].push (ohlcvs[i][3]) + result[c].push (ohlcvs[i][4]) + result[v].push (ohlcvs[i][5]) } - return result; + return result } fetchTicker (symbol, params = {}) { @@ -4417,8 +5575,8 @@ module.exports = class Exchange { async fetchStatus (params = {}) { if (this.has['fetchTime']) { - const time = await this.fetchTime(params) - return this.status = this.extend(this.status, { + const time = await this.fetchTime (params) + this.status = this.extend (this.status, { 'updated': time, }) } @@ -4450,27 +5608,34 @@ module.exports = class Exchange { return this.markets; } - filterBySinceLimit (array, since = undefined, limit = undefined, key = 'timestamp') { - if (since !== undefined && since !== null) - array = array.filter (entry => entry[key] >= since) - if (limit !== undefined && limit !== null) - array = array.slice (0, limit) + filterBySinceLimit (array, since = undefined, limit = undefined, key = 'timestamp', tail = false) { + const sinceIsDefined = (since !== undefined && since !== null) + if (sinceIsDefined) { + array = array.filter ((entry) => entry[key] >= since) + } + if (limit !== undefined && limit !== null) { + array = (tail && !sinceIsDefined) ? array.slice (-limit) : array.slice (0, limit) + } return array } - filterByValueSinceLimit (array, field, value = undefined, since = undefined, limit = undefined) { + filterByValueSinceLimit (array, field, value = undefined, since = undefined, limit = undefined, key = 'timestamp', tail = false) { const valueIsDefined = value !== undefined && value !== null const sinceIsDefined = since !== undefined && since !== null // single-pass filter for both symbol and since - if (valueIsDefined || sinceIsDefined) - array = Object.values (array).filter (entry => - ((valueIsDefined ? (entry[field] === value) : true) && - (sinceIsDefined ? (entry.timestamp >= since) : true))) + if (valueIsDefined || sinceIsDefined) { + array = Object.values (array).filter ((entry) => + ((valueIsDefined ? (entry[field] === value) : true) && + (sinceIsDefined ? (entry[key] >= since) : true))) + } - if (limit !== undefined && limit !== null) - array = Object.values (array).slice (0, limit) + if (limit !== undefined && limit !== null) { + array = ((tail && !sinceIsDefined) ? + Object.values (array).slice (-limit) : + Object.values (array).slice (0, limit)) + } return array } @@ -4488,13 +5653,15 @@ module.exports = class Exchange { objects = Object.values (objects) // return all of them if no values were passed - if (values === undefined || values === null) + if (values === undefined || values === null) { return indexed ? indexBy (objects, key) : objects + } const result = [] for (let i = 0; i < objects.length; i++) { - if (values.includes (objects[i][key])) + if (values.includes (objects[i][key])) { result.push (objects[i]) + } } return indexed ? indexBy (result, key) : result @@ -4505,7 +5672,7 @@ module.exports = class Exchange { // if (!this.isArray (trades)) { // throw new ExchangeError (this.id + ' parseTrades expected an array in the trades argument, but got ' + typeof trades); // } - let result = Object.values (trades || []).map (trade => this.extend (this.parseTrade (trade, market), params)) + let result = Object.values (trades || []).map ((trade) => this.extend (this.parseTrade (trade, market), params)) result = sortBy (result, 'timestamp') const symbol = (market !== undefined) ? market['symbol'] : undefined return this.filterBySymbolSinceLimit (result, symbol, since, limit) @@ -4516,7 +5683,7 @@ module.exports = class Exchange { // if (!this.isArray (transactions)) { // throw new ExchangeError (this.id + ' parseTransactions expected an array in the transactions argument, but got ' + typeof transactions); // } - let result = Object.values (transactions || []).map (transaction => this.extend (this.parseTransaction (transaction, currency), params)) + let result = Object.values (transactions || []).map ((transaction) => this.extend (this.parseTransaction (transaction, currency), params)) result = this.sortBy (result, 'timestamp'); const code = (currency !== undefined) ? currency['code'] : undefined; return this.filterByCurrencySinceLimit (result, code, since, limit); @@ -4672,97 +5839,32 @@ module.exports = class Exchange { // ------------------------------------------------------------------------ // web3 / 0x methods static hasWeb3 () { - return Web3 && ethUtil && ethAbi && BigNumber + return ethUtil && ethAbi } checkRequiredDependencies () { if (!Exchange.hasWeb3 ()) { - throw new ExchangeError ("Required dependencies missing: \nnpm i web3 ethereumjs-util ethereumjs-abi bignumber.js --no-save"); + throw new ExchangeError ('Required dependencies missing: \nnpm i ethereumjs-util ethereumjs-abi --no-save'); } } - ethDecimals (unit = 'ether') { - const units = { - 'wei': 0, // 1 - 'kwei': 3, // 1000 - 'babbage': 3, // 1000 - 'femtoether': 3, // 1000 - 'mwei': 6, // 1000000 - 'lovelace': 6, // 1000000 - 'picoether': 6, // 1000000 - 'gwei': 9, // 1000000000 - 'shannon': 9, // 1000000000 - 'nanoether': 9, // 1000000000 - 'nano': 9, // 1000000000 - 'szabo': 12, // 1000000000000 - 'microether': 12, // 1000000000000 - 'micro': 12, // 1000000000000 - 'finney': 15, // 1000000000000000 - 'milliether': 15, // 1000000000000000 - 'milli': 15, // 1000000000000000 - 'ether': 18, // 1000000000000000000 - 'kether': 21, // 1000000000000000000000 - 'grand': 21, // 1000000000000000000000 - 'mether': 24, // 1000000000000000000000000 - 'gether': 27, // 1000000000000000000000000000 - 'tether': 30, // 1000000000000000000000000000000 - } - return this.safeValue (units, unit) - } - - ethUnit (decimals = 18) { - const units = { - 0: 'wei', // 1000000000000000000 - 3: 'kwei', // 1000000000000000 - 6: 'mwei', // 1000000000000 - 9: 'gwei', // 1000000000 - 12: 'szabo', // 1000000 - 15: 'finney', // 1000 - 18: 'ether', // 1 - 21: 'kether', // 0.001 - 24: 'mether', // 0.000001 - 27: 'gether', // 0.000000001 - 30: 'tether', // 0.000000000001 - } - return this.safeValue (units, decimals) - } - - fromWei (amount, unit = 'ether', decimals = 18) { - if (amount === undefined) { - return amount - } - if (decimals !== 18) { - amount = new BigNumber (amount).times (new BigNumber (10 ** (18 - decimals))).toFixed () - } else { - amount = new BigNumber (amount).toFixed () - } - return parseFloat (this.web3.utils.fromWei (amount, unit)) - } - - toWei (amount, unit = 'ether', decimals = 18) { - if (amount === undefined) { - return amount - } - if (decimals !== 18) { - amount = new BigNumber (this.numberToString (amount)).div (new BigNumber (10 ** (18 - decimals))).toFixed () - } else { - amount = this.numberToString (amount) - } - return this.web3.utils.toWei (amount, unit) - } - soliditySha3 (array) { - const values = this.solidityValues (array); - const types = this.solidityTypes (values); - return '0x' + ethAbi.soliditySHA3 (types, values).toString ('hex') - } - - solidityTypes (array) { - return array.map (value => (this.web3.utils.isAddress (value) ? 'address' : 'uint256')) - } - - solidityValues (array) { - return array.map (value => (this.web3.utils.isAddress (value) ? value : (new BigNumber (value).toFixed ()))) + // we only support address, uint256, and string solidity types + const encoded = [] + for (const value of array) { + if (Number.isInteger (value) || value.match (/^[0-9]+$/)) { + encoded.push (this.numberToBE (this.numberToString (value), 32)) + } else { + const noPrefix = Exchange.remove0xPrefix (value) + if (noPrefix.length === 40 && noPrefix.toLowerCase ().match (/^[0-9a-f]+$/)) { // check if it is an address + encoded.push (this.base16ToBinary (noPrefix)) + } else { + encoded.push (this.stringToBinary (noPrefix)) + } + } + } + const concated = this.binaryConcatArray (encoded) + return '0x' + this.hash (concated, 'keccak', 'hex') } getZeroExOrderHash (order) { @@ -4848,15 +5950,6 @@ module.exports = class Exchange { ])).toString ('hex'); } - signZeroExOrder (order, privateKey) { - const orderHash = this.getZeroExOrderHash (order); - const signature = this.signMessage (orderHash, privateKey); - return this.extend (order, { - 'orderHash': orderHash, - 'ecSignature': signature, // todo fix v if needed - }) - } - signZeroExOrderV2 (order, privateKey) { const orderHash = this.getZeroExOrderHashV2 (order); const signature = this.signMessage (orderHash, privateKey); @@ -4928,7 +6021,7 @@ module.exports = class Exchange { }).call(this,require("buffer").Buffer) -},{"../static_dependencies/BN/bn":122,"./errors":9,"./functions":10,"buffer":180}],8:[function(require,module,exports){ +},{"../static_dependencies/BN/bn":120,"./errors":10,"./functions":11,"buffer":179}],9:[function(require,module,exports){ 'use strict'; const errorHierarchy = { @@ -4974,7 +6067,7 @@ const errorHierarchy = { module.exports = errorHierarchy; -},{}],9:[function(require,module,exports){ +},{}],10:[function(require,module,exports){ 'use strict'; const errorHierarchy = require ('./errorHierarchy.js') @@ -5027,7 +6120,7 @@ module.exports = subclass ( errorHierarchy ) -},{"./errorHierarchy.js":8}],10:[function(require,module,exports){ +},{"./errorHierarchy.js":9}],11:[function(require,module,exports){ 'use strict'; /* ------------------------------------------------------------------------ */ @@ -5057,7 +6150,7 @@ module.exports = unCamelCasePropertyNames (Object.assign ({} /* ------------------------------------------------------------------------ */ -},{"./functions/crypto":11,"./functions/encode":12,"./functions/generic":13,"./functions/misc":14,"./functions/number":15,"./functions/platform":16,"./functions/string":17,"./functions/throttle":18,"./functions/time":19,"./functions/type":20}],11:[function(require,module,exports){ +},{"./functions/crypto":12,"./functions/encode":13,"./functions/generic":14,"./functions/misc":15,"./functions/number":16,"./functions/platform":17,"./functions/string":18,"./functions/throttle":19,"./functions/time":20,"./functions/type":21}],12:[function(require,module,exports){ 'use strict' /* ------------------------------------------------------------------------ */ @@ -5206,7 +6299,7 @@ module.exports = { /* ------------------------------------------------------------------------ */ -},{"../../static_dependencies/BN/bn.js":122,"../../static_dependencies/crypto-js/crypto-js":123,"./../../static_dependencies/elliptic/lib/elliptic":124,"./../../static_dependencies/node-rsa/NodeRSA":139,"./../errors":9,"./encode":12,"./string":17}],12:[function(require,module,exports){ +},{"../../static_dependencies/BN/bn.js":120,"../../static_dependencies/crypto-js/crypto-js":121,"./../../static_dependencies/elliptic/lib/elliptic":122,"./../../static_dependencies/node-rsa/NodeRSA":137,"./../errors":10,"./encode":13,"./string":18}],13:[function(require,module,exports){ "use strict"; /* ------------------------------------------------------------------------ */ @@ -5279,7 +6372,7 @@ module.exports['byteArrayToWordArray'] = byteArrayToWordArray /* ------------------------------------------------------------------------ */ -},{"../../static_dependencies/BN/bn":122,"../../static_dependencies/crypto-js/crypto-js":123,"../../static_dependencies/qs/index":155}],13:[function(require,module,exports){ +},{"../../static_dependencies/BN/bn":120,"../../static_dependencies/crypto-js/crypto-js":121,"../../static_dependencies/qs/index":153}],14:[function(require,module,exports){ "use strict"; /* ------------------------------------------------------------------------ */ @@ -5313,6 +6406,7 @@ module.exports = , index , ordered: x => x // a stub to keep assoc keys in order (in JS it does nothing, it's mostly for Python) , unique: x => Array.from (index (x)) + , arrayConcat: (a, b) => a.concat (b) /* ............................................. */ @@ -5481,7 +6575,7 @@ module.exports = return out } - + return x } @@ -5499,22 +6593,19 @@ module.exports = /* ............................................. */ , deepExtend: function deepExtend (...xs) { - let out = undefined - for (const x of xs) { - if (isDictionary (x)) { - - if (!isObject (out)) + if (!isObject (out)) { out = {} - - for (const k in x) + } + for (const k in x) { out[k] = deepExtend (out[k], x[k]) - - } else out = x + } + } else { + out = x + } } - return out } @@ -5522,7 +6613,7 @@ module.exports = } -},{"./type":20}],14:[function(require,module,exports){ +},{"./type":21}],15:[function(require,module,exports){ 'use strict'; const { ROUND_UP, ROUND_DOWN } = require ('./number') @@ -5655,7 +6746,7 @@ module.exports = { /* ------------------------------------------------------------------------ */ -},{"./../errors":9,"./number":15}],15:[function(require,module,exports){ +},{"./../errors":10,"./number":16}],16:[function(require,module,exports){ 'use strict' /* ------------------------------------------------------------------------ @@ -5764,9 +6855,13 @@ const decimalToPrecision = (x, roundingMode /* handle tick size */ if (countingMode === TICK_SIZE) { - const missing = x % numPrecisionDigits - const reminder = x / numPrecisionDigits - if (reminder !== Math.floor (reminder)) { + const precisionDigitsString = decimalToPrecision (numPrecisionDigits, ROUND, 100, DECIMAL_PLACES, NO_PADDING) + const newNumPrecisionDigits = precisionFromString (precisionDigitsString) + let missing = x % numPrecisionDigits + // See: https://github.com/ccxt/ccxt/pull/6486 + missing = Number (decimalToPrecision (missing, ROUND, 8, DECIMAL_PLACES, NO_PADDING)); + const fpError = decimalToPrecision (missing / numPrecisionDigits, ROUND, Math.max (newNumPrecisionDigits, 8), DECIMAL_PLACES, NO_PADDING) + if (precisionFromString (fpError) !== 0) { if (roundingMode === ROUND) { if (x > 0) { if (missing >= numPrecisionDigits / 2) { @@ -5785,8 +6880,6 @@ const decimalToPrecision = (x, roundingMode x = x - missing } } - const precisionDigitsString = decimalToPrecision (numPrecisionDigits, ROUND, 100, DECIMAL_PLACES, NO_PADDING) - const newNumPrecisionDigits = precisionFromString (precisionDigitsString) return decimalToPrecision (x, ROUND, newNumPrecisionDigits, DECIMAL_PLACES, paddingMode); } @@ -5940,10 +7033,33 @@ const decimalToPrecision = (x, roundingMode return String.fromCharCode (...out) } +// toWei / fromWei + +function fromWei (amount, decimals = 18) { + if (amount === undefined) { + return amount + } + const exponential = Math.floor (amount).toExponential () // wei must be whole numbers + const [ n, exponent ] = exponential.split ('e') + const newExponent = parseInt (exponent) - decimals + return parseFloat (n + 'e' + newExponent) +} + +function toWei (amount, decimals = 18) { + if (amount === undefined) { + return amount + } + const exponential = parseFloat (amount).toExponential () + const [ n, exponent ] = exponential.split ('e') + const newExponent = parseInt (exponent) + decimals + return numberToString (Math.floor (parseFloat (n + 'e' + newExponent))) // wei must be whole numbers +} + /* ------------------------------------------------------------------------ */ module.exports = { - + toWei, + fromWei, numberToString, precisionFromString, decimalToPrecision, @@ -5963,7 +7079,7 @@ module.exports = { /* ------------------------------------------------------------------------ */ -},{}],16:[function(require,module,exports){ +},{}],17:[function(require,module,exports){ (function (process){ "use strict"; @@ -6004,7 +7120,7 @@ module.exports = { defaultFetch, } }).call(this,require('_process')) -},{"../../static_dependencies/fetch-ponyfill/fetch-node":137,"_process":202}],17:[function(require,module,exports){ +},{"../../static_dependencies/fetch-ponyfill/fetch-node":135,"_process":201}],18:[function(require,module,exports){ "use strict"; /* ------------------------------------------------------------------------ */ @@ -6027,7 +7143,7 @@ module.exports = /* ------------------------------------------------------------------------ */ -},{}],18:[function(require,module,exports){ +},{}],19:[function(require,module,exports){ "use strict"; /* ------------------------------------------------------------------------ */ @@ -6048,7 +7164,7 @@ module.exports = { const queue = [] - return Object.assign ((cost) => { + return Object.assign ((rateLimit, cost) => { if (queue.length > cfg.maxCapacity) throw new Error ('Backlog is over max capacity of ' + cfg.maxCapacity) @@ -6076,7 +7192,7 @@ module.exports = { const t = now () , elapsed = t - lastTimestamp lastTimestamp = t - numTokens = Math.min (cfg.capacity, numTokens + elapsed * cfg.refillRate) + numTokens = Math.min (cfg.capacity, numTokens + elapsed * (1 / rateLimit)) await sleep (cfg.delay) } running = false @@ -6093,7 +7209,7 @@ module.exports = { /* ------------------------------------------------------------------------ */ -},{"./time":19}],19:[function(require,module,exports){ +},{"./time":20}],20:[function(require,module,exports){ 'use strict'; /* ------------------------------------------------------------------------ */ @@ -6280,12 +7396,13 @@ module.exports = /* ------------------------------------------------------------------------ */ -},{}],20:[function(require,module,exports){ +},{}],21:[function(require,module,exports){ "use strict"; /* ------------------------------------------------------------------------ */ const isNumber = Number.isFinite + , isInteger = Number.isInteger , isArray = Array.isArray , hasProps = o => ((o !== undefined) && (o !== null)) , isString = s => (typeof s === 'string') @@ -6308,6 +7425,7 @@ const asFloat = x => ((isNumber (x) || isString (x)) ? parseFloat (x) : Na module.exports = { isNumber + , isInteger , isArray , isObject , isString @@ -6345,7 +7463,7 @@ module.exports = { /* ------------------------------------------------------------------------ */ -},{}],21:[function(require,module,exports){ +},{}],22:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -6377,7 +7495,7 @@ module.exports = class bcex extends Exchange { 'fetchTradingLimits': true, }, 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/43362240-21c26622-92ee-11e8-9464-5801ec526d77.jpg', + 'logo': 'https://user-images.githubusercontent.com/51840849/77231516-851c6900-6bac-11ea-8fd6-ee5c23eddbd4.jpg', 'api': 'https://www.bcex.top', 'www': 'https://www.bcex.top', 'doc': 'https://github.com/BCEX-TECHNOLOGY-LIMITED/API_Docs/wiki/Interface', @@ -6423,8 +7541,8 @@ module.exports = class bcex extends Exchange { 'trading': { 'tierBased': false, 'percentage': true, - 'buy': 0.0, - 'sell': 0.2 / 100, + 'maker': 0.1 / 100, + 'taker': 0.2 / 100, }, 'funding': { 'tierBased': false, @@ -6717,6 +7835,7 @@ module.exports = class bcex extends Exchange { 'cost': cost, 'order': orderId, 'fee': undefined, + 'takerOrMaker': undefined, }; } @@ -6865,6 +7984,8 @@ module.exports = class bcex extends Exchange { 'remaining': this.safeFloat (order, 'numberover'), 'status': status, 'fee': undefined, + 'clientOrderId': undefined, + 'trades': undefined, }; } @@ -6891,6 +8012,7 @@ module.exports = class bcex extends Exchange { const result = { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -6905,6 +8027,7 @@ module.exports = class bcex extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; return result; } @@ -7019,37 +8142,29 @@ module.exports = class bcex extends Exchange { } } } - - calculateFee (symbol, type, side, amount, price, takerOrMaker = 'taker', params = {}) { - const market = this.markets[symbol]; - const rate = market[side]; - const cost = parseFloat (this.costToPrecision (symbol, amount * price)); - return { - 'type': takerOrMaker, - 'currency': market['quote'], - 'rate': rate, - 'cost': parseFloat (this.feeToPrecision (symbol, rate * cost)), - }; - } }; -},{"./base/Exchange":7,"./base/errors":9}],22:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],23:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- -const hitbtc2 = require ('./hitbtc2'); +const hitbtc = require ('./hitbtc'); // --------------------------------------------------------------------------- -module.exports = class bequant extends hitbtc2 { +module.exports = class bequant extends hitbtc { describe () { return this.deepExtend (super.describe (), { 'id': 'bequant', 'name': 'Bequant', 'countries': [ 'MT' ], // Malta + 'pro': true, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/55248342-a75dfe00-525a-11e9-8aa2-05e9dca943c6.jpg', - 'api': 'https://api.bequant.io', + 'api': { + 'public': 'https://api.bequant.io', + 'private': 'https://api.bequant.io', + }, 'www': 'https://bequant.io', 'doc': [ 'https://api.bequant.io/', @@ -7063,7 +8178,7 @@ module.exports = class bequant extends hitbtc2 { } }; -},{"./hitbtc2":92}],23:[function(require,module,exports){ +},{"./hitbtc":90}],24:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -7112,14 +8227,14 @@ module.exports = class bibox extends Exchange { '1w': 'week', }, 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/34902611-2be8bf1a-f830-11e7-91a2-11b2f292e750.jpg', + 'logo': 'https://user-images.githubusercontent.com/51840849/77257418-3262b000-6c85-11ea-8fb8-20bdf20b3592.jpg', 'api': 'https://api.bibox.com', 'www': 'https://www.bibox.com', 'doc': [ 'https://biboxcom.github.io/en/', ], 'fees': 'https://bibox.zendesk.com/hc/en-us/articles/360002336133', - 'referral': 'https://www.bibox.com/signPage?id=11114745&lang=en', + 'referral': 'https://w2.bibox.com/login/register?invite_code=05Kj3I', }, 'api': { 'public': { @@ -7128,11 +8243,14 @@ module.exports = class bibox extends Exchange { 'mdata', ], 'get': [ + 'cquery', 'mdata', ], }, 'private': { 'post': [ + 'cquery', + 'ctrade', 'user', 'orderpending', 'transfer', @@ -7149,7 +8267,7 @@ module.exports = class bibox extends Exchange { 'tierBased': false, 'percentage': true, 'taker': 0.001, - 'maker': 0.001, + 'maker': 0.0008, }, 'funding': { 'tierBased': false, @@ -7776,6 +8894,7 @@ module.exports = class bibox extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -7790,6 +8909,7 @@ module.exports = class bibox extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; } @@ -8028,7 +9148,7 @@ module.exports = class bibox extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],24:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],25:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -8075,7 +9195,7 @@ module.exports = class bigone extends Exchange { '1w': 'week1', '1M': 'month1', }, - 'hostname': 'big.one', // set to 'b1.run' for China mainland + 'hostname': 'big.one', // or 'bigone.com' 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/69354403-1d532180-0c91-11ea-88ed-44c06cefdf87.jpg', 'api': { @@ -8766,6 +9886,7 @@ module.exports = class bigone extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -8953,7 +10074,7 @@ module.exports = class bigone extends Exchange { // } // const trades = this.safeValue (response, 'data', []); - return this.parseTrades (trades, market, since, limit, params); + return this.parseTrades (trades, market, since, limit); } parseOrderStatus (status) { @@ -9285,14 +10406,14 @@ module.exports = class bigone extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],25:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],26:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, InvalidAddress } = require ('./base/errors'); -const { ROUND } = require ('./base/functions/number'); +const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, InvalidAddress, RateLimitExceeded, PermissionDenied } = require ('./base/errors'); +const { ROUND, TRUNCATE } = require ('./base/functions/number'); // --------------------------------------------------------------------------- @@ -9304,6 +10425,7 @@ module.exports = class binance extends Exchange { 'countries': [ 'JP', 'MT' ], // Japan, Malta 'rateLimit': 500, 'certified': true, + 'pro': true, // new metainfo interface 'has': { 'fetchDepositAddress': true, @@ -9408,6 +10530,15 @@ module.exports = class binance extends Exchange { 'sub-account/margin/account', 'sub-account/margin/accountSummary', 'sub-account/status', + // lending endpoints + 'lending/daily/product/list', + 'lending/daily/userLeftQuota', + 'lending/daily/userRedemptionQuota', + 'lending/daily/token/position', + 'lending/union/account', + 'lending/union/purchaseRecord', + 'lending/union/redemptionRecord', + 'lending/union/interestHistory', ], 'post': [ 'asset/dust', @@ -9423,6 +10554,9 @@ module.exports = class binance extends Exchange { 'sub-account/futures/enable', 'userDataStream', 'futures/transfer', + // lending + 'lending/daily/purchase', + 'lending/daily/redeem', ], 'put': [ 'userDataStream', @@ -9462,18 +10596,20 @@ module.exports = class binance extends Exchange { 'historicalTrades', 'aggTrades', 'klines', + 'fundingRate', 'premiumIndex', 'ticker/24hr', 'ticker/price', 'ticker/bookTicker', + 'allForceOrders', + 'openInterest', + 'leverageBracket', ], - 'put': [ 'listenKey' ], - 'post': [ 'listenKey' ], - 'delete': [ 'listenKey' ], }, 'fapiPrivate': { 'get': [ 'allOrders', + 'openOrder', 'openOrders', 'order', 'account', @@ -9488,10 +10624,15 @@ module.exports = class binance extends Exchange { 'marginType', 'order', 'leverage', + 'listenKey', + ], + 'put': [ + 'listenKey', ], 'delete': [ 'order', 'allOpenOrders', + 'listenKey', ], }, 'v3': { @@ -9554,7 +10695,7 @@ module.exports = class binance extends Exchange { }, // exchange-specific options 'options': { - 'fetchTradesMethod': 'publicGetAggTrades', + 'fetchTradesMethod': 'publicGetAggTrades', // publicGetTrades, publicGetHistoricalTrades 'fetchTickersMethod': 'publicGetTicker24hr', 'defaultTimeInForce': 'GTC', // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel 'defaultLimitOrderType': 'limit', // or 'limit_maker' @@ -9575,7 +10716,10 @@ module.exports = class binance extends Exchange { 'Order would trigger immediately.': InvalidOrder, 'Account has insufficient balance for requested action.': InsufficientFunds, 'Rest API trading is not enabled.': ExchangeNotAvailable, + "You don't have permission.": PermissionDenied, // {"msg":"You don't have permission.","success":false} + 'Market is closed.': ExchangeNotAvailable, // {"code":-1013,"msg":"Market is closed."} '-1000': ExchangeNotAvailable, // {"code":-1000,"msg":"An unknown error occured while processing the request."} + '-1003': RateLimitExceeded, // {"code":-1003,"msg":"Too much request weight used, current limit is 1200 request weight per 1 MINUTE. Please use the websocket for live updates to avoid polling the API."} '-1013': InvalidOrder, // createOrder -> 'invalid quantity'/'invalid price'/MIN_NOTIONAL '-1021': InvalidNonce, // 'your time is ahead of server' '-1022': AuthenticationError, // {"code":-1022,"msg":"Signature for this request is not valid."} @@ -9599,13 +10743,13 @@ module.exports = class binance extends Exchange { const type = this.safeString2 (this.options, 'fetchTime', 'defaultType', 'spot'); const method = (type === 'spot') ? 'publicGetTime' : 'fapiPublicGetTime'; const response = await this[method] (params); - return this.safeFloat (response, 'serverTime'); + return this.safeInteger (response, 'serverTime'); } async loadTimeDifference () { const serverTime = await this.fetchTime (); const after = this.milliseconds (); - this.options['timeDifference'] = parseInt (after - serverTime); + this.options['timeDifference'] = after - serverTime; return this.options['timeDifference']; } @@ -9702,6 +10846,7 @@ module.exports = class binance extends Exchange { const spot = !future; const marketType = spot ? 'spot' : 'future'; const id = this.safeString (market, 'symbol'); + const lowercaseId = this.safeStringLower (market, 'symbol'); const baseId = market['baseAsset']; const quoteId = market['quoteAsset']; const base = this.safeCurrencyCode (baseId); @@ -9718,6 +10863,7 @@ module.exports = class binance extends Exchange { const active = (status === 'TRADING'); const entry = { 'id': id, + 'lowercaseId': lowercaseId, 'symbol': symbol, 'base': base, 'quote': quote, @@ -9769,6 +10915,13 @@ module.exports = class binance extends Exchange { 'max': this.safeFloat (filter, 'maxQty'), }; } + if ('MARKET_LOT_SIZE' in filters) { + const filter = this.safeValue (filters, 'MARKET_LOT_SIZE', {}); + entry['limits']['market'] = { + 'min': this.safeFloat (filter, 'minQty'), + 'max': this.safeFloat (filter, 'maxQty'), + }; + } if ('MIN_NOTIONAL' in filters) { entry['limits']['cost']['min'] = this.safeFloat (filters['MIN_NOTIONAL'], 'minNotional'); } @@ -9943,7 +11096,7 @@ module.exports = class binance extends Exchange { } async fetchStatus (params = {}) { - const response = await this.wapiGetSystemStatus (); + const response = await this.wapiGetSystemStatus (params); let status = this.safeValue (response, 'status'); if (status !== undefined) { status = (status === 0) ? 'ok' : 'maintenance'; @@ -10153,13 +11306,23 @@ module.exports = class binance extends Exchange { // 'endTime': 789, // Timestamp in ms to get aggregate trades until INCLUSIVE. // 'limit': 500, // default = 500, maximum = 1000 }; - if (this.options['fetchTradesMethod'] === 'publicGetAggTrades') { + const defaultType = this.safeString2 (this.options, 'fetchTrades', 'defaultType', 'spot'); + const type = this.safeString (params, 'type', defaultType); + const query = this.omit (params, 'type'); + const defaultMethod = (type === 'future') ? 'fapiPublicGetTrades' : 'publicGetTrades'; + let method = this.safeString (this.options, 'fetchTradesMethod', defaultMethod); + if (method === 'publicGetAggTrades') { if (since !== undefined) { request['startTime'] = since; // https://github.com/ccxt/ccxt/issues/6400 // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#compressedaggregate-trades-list request['endTime'] = this.sum (since, 3600000); } + if (type === 'future') { + method = 'fapiPublicGetAggTrades'; + } + } else if ((method === 'publicGetHistoricalTrades') && (type === 'future')) { + method = 'fapiPublicGetHistoricalTrades'; } if (limit !== undefined) { request['limit'] = limit; // default = 500, maximum = 1000 @@ -10173,8 +11336,7 @@ module.exports = class binance extends Exchange { // - 'tradeId' accepted and returned by this method is "aggregate" trade id // which is different from actual trade id // - setting both fromId and time window results in error - const method = this.safeValue (this.options, 'fetchTradesMethod', 'publicGetTrades'); - const response = await this[method] (this.extend (request, params)); + const response = await this[method] (this.extend (request, query)); // // aggregate trades // @@ -10221,6 +11383,46 @@ module.exports = class binance extends Exchange { } parseOrder (order, market = undefined) { + // + // spot + // + // { + // "symbol": "LTCBTC", + // "orderId": 1, + // "clientOrderId": "myOrder1", + // "price": "0.1", + // "origQty": "1.0", + // "executedQty": "0.0", + // "cummulativeQuoteQty": "0.0", + // "status": "NEW", + // "timeInForce": "GTC", + // "type": "LIMIT", + // "side": "BUY", + // "stopPrice": "0.0", + // "icebergQty": "0.0", + // "time": 1499827319559, + // "updateTime": 1499827319559, + // "isWorking": true + // } + // + // futures + // + // { + // "symbol": "BTCUSDT", + // "orderId": 1, + // "clientOrderId": "myOrder1", + // "price": "0.1", + // "origQty": "1.0", + // "executedQty": "1.0", + // "cumQuote": "10.0", + // "status": "NEW", + // "timeInForce": "GTC", + // "type": "LIMIT", + // "side": "BUY", + // "stopPrice": "0.0", + // "updateTime": 1499827319559 + // } + // const status = this.parseOrderStatus (this.safeString (order, 'status')); let symbol = undefined; const marketId = this.safeString (order, 'symbol'); @@ -10305,9 +11507,11 @@ module.exports = class binance extends Exchange { cost = parseFloat (this.costToPrecision (symbol, cost)); } } + const clientOrderId = this.safeString (order, 'clientOrderId'); return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -10350,10 +11554,12 @@ module.exports = class binance extends Exchange { }; if (uppercaseType === 'MARKET') { const quoteOrderQty = this.safeFloat (params, 'quoteOrderQty'); + const precision = market['precision']['price']; if (quoteOrderQty !== undefined) { - request['quoteOrderQty'] = this.costToPrecision (symbol, quoteOrderQty); + request['quoteOrderQty'] = this.decimalToPrecision (quoteOrderQty, TRUNCATE, precision, this.precisionMode); + params = this.omit (params, 'quoteOrderQty'); } else if (price !== undefined) { - request['quoteOrderQty'] = this.costToPrecision (symbol, amount * price); + request['quoteOrderQty'] = this.decimalToPrecision (amount * price, TRUNCATE, precision, this.precisionMode); } else { request['quantity'] = this.amountToPrecision (symbol, amount); } @@ -10371,6 +11577,9 @@ module.exports = class binance extends Exchange { timeInForceIsRequired = true; } else if ((uppercaseType === 'STOP_LOSS') || (uppercaseType === 'TAKE_PROFIT')) { stopPriceIsRequired = true; + if (market['future']) { + priceIsRequired = true; + } } else if ((uppercaseType === 'STOP_LOSS_LIMIT') || (uppercaseType === 'TAKE_PROFIT_LIMIT')) { stopPriceIsRequired = true; priceIsRequired = true; @@ -10522,11 +11731,18 @@ module.exports = class binance extends Exchange { } await this.loadMarkets (); const market = this.market (symbol); + // https://github.com/ccxt/ccxt/issues/6507 + const origClientOrderId = this.safeValue (params, 'origClientOrderId'); const request = { 'symbol': market['id'], - 'orderId': parseInt (id), + // 'orderId': parseInt (id), // 'origClientOrderId': id, }; + if (origClientOrderId === undefined) { + request['orderId'] = parseInt (id); + } else { + request['origClientOrderId'] = origClientOrderId; + } const method = market['spot'] ? 'privateDeleteOrder' : 'fapiPrivateDeleteOrder'; const response = await this[method] (this.extend (request, params)); return this.parseOrder (response); @@ -10706,6 +11922,8 @@ module.exports = class binance extends Exchange { } if (since !== undefined) { request['startTime'] = since; + // max 3 months range https://github.com/ccxt/ccxt/issues/6495 + request['endTime'] = this.sum (since, 7776000000); } const response = await this.wapiGetDepositHistory (this.extend (request, params)); // @@ -10731,6 +11949,8 @@ module.exports = class binance extends Exchange { } if (since !== undefined) { request['startTime'] = since; + // max 3 months range https://github.com/ccxt/ccxt/issues/6495 + request['endTime'] = this.sum (since, 7776000000); } const response = await this.wapiGetWithdrawHistory (this.extend (request, params)); // @@ -11014,7 +12234,7 @@ module.exports = class binance extends Exchange { if (api === 'wapi') { url += '.html'; } - const userDataStream = ((path === 'userDataStream') || (path === 'listenKey')); + const userDataStream = (path === 'userDataStream') || (path === 'listenKey'); if (path === 'historicalTrades') { if (this.apiKey) { headers = { @@ -11118,9 +12338,13 @@ module.exports = class binance extends Exchange { // checks against error codes const error = this.safeString (response, 'code'); if (error !== undefined) { + // https://github.com/ccxt/ccxt/issues/6501 + if (error === '200') { + return; + } // a workaround for {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."} // despite that their message is very confusing, it is raised by Binance - // on a temporary ban (the API key is valid, but disabled for a while) + // on a temporary ban, the API key is valid, but disabled for a while if ((error === '-2015') && this.options['hasAlreadyAuthenticatedSuccessfully']) { throw new DDoSProtection (this.id + ' temporary banned: ' + body); } @@ -11145,7 +12369,7 @@ module.exports = class binance extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],26:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],27:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -11161,6 +12385,7 @@ module.exports = class binanceje extends binance { 'name': 'Binance Jersey', 'countries': [ 'JE' ], // Jersey 'certified': false, + 'pro': true, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/54874009-d526eb00-4df3-11e9-928c-ce6a2b914cd1.jpg', 'api': { @@ -11199,7 +12424,7 @@ module.exports = class binanceje extends binance { }; -},{"./binance.js":25}],27:[function(require,module,exports){ +},{"./binance.js":26}],28:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -11215,6 +12440,7 @@ module.exports = class binanceus extends binance { 'name': 'Binance US', 'countries': [ 'US' ], // US 'certified': false, + 'pro': true, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/65177307-217b7c80-da5f-11e9-876e-0b748ba0a358.jpg', 'api': { @@ -11243,7 +12469,7 @@ module.exports = class binanceus extends binance { }; -},{"./binance.js":25}],28:[function(require,module,exports){ +},{"./binance.js":26}],29:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -11525,6 +12751,7 @@ module.exports = class bit2c extends Exchange { const status = this.safeString (order, 'status'); return { 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -11540,6 +12767,7 @@ module.exports = class bit2c extends Exchange { 'trades': undefined, 'fee': undefined, 'info': order, + 'average': undefined, }; } @@ -11663,7 +12891,7 @@ module.exports = class bit2c extends Exchange { }; -},{"./base/Exchange":7,"./base/errors":9}],29:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],30:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -11979,6 +13207,7 @@ module.exports = class bitbank extends Exchange { const side = this.safeStringLower (order, 'side'); return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -12231,13 +13460,13 @@ module.exports = class bitbank extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],30:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],31:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { InvalidNonce, InsufficientFunds, AuthenticationError, InvalidOrder, ExchangeError, OrderNotFound } = require ('./base/errors'); +const { InvalidNonce, InsufficientFunds, AuthenticationError, InvalidOrder, ExchangeError, OrderNotFound, AccountSuspended, BadSymbol, OrderImmediatelyFillable, RateLimitExceeded } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -12253,6 +13482,22 @@ module.exports = class bitbay extends Exchange { 'withdraw': true, 'fetchMyTrades': true, 'fetchOpenOrders': true, + 'fetchOHLCV': true, + }, + 'timeframes': { + '1m': '60', + '3m': '180', + '5m': '300', + '15m': '900', + '30m': '1800', + '1h': '3600', + '2h': '7200', + '4h': '14400', + '6h': '21600', + '12h': '43200', + '1d': '86400', + '3d': '259200', + '1w': '604800', }, 'urls': { 'referral': 'https://auth.bitbay.net/ref/jHlbB4mIkdS1', @@ -12368,13 +13613,15 @@ module.exports = class bitbay extends Exchange { '503': InvalidNonce, // Invalid moment parameter. Request time doesn't match current server time '504': ExchangeError, // Invalid method '505': AuthenticationError, // Key has no permission for this action - '506': AuthenticationError, // Account locked. Please contact with customer service + '506': AccountSuspended, // Account locked. Please contact with customer service // codes 507 and 508 are not specified in their docs '509': ExchangeError, // The BIC/SWIFT is required for this currency - '510': ExchangeError, // Invalid market name + '510': BadSymbol, // Invalid market name 'FUNDS_NOT_SUFFICIENT': InsufficientFunds, 'OFFER_FUNDS_NOT_EXCEEDING_MINIMUMS': InvalidOrder, 'OFFER_NOT_FOUND': OrderNotFound, + 'OFFER_WOULD_HAVE_BEEN_PARTIALLY_FILLED': OrderImmediatelyFillable, + 'ACTION_LIMIT_EXCEEDED': RateLimitExceeded, }, }); } @@ -12506,6 +13753,7 @@ module.exports = class bitbay extends Exchange { } return { 'id': this.safeString (order, 'id'), + 'clientOrderId': undefined, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -12977,6 +14225,55 @@ module.exports = class bitbay extends Exchange { return this.safeString (types, type, type); } + parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) { + // [ + // '1582399800000', + // { + // o: '0.0001428', + // c: '0.0001428', + // h: '0.0001428', + // l: '0.0001428', + // v: '4', + // co: '1' + // } + // ] + return [ + parseInt (ohlcv[0]), + this.safeFloat (ohlcv[1], 'o'), + this.safeFloat (ohlcv[1], 'h'), + this.safeFloat (ohlcv[1], 'l'), + this.safeFloat (ohlcv[1], 'c'), + this.safeFloat (ohlcv[1], 'v'), + ]; + } + + async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const tradingSymbol = market['baseId'] + '-' + market['quoteId']; + const request = { + 'symbol': tradingSymbol, + 'resolution': this.timeframes[timeframe], + // 'from': 1574709092000, // unix timestamp in milliseconds, required + // 'to': 1574709092000, // unix timestamp in milliseconds, required + }; + if (limit === undefined) { + limit = 100; + } + const duration = this.parseTimeframe (timeframe); + const timerange = limit * duration * 1000; + if (since === undefined) { + request['to'] = this.milliseconds (); + request['from'] = request['to'] - timerange; + } else { + request['from'] = parseInt (since); + request['to'] = this.sum (request['from'], timerange); + } + const response = await this.v1_01PublicGetTradingCandleHistorySymbolResolution (this.extend (request, params)); + const ohlcvs = this.safeValue (response, 'items', []); + return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit); + } + parseTrade (trade, market = undefined) { // // createOrder trades @@ -13212,6 +14509,7 @@ module.exports = class bitbay extends Exchange { 'average': undefined, 'fee': undefined, 'trades': trades, + 'clientOrderId': undefined, }; } @@ -13378,7 +14676,7 @@ module.exports = class bitbay extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],31:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],32:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -13398,6 +14696,7 @@ module.exports = class bitfinex extends Exchange { 'version': 'v1', 'rateLimit': 1500, 'certified': true, + 'pro': true, // new metainfo interface 'has': { 'CORS': false, @@ -13655,6 +14954,7 @@ module.exports = class bitfinex extends Exchange { }, }, }, + // todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method 'commonCurrencies': { 'ABS': 'ABYSS', 'AIO': 'AION', @@ -13690,7 +14990,9 @@ module.exports = class bitfinex extends Exchange { 'UST': 'USDT', 'UTN': 'UTNP', 'VSY': 'VSYS', + 'WAX': 'WAXP', 'XCH': 'XCHF', + 'ZBT': 'ZB', }, 'exceptions': { 'exact': { @@ -13792,7 +15094,7 @@ module.exports = class bitfinex extends Exchange { 'YOYOW': 'yoyow', 'ZEC': 'zcash', 'ZRX': 'zrx', - 'XTZ': 'tezos', + 'XTZ': 'xtz', }, 'orderTypes': { 'limit': 'exchange limit', @@ -14007,6 +15309,7 @@ module.exports = class bitfinex extends Exchange { if (timestamp !== undefined) { timestamp *= 1000; } + timestamp = parseInt (timestamp); let symbol = undefined; if (market !== undefined) { symbol = market['symbol']; @@ -14221,6 +15524,7 @@ module.exports = class bitfinex extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -14234,6 +15538,8 @@ module.exports = class bitfinex extends Exchange { 'filled': this.safeFloat (order, 'executed_amount'), 'status': status, 'fee': undefined, + 'cost': undefined, + 'trades': undefined, }; } @@ -14308,6 +15614,7 @@ module.exports = class bitfinex extends Exchange { } getCurrencyName (code) { + // todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method if (code in this.options['currencyNames']) { return this.options['currencyNames'][code]; } @@ -14320,18 +15627,12 @@ module.exports = class bitfinex extends Exchange { 'renew': 1, }; const response = await this.fetchDepositAddress (code, this.extend (request, params)); - const address = this.safeString (response, 'address'); - this.checkAddress (address); - return { - 'info': response['info'], - 'currency': code, - 'address': address, - 'tag': undefined, - }; + return response; } async fetchDepositAddress (code, params = {}) { await this.loadMarkets (); + // todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method const name = this.getCurrencyName (code); const request = { 'method': name, @@ -14473,11 +15774,13 @@ module.exports = class bitfinex extends Exchange { async withdraw (code, amount, address, tag = undefined, params = {}) { this.checkAddress (address); + await this.loadMarkets (); + // todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method const name = this.getCurrencyName (code); const request = { 'withdraw_type': name, 'walletselected': 'exchange', - 'amount': amount.toString (), + 'amount': this.numberToString (amount), 'address': address, }; if (tag !== undefined) { @@ -14558,13 +15861,13 @@ module.exports = class bitfinex extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],32:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],33:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const bitfinex = require ('./bitfinex.js'); -const { ExchangeError, NotSupported, InsufficientFunds } = require ('./base/errors'); +const { ExchangeError, InvalidAddress, ArgumentsRequired, InsufficientFunds, AuthenticationError, OrderNotFound, InvalidOrder, BadRequest, InvalidNonce, BadSymbol, OnMaintenance } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -14576,21 +15879,29 @@ module.exports = class bitfinex2 extends bitfinex { 'countries': [ 'VG' ], 'version': 'v2', 'certified': false, + 'pro': false, // new metainfo interface 'has': { - 'CORS': true, - 'createLimitOrder': false, - 'createMarketOrder': false, - 'createOrder': false, + 'CORS': false, + 'cancelAllOrders': true, + 'createDepositAddress': true, + 'createLimitOrder': true, + 'createMarketOrder': true, + 'createOrder': true, + 'cancelOrder': true, 'deposit': false, 'editOrder': false, - 'fetchDepositAddress': false, + 'fetchDepositAddress': true, 'fetchClosedOrders': false, 'fetchFundingFees': false, 'fetchMyTrades': true, 'fetchOHLCV': true, - 'fetchOpenOrders': false, - 'fetchOrder': true, + 'fetchOpenOrders': true, + 'fetchOrder': false, + 'fetchOpenOrder': true, + 'fetchClosedOrder': true, + 'fetchOrderTrades': true, + 'fetchStatus': true, 'fetchTickers': true, 'fetchTradingFee': false, 'fetchTradingFees': false, @@ -14635,7 +15946,30 @@ module.exports = class bitfinex2 extends bitfinex { }, 'public': { 'get': [ - 'conf/pub:map:currency:label', + 'conf/{config}', + 'conf/pub:{action}:{object}', + 'conf/pub:{action}:{object}:{detail}', + 'conf/pub:map:{object}', + 'conf/pub:map:{object}:{detail}', + 'conf/pub:map:currency:{detail}', + 'conf/pub:map:currency:sym', // maps symbols to their API symbols, BAB > BCH + 'conf/pub:map:currency:label', // verbose friendly names, BNT > Bancor + 'conf/pub:map:currency:unit', // maps symbols to unit of measure where applicable + 'conf/pub:map:currency:undl', // maps derivatives symbols to their underlying currency + 'conf/pub:map:currency:pool', // maps symbols to underlying network/protocol they operate on + 'conf/pub:map:currency:explorer', // maps symbols to their recognised block explorer URLs + 'conf/pub:map:tx:method', + 'conf/pub:list:{object}', + 'conf/pub:list:{object}:{detail}', + 'conf/pub:list:currency', + 'conf/pub:list:pair:exchange', + 'conf/pub:list:pair:margin', + 'conf/pub:list:competitions', + 'conf/pub:info:{object}', + 'conf/pub:info:{object}:{detail}', + 'conf/pub:info:pair', + 'conf/pub:info:tx:status', // [ deposit, withdrawal ] statuses 1 = active, 0 = maintenance + 'conf/pub:fees', 'platform/status', 'tickers', 'ticker/{symbol}', @@ -14647,7 +15981,11 @@ module.exports = class bitfinex2 extends bitfinex { 'book/{symbol}/P3', 'book/{symbol}/R0', 'stats1/{key}:{size}:{symbol}:{side}/{section}', + 'stats1/{key}:{size}:{symbol}:{side}/last', + 'stats1/{key}:{size}:{symbol}:{side}/hist', 'stats1/{key}:{size}:{symbol}/{section}', + 'stats1/{key}:{size}:{symbol}/last', + 'stats1/{key}:{size}:{symbol}/hist', 'stats1/{key}:{size}:{symbol}:long/last', 'stats1/{key}:{size}:{symbol}:long/hist', 'stats1/{key}:{size}:{symbol}:short/last', @@ -14655,6 +15993,11 @@ module.exports = class bitfinex2 extends bitfinex { 'candles/trade:{timeframe}:{symbol}/{section}', 'candles/trade:{timeframe}:{symbol}/last', 'candles/trade:{timeframe}:{symbol}/hist', + 'status/{type}', + 'status/deriv', + 'liquidations/hist', + 'rankings/{key}:{timeframe}:{symbol}/{section}', + 'rankings/{key}:{timeframe}:{symbol}/hist', ], 'post': [ 'calc/trade/avg', @@ -14663,39 +16006,69 @@ module.exports = class bitfinex2 extends bitfinex { }, 'private': { 'post': [ + // 'auth/r/orders/{symbol}/new', // outdated + // 'auth/r/stats/perf:{timeframe}/hist', // outdated 'auth/r/wallets', + 'auth/r/wallets/hist', + 'auth/r/orders', 'auth/r/orders/{symbol}', - 'auth/r/orders/{symbol}/new', - 'auth/r/orders/{symbol}/hist', - 'auth/r/order/{symbol}:{id}/trades', 'auth/w/order/submit', - 'auth/r/trades/hist', + 'auth/w/order/update', + 'auth/w/order/cancel', + 'auth/w/order/multi', + 'auth/w/order/cancel/multi', + 'auth/r/orders/{symbol}/hist', + 'auth/r/orders/hist', + 'auth/r/order/{symbol}:{id}/trades', 'auth/r/trades/{symbol}/hist', + 'auth/r/trades/hist', + 'auth/r/ledgers/{currency}/hist', + 'auth/r/ledgers/hist', + 'auth/r/info/margin/{key}', + 'auth/r/info/margin/base', + 'auth/r/info/margin/sym_all', 'auth/r/positions', + 'auth/w/position/claim', 'auth/r/positions/hist', 'auth/r/positions/audit', + 'auth/w/deriv/collateral/set', + 'auth/r/funding/offers', 'auth/r/funding/offers/{symbol}', + 'auth/w/funding/offer/submit', + 'auth/w/funding/offer/cancel', + 'auth/w/funding/offer/cancel/all', + 'auth/w/funding/close', + 'auth/w/funding/auto', + 'auth/w/funding/keep', 'auth/r/funding/offers/{symbol}/hist', + 'auth/r/funding/offers/hist', + 'auth/r/funding/loans', + 'auth/r/funding/loans/hist', 'auth/r/funding/loans/{symbol}', 'auth/r/funding/loans/{symbol}/hist', + 'auth/r/funding/credits', + 'auth/r/funding/credits/hist', 'auth/r/funding/credits/{symbol}', 'auth/r/funding/credits/{symbol}/hist', 'auth/r/funding/trades/{symbol}/hist', - 'auth/r/info/margin/{key}', + 'auth/r/funding/trades/hist', 'auth/r/info/funding/{key}', - 'auth/r/ledgers/hist', - 'auth/r/movements/hist', + 'auth/r/info/user', + 'auth/r/logins/hist', + 'auth/w/transfer', + 'auth/w/deposit/address', + 'auth/w/deposit/invoice', + 'auth/w/withdraw', 'auth/r/movements/{currency}/hist', - 'auth/r/stats/perf:{timeframe}/hist', + 'auth/r/movements/hist', 'auth/r/alerts', 'auth/w/alert/set', + 'auth/w/alert/price:{symbol}:{price}/del', 'auth/w/alert/{type}:{symbol}:{price}/del', 'auth/calc/order/avail', - 'auth/r/ledgers/{symbol}/hist', - 'auth/r/settings', 'auth/w/settings/set', + 'auth/r/settings', 'auth/w/settings/del', - 'auth/r/info/user', ], }, }, @@ -14738,21 +16111,31 @@ module.exports = class bitfinex2 extends bitfinex { }, 'options': { 'precision': 'R0', // P0, P1, P2, P3, P4, R0 - 'orderTypes': { - 'MARKET': undefined, + // convert 'EXCHANGE MARKET' to lowercase 'market' + // convert 'EXCHANGE LIMIT' to lowercase 'limit' + // everything else remains uppercase + 'exchangeTypes': { + // 'MARKET': undefined, 'EXCHANGE MARKET': 'market', - 'LIMIT': undefined, + // 'LIMIT': undefined, 'EXCHANGE LIMIT': 'limit', - 'STOP': undefined, - 'EXCHANGE STOP': 'stopOrLoss', - 'TRAILING STOP': undefined, - 'EXCHANGE TRAILING STOP': undefined, - 'FOK': undefined, - 'EXCHANGE FOK': 'limit FOK', - 'STOP LIMIT': undefined, - 'EXCHANGE STOP LIMIT': 'limit stop', - 'IOC': undefined, - 'EXCHANGE IOC': 'limit ioc', + // 'STOP': undefined, + // 'EXCHANGE STOP': undefined, + // 'TRAILING STOP': undefined, + // 'EXCHANGE TRAILING STOP': undefined, + // 'FOK': undefined, + // 'EXCHANGE FOK': undefined, + // 'STOP LIMIT': undefined, + // 'EXCHANGE STOP LIMIT': undefined, + // 'IOC': undefined, + // 'EXCHANGE IOC': undefined, + }, + // convert 'market' to 'EXCHANGE MARKET' + // convert 'limit' 'EXCHANGE LIMIT' + // everything else remains as is + 'orderTypes': { + 'market': 'EXCHANGE MARKET', + 'limit': 'EXCHANGE LIMIT', }, 'fiat': { 'USD': 'USD', @@ -14761,6 +16144,22 @@ module.exports = class bitfinex2 extends bitfinex { 'GBP': 'GBP', }, }, + 'exceptions': { + 'exact': { + '10020': BadRequest, + '10100': AuthenticationError, + '10114': InvalidNonce, + '20060': OnMaintenance, + }, + 'broad': { + 'address': InvalidAddress, + 'available balance is only': InsufficientFunds, + 'not enough exchange balance': InsufficientFunds, + 'Order not found': OrderNotFound, + 'symbol: invalid': BadSymbol, + 'Invalid order': InvalidOrder, + }, + }, }); } @@ -14772,13 +16171,27 @@ module.exports = class bitfinex2 extends bitfinex { return 'f' + code; } + async fetchStatus (params = {}) { + // + // [1] // operative + // [0] // maintenance + // + const response = await this.publicGetPlatformStatus (params); + const status = this.safeValue (response, 0); + const formattedStatus = (status === 1) ? 'ok' : 'maintenance'; + this.status = this.extend (this.status, { + 'status': formattedStatus, + 'updated': this.milliseconds (), + }); + return this.status; + } + async fetchMarkets (params = {}) { const response = await this.v1GetSymbolsDetails (params); const result = []; for (let i = 0; i < response.length; i++) { const market = response[i]; - let id = this.safeString (market, 'pair'); - id = id.toUpperCase (); + let id = this.safeStringUpper (market, 'pair'); let baseId = undefined; let quoteId = undefined; if (id.indexOf (':') >= 0) { @@ -14968,6 +16381,26 @@ module.exports = class bitfinex2 extends bitfinex { return this.parseTicker (ticker, market); } + parseSymbol (marketId) { + if (marketId === undefined) { + return marketId; + } + marketId = marketId.replace ('t', ''); + let baseId = undefined; + let quoteId = undefined; + if (marketId.indexOf (':') >= 0) { + const parts = marketId.split (':'); + baseId = parts[0]; + quoteId = parts[1]; + } else { + baseId = marketId.slice (0, 3); + quoteId = marketId.slice (3, 6); + } + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + return base + '/' + quote; + } + parseTrade (trade, market = undefined) { // // fetchTrades (public) @@ -15014,26 +16447,34 @@ module.exports = class bitfinex2 extends bitfinex { const timestamp = trade[timestampIndex]; if (isPrivate) { const marketId = trade[1]; - if (marketId !== undefined) { - if (marketId in this.markets_by_id) { - market = this.markets_by_id[marketId]; - symbol = market['symbol']; - } else { - symbol = marketId; - } + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + symbol = this.parseSymbol (marketId); } orderId = trade[3].toString (); takerOrMaker = (trade[8] === 1) ? 'maker' : 'taker'; - const feeCost = trade[9]; + let feeCost = trade[9]; const feeCurrency = this.safeCurrencyCode (trade[10]); if (feeCost !== undefined) { + feeCost = -feeCost; + if (symbol in this.markets) { + feeCost = this.feeToPrecision (symbol, feeCost); + } else { + const currencyId = 'f' + feeCurrency; + if (currencyId in this.currencies_by_id) { + const currency = this.currencies_by_id[currencyId]; + feeCost = this.currencyToPrecision (currency['code'], feeCost); + } + } fee = { - 'cost': Math.abs (feeCost), + 'cost': parseFloat (feeCost), 'currency': feeCurrency, }; } const orderType = trade[6]; - type = this.safeString (this.options['orderTypes'], orderType); + type = this.safeString (this.options['exchangeTypes'], orderType); } if (symbol === undefined) { if (market !== undefined) { @@ -15116,24 +16557,252 @@ module.exports = class bitfinex2 extends bitfinex { return this.parseOHLCVs (response, market, timeframe, since, limit); } + parseOrderStatus (status) { + const statuses = { + 'ACTIVE': 'open', + 'PARTIALLY FILLED': 'open', + 'EXECUTED': 'closed', + 'CANCELED': 'canceled', + 'INSUFFICIENT MARGIN': 'canceled', + 'INSUFFICIENT BALANCE (G1) was: PARTIALLY FILLED': 'canceled', + 'RSN_DUST': 'rejected', + 'RSN_PAUSE': 'rejected', + }; + return this.safeString (statuses, status, status); + } + + parseOrder (order, market = undefined) { + const id = this.safeString (order, 0); + let symbol = undefined; + const marketId = this.safeString (order, 3); + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } else { + symbol = this.parseSymbol (marketId); + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + // https://github.com/ccxt/ccxt/issues/6686 + // const timestamp = this.safeTimestamp (order, 5); + const timestamp = this.safeInteger (order, 5); + const remaining = Math.abs (this.safeFloat (order, 6)); + const amount = Math.abs (this.safeFloat (order, 7)); + const filled = amount - remaining; + const side = (order[7] < 0) ? 'sell' : 'buy'; + const orderType = this.safeString (order, 8); + const type = this.safeString (this.safeValue (this.options, 'exchangeTypes'), orderType); + let status = undefined; + const statusString = this.safeString (order, 13); + if (statusString !== undefined) { + const parts = statusString.split (' @ '); + status = this.parseOrderStatus (this.safeString (parts, 0)); + } + const price = this.safeFloat (order, 16); + const average = this.safeFloat (order, 17); + const cost = price * filled; + const clientOrderId = this.safeString (order, 2); + return { + 'info': order, + 'id': id, + 'clientOrderId': clientOrderId, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': undefined, + 'symbol': symbol, + 'type': type, + 'side': side, + 'price': price, + 'amount': amount, + 'cost': cost, + 'average': average, + 'filled': filled, + 'remaining': remaining, + 'status': status, + 'fee': undefined, + 'trades': undefined, + }; + } + async createOrder (symbol, type, side, amount, price = undefined, params = {}) { - throw new NotSupported (this.id + ' createOrder not implemented yet'); + await this.loadMarkets (); + const market = this.market (symbol); + const orderTypes = this.safeValue (this.options, 'orderTypes', {}); + const orderType = this.safeString (orderTypes, type, type); + amount = (side === 'sell') ? -amount : amount; + const request = { + 'symbol': market['id'], + 'type': orderType, + 'amount': this.numberToString (amount), + }; + if (type !== 'market') { + request['price'] = this.numberToString (price); + } + const response = await this.privatePostAuthWOrderSubmit (this.extend (request, params)); + // + // [ + // 1578784364.748, // Millisecond Time Stamp of the update + // "on-req", // Purpose of notification ('on-req', 'oc-req', 'uca', 'fon-req', 'foc-req') + // null, // Unique ID of the message + // null, // Ignore + // [ + // [ + // 37271830598, // Order ID + // null, // Group ID + // 1578784364748, // Client Order ID + // "tBTCUST", // Pair + // 1578784364748, // Millisecond timestamp of creation + // 1578784364748, // Millisecond timestamp of update + // -0.005, // Positive means buy, negative means sell + // -0.005, // Original amount + // "EXCHANGE LIMIT", // Order type (LIMIT, MARKET, STOP, TRAILING STOP, EXCHANGE MARKET, EXCHANGE LIMIT, EXCHANGE STOP, EXCHANGE TRAILING STOP, FOK, EXCHANGE FOK, IOC, EXCHANGE IOC) + // null, // Previous order type + // null, // Millisecond timestamp of Time-In-Force: automatic order cancellation + // null, // Ignore + // 0, // Flags (see https://docs.bitfinex.com/docs/flag-values) + // "ACTIVE", // Order Status + // null, // Ignore + // null, // Ignore + // 20000, // Price + // 0, // Average price + // 0, // The trailing price + // 0, // Auxiliary Limit price (for STOP LIMIT) + // null, // Ignore + // null, // Ignore + // null, // Ignore + // 0, // 1 - hidden order + // null, // If another order caused this order to be placed (OCO) this will be that other order's ID + // null, // Ignore + // null, // Ignore + // null, // Ignore + // "API>BFX", // Origin of action: BFX, ETHFX, API>BFX, API>ETHFX + // null, // Ignore + // null, // Ignore + // null // Meta + // ] + // ], + // null, // Error code + // "SUCCESS", // Status (SUCCESS, ERROR, FAILURE, ...) + // "Submitting 1 orders." // Text of the notification + // ] + // + const status = this.safeString (response, 6); + if (status !== 'SUCCESS') { + const errorCode = response[5]; + const errorText = response[7]; + throw new ExchangeError (this.id + ' ' + response[6] + ': ' + errorText + ' (#' + errorCode + ')'); + } + const orders = this.safeValue (response, 4, []); + const order = this.safeValue (orders, 0); + return this.parseOrder (order, market); } - cancelOrder (id, symbol = undefined, params = {}) { - throw new NotSupported (this.id + ' cancelOrder not implemented yet'); + async cancelAllOrders (symbol = undefined, params = {}) { + const request = { + 'all': 1, + }; + const response = await this.privatePostAuthWOrderCancelMulti (this.extend (request, params)); + const orders = this.safeValue (response, 4, []); + return this.parseOrders (orders); } - async fetchOrder (id, symbol = undefined, params = {}) { - throw new NotSupported (this.id + ' fetchOrder not implemented yet'); + async cancelOrder (id, symbol = undefined, params = {}) { + const cid = this.safeValue (params, 'cid'); // client order id + let request = undefined; + if (cid !== undefined) { + const cidDate = this.safeValue (params, 'cidDate'); // client order id date + if (cidDate === undefined) { + throw new InvalidOrder (this.id + " canceling an order by client order id ('cid') requires both 'cid' and 'cid_date' ('YYYY-MM-DD')"); + } + request = { + 'cid': cid, + 'cid_date': cidDate, + }; + } else { + request = { + 'id': parseInt (id), + }; + } + const response = await this.privatePostAuthWOrderCancel (this.extend (request, params)); + const order = this.safeValue (response, 4); + return this.parseOrder (order); } - async fetchDepositAddress (currency, params = {}) { - throw new NotSupported (this.id + ' fetchDepositAddress() not implemented yet.'); + async fetchOpenOrder (id, symbol = undefined, params = {}) { + const request = { + 'id': [ parseInt (id) ], + }; + const orders = await this.fetchOpenOrders (symbol, undefined, undefined, this.extend (request, params)); + const order = this.safeValue (orders, 0); + if (order === undefined) { + throw new OrderNotFound (this.id + ' order ' + id + ' not found'); + } + return order; } - async withdraw (code, amount, address, tag = undefined, params = {}) { - throw new NotSupported (this.id + ' withdraw not implemented yet'); + async fetchClosedOrder (id, symbol = undefined, params = {}) { + const request = { + 'id': [ parseInt (id) ], + }; + const orders = await this.fetchClosedOrders (symbol, undefined, undefined, this.extend (request, params)); + const order = this.safeValue (orders, 0); + if (order === undefined) { + throw new OrderNotFound (this.id + ' order ' + id + ' not found'); + } + return order; + } + + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = {}; + let market = undefined; + let response = undefined; + if (symbol === undefined) { + response = await this.privatePostAuthROrders (this.extend (request, params)); + } else { + market = this.market (symbol); + request['symbol'] = market['id']; + response = await this.privatePostAuthROrdersSymbol (this.extend (request, params)); + } + return this.parseOrders (response, market, since, limit); + } + + async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + // returns the most recent closed or canceled orders up to circa two weeks ago + await this.loadMarkets (); + const request = {}; + let market = undefined; + let response = undefined; + if (symbol === undefined) { + response = await this.privatePostAuthROrdersHist (this.extend (request, params)); + } else { + market = this.market (symbol); + request['symbol'] = market['id']; + response = await this.privatePostAuthROrdersSymbolHist (this.extend (request, params)); + } + if (since !== undefined) { + request['start'] = since; + } + if (limit !== undefined) { + request['limit'] = limit; // default 25, max 2500 + } + return this.parseOrders (response, market, since, limit); + } + + async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOrderTrades() requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const orderId = parseInt (id); + const request = { + 'id': orderId, + 'symbol': market['id'], + }; + // valid for trades upto 10 days old + const response = await this.privatePostAuthROrderSymbolIdTrades (this.extend (request, params)); + return this.parseTrades (response, market, since, limit); } async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { @@ -15158,6 +16827,170 @@ module.exports = class bitfinex2 extends bitfinex { return this.parseTrades (response, market, since, limit); } + async createDepositAddress (code, params = {}) { + await this.loadMarkets (); + const request = { + 'op_renew': 1, + }; + const response = await this.fetchDepositAddress (code, this.extend (request, params)); + return response; + } + + async fetchDepositAddress (code, params = {}) { + await this.loadMarkets (); + // todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method + const name = this.getCurrencyName (code); + const request = { + 'method': name, + 'wallet': 'exchange', // 'exchange', 'margin', 'funding' and also old labels 'exchange', 'trading', 'deposit', respectively + 'op_renew': 0, // a value of 1 will generate a new address + }; + const response = await this.privatePostAuthWDepositAddress (this.extend (request, params)); + // + // [ + // 1582269616687, // MTS Millisecond Time Stamp of the update + // 'acc_dep', // TYPE Purpose of notification 'acc_dep' for account deposit + // null, // MESSAGE_ID unique ID of the message + // null, // not documented + // [ + // null, // PLACEHOLDER + // 'BITCOIN', // METHOD Method of deposit + // 'BTC', // CURRENCY_CODE Currency code of new address + // null, // PLACEHOLDER + // '1BC9PZqpUmjyEB54uggn8TFKj49zSDYzqG', // ADDRESS + // null, // POOL_ADDRESS + // ], + // null, // CODE null or integer work in progress + // 'SUCCESS', // STATUS Status of the notification, SUCCESS, ERROR, FAILURE + // 'success', // TEXT Text of the notification + // ] + // + const result = this.safeValue (response, 4, []); + const poolAddress = this.safeString (result, 5); + const address = (poolAddress === undefined) ? this.safeString (result, 4) : poolAddress; + const tag = (poolAddress === undefined) ? undefined : this.safeString (result, 4); + this.checkAddress (address); + return { + 'currency': code, + 'address': address, + 'tag': tag, + 'info': response, + }; + } + + parseTransaction (transaction, currency = undefined) { + // + // withdraw + // + // [ + // 1582271520931, // MTS Millisecond Time Stamp of the update + // "acc_wd-req", // TYPE Purpose of notification 'acc_wd-req' account withdrawal request + // null, // MESSAGE_ID unique ID of the message + // null, // not documented + // [ + // 0, // WITHDRAWAL_ID Unique Withdrawal ID + // null, // PLACEHOLDER + // "bitcoin", // METHOD Method of withdrawal + // null, // PAYMENT_ID Payment ID if relevant + // "exchange", // WALLET Sending wallet + // 1, // AMOUNT Amount of Withdrawal less fee + // null, // PLACEHOLDER + // null, // PLACEHOLDER + // 0.0004, // WITHDRAWAL_FEE Fee on withdrawal + // ], + // null, // CODE null or integer Work in progress + // "SUCCESS", // STATUS Status of the notification, it may vary over time SUCCESS, ERROR, FAILURE + // "Invalid bitcoin address (abcdef)", // TEXT Text of the notification + // ] + // + // todo add support for all movements, deposits and withdrawals + // + const data = this.safeValue (transaction, 4, []); + const timestamp = this.safeInteger (transaction, 0); + let code = undefined; + if (currency !== undefined) { + code = currency['code']; + } + let feeCost = this.safeFloat (data, 8); + if (feeCost !== undefined) { + feeCost = Math.abs (feeCost); + } + const amount = this.safeFloat (data, 5); + let id = this.safeValue (data, 0); + let status = 'ok'; + if (id === 0) { + id = undefined; + status = 'failed'; + } + return { + 'info': transaction, + 'id': id, + 'txid': undefined, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'address': undefined, // this is actually the tag for XRP transfers (the address is missing) + 'tag': this.safeString (data, 3), // refix it properly for the tag from description + 'type': 'withdrawal', + 'amount': amount, + 'currency': code, + 'status': status, + 'updated': undefined, + 'fee': { + 'currency': code, + 'cost': feeCost, + 'rate': undefined, + }, + }; + } + + async withdraw (code, amount, address, tag = undefined, params = {}) { + this.checkAddress (address); + await this.loadMarkets (); + const currency = this.currency (code); + // todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method + const name = this.getCurrencyName (code); + const request = { + 'method': name, + 'wallet': 'exchange', // 'exchange', 'margin', 'funding' and also old labels 'exchange', 'trading', 'deposit', respectively + 'amount': this.numberToString (amount), + 'address': address, + }; + if (tag !== undefined) { + request['payment_id'] = tag; + } + const response = await this.privatePostAuthWWithdraw (this.extend (request, params)); + // + // [ + // 1582271520931, // MTS Millisecond Time Stamp of the update + // "acc_wd-req", // TYPE Purpose of notification 'acc_wd-req' account withdrawal request + // null, // MESSAGE_ID unique ID of the message + // null, // not documented + // [ + // 0, // WITHDRAWAL_ID Unique Withdrawal ID + // null, // PLACEHOLDER + // "bitcoin", // METHOD Method of withdrawal + // null, // PAYMENT_ID Payment ID if relevant + // "exchange", // WALLET Sending wallet + // 1, // AMOUNT Amount of Withdrawal less fee + // null, // PLACEHOLDER + // null, // PLACEHOLDER + // 0.0004, // WITHDRAWAL_FEE Fee on withdrawal + // ], + // null, // CODE null or integer Work in progress + // "SUCCESS", // STATUS Status of the notification, it may vary over time SUCCESS, ERROR, FAILURE + // "Invalid bitcoin address (abcdef)", // TEXT Text of the notification + // ] + // + const text = this.safeString (response, 7); + if (text !== 'success') { + this.throwBroadlyMatchedException (this.exceptions['broad'], text, text); + } + const transaction = this.parseTransaction (response, currency); + return this.extend (transaction, { + 'address': address, + }); + } + nonce () { return this.milliseconds (); } @@ -15207,9 +17040,22 @@ module.exports = class bitfinex2 extends bitfinex { } return response; } + + handleErrors (statusCode, statusText, url, method, responseHeaders, responseBody, response, requestHeaders, requestBody) { + if (statusCode === 500) { + // See https://docs.bitfinex.com/docs/abbreviations-glossary#section-errorinfo-codes + const errorCode = this.numberToString (response[1]); + const errorText = response[2]; + const feedback = this.id + ' ' + errorText; + this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback); + this.throwExactlyMatchedException (this.exceptions['exact'], errorText, feedback); + this.throwBroadlyMatchedException (this.exceptions['broad'], errorText, feedback); + throw new ExchangeError (this.id + ' ' + errorText + ' (#' + errorCode + ')'); + } + } }; -},{"./base/errors":9,"./bitfinex.js":31}],33:[function(require,module,exports){ +},{"./base/errors":10,"./bitfinex.js":32}],34:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -15568,6 +17414,7 @@ module.exports = class bitflyer extends Exchange { const id = this.safeString (order, 'child_order_acceptance_id'); return { 'id': id, + 'clientOrderId': undefined, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -15582,6 +17429,8 @@ module.exports = class bitflyer extends Exchange { 'filled': filled, 'remaining': remaining, 'fee': fee, + 'average': undefined, + 'trades': undefined, }; } @@ -15698,7 +17547,7 @@ module.exports = class bitflyer extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],34:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],35:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -15921,6 +17770,9 @@ module.exports = class bitforex extends Exchange { }, }, }, + 'commonCurrencies': { + 'UOS': 'UOS Network', + }, 'exceptions': { '4004': OrderNotFound, '1013': AuthenticationError, @@ -16010,6 +17862,7 @@ module.exports = class bitforex extends Exchange { 'cost': cost, 'order': orderId, 'fee': undefined, + 'takerOrMaker': undefined, }; } @@ -16163,6 +18016,7 @@ module.exports = class bitforex extends Exchange { const result = { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -16177,6 +18031,7 @@ module.exports = class bitforex extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; return result; } @@ -16294,7 +18149,7 @@ module.exports = class bitforex extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],35:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],36:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -16426,6 +18281,8 @@ module.exports = class bithumb extends Exchange { 'max': undefined, }, }, + 'baseId': undefined, + 'quoteId': undefined, }); } return result; @@ -16745,7 +18602,7 @@ module.exports = class bithumb extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],36:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],37:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -16773,387 +18630,7 @@ module.exports = class bitkk extends zb { } }; -},{"./zb.js":174}],37:[function(require,module,exports){ -'use strict'; - -// --------------------------------------------------------------------------- - -const Exchange = require ('./base/Exchange'); -const { NotSupported } = require ('./base/errors'); - -// --------------------------------------------------------------------------- - -module.exports = class bitlish extends Exchange { - describe () { - return this.deepExtend (super.describe (), { - 'id': 'bitlish', - 'name': 'Bitlish', - 'countries': [ 'GB', 'EU', 'RU' ], - 'rateLimit': 1500, - 'version': 'v1', - 'has': { - 'CORS': false, - 'fetchTickers': true, - 'fetchOHLCV': true, - 'withdraw': true, - }, - 'timeframes': { - '1h': 3600, - }, - 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/27766275-dcfc6c30-5ed3-11e7-839d-00a846385d0b.jpg', - 'api': 'https://bitlish.com/api', - 'www': 'https://bitlish.com', - 'doc': 'https://bitlish.com/api', - 'fees': 'https://bitlish.com/fees', - }, - 'requiredCredentials': { - 'apiKey': true, - 'secret': false, - }, - 'fees': { - 'trading': { - 'tierBased': false, - 'percentage': true, - 'taker': 0.3 / 100, // anonymous 0.3%, verified 0.2% - 'maker': 0.2 / 100, // anonymous 0.2%, verified 0.1% - }, - 'funding': { - 'tierBased': false, - 'percentage': false, - 'withdraw': { - 'BTC': 0.001, - 'LTC': 0.001, - 'DOGE': 0.001, - 'ETH': 0.001, - 'XMR': 0, - 'ZEC': 0.001, - 'DASH': 0.0001, - 'EUR': 50, - }, - 'deposit': { - 'BTC': 0, - 'LTC': 0, - 'DOGE': 0, - 'ETH': 0, - 'XMR': 0, - 'ZEC': 0, - 'DASH': 0, - 'EUR': 0, - }, - }, - }, - 'api': { - 'public': { - 'get': [ - 'instruments', - 'ohlcv', - 'pairs', - 'tickers', - 'trades_depth', - 'trades_history', - ], - 'post': [ - 'instruments', - 'ohlcv', - 'pairs', - 'tickers', - 'trades_depth', - 'trades_history', - ], - }, - 'private': { - 'post': [ - 'accounts_operations', - 'balance', - 'cancel_trade', - 'cancel_trades_by_ids', - 'cancel_all_trades', - 'create_bcode', - 'create_template_wallet', - 'create_trade', - 'deposit', - 'list_accounts_operations_from_ts', - 'list_active_trades', - 'list_bcodes', - 'list_my_matches_from_ts', - 'list_my_trades', - 'list_my_trads_from_ts', - 'list_payment_methods', - 'list_payments', - 'redeem_code', - 'resign', - 'signin', - 'signout', - 'trade_details', - 'trade_options', - 'withdraw', - 'withdraw_by_id', - ], - }, - }, - 'commonCurrencies': { - 'DSH': 'DASH', - 'XDG': 'DOGE', - }, - }); - } - - async fetchMarkets (params = {}) { - const response = await this.publicGetPairs (params); - const result = []; - const keys = Object.keys (response); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - const market = response[key]; - const id = this.safeString (market, 'id'); - const name = this.safeString (market, 'name'); - const [ baseId, quoteId ] = name.split ('/'); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - const symbol = base + '/' + quote; - result.push ({ - 'id': id, - 'symbol': symbol, - 'base': base, - 'quote': quote, - 'baseId': baseId, - 'quoteId': quoteId, - 'info': market, - }); - } - return result; - } - - parseTicker (ticker, market) { - const timestamp = this.milliseconds (); - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; - } - const last = this.safeFloat (ticker, 'last'); - return { - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': symbol, - 'high': this.safeFloat (ticker, 'max'), - 'low': this.safeFloat (ticker, 'min'), - 'bid': this.safeFloat (ticker, 'bid'), - 'bidVolume': undefined, - 'ask': this.safeFloat (ticker, 'ask'), - 'askVolume': undefined, - 'vwap': undefined, - 'open': this.safeFloat (ticker, 'first'), - 'close': last, - 'last': last, - 'previousClose': undefined, - 'change': undefined, - 'percentage': this.safeFloat (ticker, 'prc') * 100, - 'average': undefined, - 'baseVolume': this.safeFloat (ticker, 'sum'), - 'quoteVolume': undefined, - 'info': ticker, - }; - } - - async fetchTickers (symbols = undefined, params = {}) { - await this.loadMarkets (); - const tickers = await this.publicGetTickers (params); - const ids = Object.keys (tickers); - const result = {}; - for (let i = 0; i < ids.length; i++) { - const id = ids[i]; - const market = this.safeValue (this.markets_by_id, id); - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; - } else { - const baseId = id.slice (0, 3); - const quoteId = id.slice (3, 6); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - symbol = base + '/' + quote; - } - const ticker = tickers[id]; - result[symbol] = this.parseTicker (ticker, market); - } - return result; - } - - async fetchTicker (symbol, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const response = await this.publicGetTickers (params); - const marketId = market['id']; - return this.parseTicker (response[marketId], market); - } - - async fetchOHLCV (symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - // let market = this.market (symbol); - const now = this.seconds (); - let start = now - 86400 * 30; // last 30 days - if (since !== undefined) { - start = parseInt (since / 1000); - } - const interval = [ start.toString (), undefined ]; - const request = { - 'time_range': interval, - }; - return await this.publicPostOhlcv (this.extend (request, params)); - } - - async fetchOrderBook (symbol, limit = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'pair_id': this.marketId (symbol), - }; - const response = await this.publicGetTradesDepth (this.extend (request, params)); - let timestamp = undefined; - const last = this.safeInteger (response, 'last'); - if (last !== undefined) { - timestamp = parseInt (last / 1000); - } - return this.parseOrderBook (response, timestamp, 'bid', 'ask', 'price', 'volume'); - } - - parseTrade (trade, market = undefined) { - const side = (trade['dir'] === 'bid') ? 'buy' : 'sell'; - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; - } - let timestamp = this.safeInteger (trade, 'created'); - if (timestamp !== undefined) { - timestamp = parseInt (timestamp / 1000); - } - const price = this.safeFloat (trade, 'price'); - const amount = this.safeFloat (trade, 'amount'); - let cost = undefined; - if (amount !== undefined) { - if (price !== undefined) { - cost = price * amount; - } - } - return { - 'id': undefined, - 'info': trade, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': symbol, - 'order': undefined, - 'type': undefined, - 'side': side, - 'takerOrMaker': undefined, - 'price': price, - 'amount': amount, - 'cost': cost, - 'fee': undefined, - }; - } - - async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const response = await this.publicGetTradesHistory (this.extend ({ - 'pair_id': market['id'], - }, params)); - return this.parseTrades (response['list'], market, since, limit); - } - - async fetchBalance (params = {}) { - await this.loadMarkets (); - const response = await this.privatePostBalance (params); - const result = { 'info': response }; - const currencyIds = Object.keys (response); - for (let i = 0; i < currencyIds.length; i++) { - const currencyId = currencyIds[i]; - const code = this.safeCurrencyCode (currencyId); - const account = this.account (); - const balance = this.safeValue (response, currencyId, {}); - account['free'] = this.safeFloat (balance, 'funds'); - account['used'] = this.safeFloat (balance, 'holded'); - result[code] = account; - } - return this.parseBalance (result); - } - - async signIn (params = {}) { - const request = { - 'login': this.login, - 'passwd': this.password, - }; - return await this.privatePostSignin (this.extend (request, params)); - } - - async createOrder (symbol, type, side, amount, price = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'pair_id': this.marketId (symbol), - 'dir': (side === 'buy') ? 'bid' : 'ask', - 'amount': amount, - }; - if (type === 'limit') { - request['price'] = price; - } - const response = await this.privatePostCreateTrade (this.extend (request, params)); - const id = this.safeString (response, 'id'); - return { - 'info': response, - 'id': id, - }; - } - - async cancelOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'id': id, - }; - return await this.privatePostCancelTrade (this.extend (request, params)); - } - - async withdraw (code, amount, address, tag = undefined, params = {}) { - if (code !== 'BTC') { - // they did not document other types... - throw new NotSupported (this.id + ' currently supports BTC withdrawals only, until they document other currencies...'); - } - this.checkAddress (address); - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'currency': currency['id'], - 'amount': parseFloat (amount), - 'account': address, - 'payment_method': 'bitcoin', // they did not document other types... - }; - const response = await this.privatePostWithdraw (this.extend (request, params)); - return { - 'info': response, - 'id': response['message_id'], - }; - } - - sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = this.urls['api'] + '/' + this.version + '/' + path; - if (api === 'public') { - if (method === 'GET') { - if (Object.keys (params).length) { - url += '?' + this.urlencode (params); - } - } else { - body = this.json (params); - headers = { 'Content-Type': 'application/json' }; - } - } else { - this.checkRequiredCredentials (); - body = this.json (this.extend ({ 'token': this.apiKey }, params)); - headers = { 'Content-Type': 'application/json' }; - } - return { 'url': url, 'method': method, 'body': body, 'headers': headers }; - } -}; - -},{"./base/Exchange":7,"./base/errors":9}],38:[function(require,module,exports){ +},{"./zb.js":173}],38:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -17306,6 +18783,7 @@ module.exports = class bitmart extends Exchange { }, 'commonCurrencies': { 'ONE': 'Menlo One', + 'PLA': 'Plair', }, }); } @@ -17404,6 +18882,7 @@ module.exports = class bitmart extends Exchange { 'precision': precision, 'limits': limits, 'info': market, + 'active': undefined, }); } return result; @@ -17837,6 +19316,7 @@ module.exports = class bitmart extends Exchange { const type = undefined; return { 'id': id, + 'clientOrderId': undefined, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -18078,7 +19558,7 @@ module.exports = class bitmart extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],39:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],39:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -18133,7 +19613,7 @@ module.exports = class bitmax extends Exchange { 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/66820319-19710880-ef49-11e9-8fbe-16be62a11992.jpg', 'api': 'https://bitmax.io', - 'test': 'https://bitmax-test.io/api', + 'test': 'https://bitmax-test.io', 'www': 'https://bitmax.io', 'doc': [ 'https://github.com/bitmax-exchange/api-doc/blob/master/bitmax-api-doc-v1.2.md', @@ -18202,12 +19682,17 @@ module.exports = class bitmax extends Exchange { 'exact': { '2100': AuthenticationError, // {"code":2100,"message":"ApiKeyFailure"} '5002': BadSymbol, // {"code":5002,"message":"Invalid Symbol"} + '6001': BadSymbol, // {"code":6001,"message":"Trading is disabled on symbol."} '6010': InsufficientFunds, // {'code': 6010, 'message': 'Not enough balance.'} '60060': InvalidOrder, // { 'code': 60060, 'message': 'The order is already filled or canceled.' } '600503': InvalidOrder, // {"code":600503,"message":"Notional is too small."} }, 'broad': {}, }, + 'commonCurrencies': { + 'BTCBEAR': 'BEAR', + 'BTCBULL': 'BULL', + }, }); } @@ -18803,9 +20288,11 @@ module.exports = class bitmax extends Exchange { 'currency': this.safeString (order, 'feeAsset'), }; const average = this.safeFloat (order, 'avgPrice'); + const clientOrderId = id; return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -19226,7 +20713,7 @@ module.exports = class bitmax extends Exchange { headers['x-auth-coid'] = coid; } const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256', 'base64'); - headers['x-auth-signature'] = signature; + headers['x-auth-signature'] = this.decode (signature); if (method === 'GET') { if (Object.keys (query).length) { url += '?' + this.urlencode (query); @@ -19261,7 +20748,7 @@ module.exports = class bitmax extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],40:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],40:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -19281,6 +20768,7 @@ module.exports = class bitmex extends Exchange { 'version': 'v1', 'userAgent': undefined, 'rateLimit': 2000, + 'pro': true, 'has': { 'CORS': false, 'fetchOHLCV': true, @@ -19316,7 +20804,7 @@ module.exports = class bitmex extends Exchange { 'https://github.com/BitMEX/api-connectors/tree/master/official-http', ], 'fees': 'https://www.bitmex.com/app/fees', - 'referral': 'https://www.bitmex.com/register/rm3C16', + 'referral': 'https://www.bitmex.com/register/upZpOX', }, 'api': { 'public': { @@ -20374,9 +21862,11 @@ module.exports = class bitmex extends Exchange { const id = this.safeString (order, 'orderID'); const type = this.safeStringLower (order, 'ordType'); const side = this.safeStringLower (order, 'side'); + const clientOrderId = this.safeString (order, 'clOrdID'); return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -20391,6 +21881,7 @@ module.exports = class bitmex extends Exchange { 'remaining': remaining, 'status': status, 'fee': undefined, + 'trades': undefined, }; } @@ -20475,7 +21966,15 @@ module.exports = class bitmex extends Exchange { async cancelOrder (id, symbol = undefined, params = {}) { await this.loadMarkets (); - const response = await this.privateDeleteOrder (this.extend ({ 'orderID': id }, params)); + // https://github.com/ccxt/ccxt/issues/6507 + const clOrdID = this.safeValue (params, 'clOrdID'); + const request = {}; + if (clOrdID === undefined) { + request['orderID'] = id; + } else { + request['clOrdID'] = clOrdID; + } + const response = await this.privateDeleteOrder (this.extend (request, params)); let order = response[0]; const error = this.safeString (order, 'error'); if (error !== undefined) { @@ -20580,7 +22079,7 @@ module.exports = class bitmex extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],41:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],41:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -20599,7 +22098,7 @@ module.exports = class bitso extends Exchange { 'rateLimit': 2000, // 30 requests per minute 'version': 'v3', 'has': { - 'CORS': true, + 'CORS': false, 'fetchMyTrades': true, 'fetchOpenOrders': true, 'fetchOrder': true, @@ -20722,6 +22221,7 @@ module.exports = class bitso extends Exchange { 'info': market, 'limits': limits, 'precision': precision, + 'active': undefined, }); } return result; @@ -20952,9 +22452,11 @@ module.exports = class bitso extends Exchange { filled = amount - remaining; } } + const clientOrderId = this.safeString (order, 'client_id'); return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -20968,6 +22470,8 @@ module.exports = class bitso extends Exchange { 'filled': filled, 'status': status, 'fee': undefined, + 'average': undefined, + 'trades': undefined, }; } @@ -21144,7 +22648,7 @@ module.exports = class bitso extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],42:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],42:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -21163,6 +22667,7 @@ module.exports = class bitstamp extends Exchange { 'rateLimit': 1000, 'version': 'v2', 'userAgent': this.userAgents['chrome'], + 'pro': true, 'has': { 'CORS': true, 'fetchDepositAddress': true, @@ -21178,6 +22683,7 @@ module.exports = class bitstamp extends Exchange { 'api': { 'public': 'https://www.bitstamp.net/api', 'private': 'https://www.bitstamp.net/api', + 'v1': 'https://www.bitstamp.net/api', }, 'www': 'https://www.bitstamp.net', 'doc': 'https://www.bitstamp.net/api', @@ -21380,8 +22886,27 @@ module.exports = class bitstamp extends Exchange { 'pair': this.marketId (symbol), }; const response = await this.publicGetOrderBookPair (this.extend (request, params)); - const timestamp = this.safeTimestamp (response, 'timestamp'); - return this.parseOrderBook (response, timestamp); + // + // { + // "timestamp": "1583652948", + // "microtimestamp": "1583652948955826", + // "bids": [ + // [ "8750.00", "1.33685271" ], + // [ "8749.39", "0.07700000" ], + // [ "8746.98", "0.07400000" ], + // ] + // "asks": [ + // [ "8754.10", "1.51995636" ], + // [ "8754.71", "1.40000000" ], + // [ "8754.72", "2.50000000" ], + // ] + // } + // + const microtimestamp = this.safeInteger (response, 'microtimestamp'); + const timestamp = parseInt (microtimestamp / 1000); + const orderbook = this.parseOrderBook (response, timestamp); + orderbook['nonce'] = microtimestamp; + return orderbook; } async fetchTicker (symbol, params = {}) { @@ -22093,6 +23618,7 @@ module.exports = class bitstamp extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': lastTradeTimestamp, @@ -22108,6 +23634,7 @@ module.exports = class bitstamp extends Exchange { 'trades': trades, 'fee': fee, 'info': order, + 'average': undefined, }; } @@ -22170,7 +23697,10 @@ module.exports = class bitstamp extends Exchange { method += 'Post' + this.capitalize (name); method += v1 ? 'Deposit' : ''; method += 'Address'; - const response = await this[method] (params); + let response = await this[method] (params); + if (v1) { + response = JSON.parse (response); + } const address = v1 ? response : this.safeString (response, 'address'); const tag = v1 ? undefined : this.safeString (response, 'destination_tag'); this.checkAddress (address); @@ -22224,18 +23754,44 @@ module.exports = class bitstamp extends Exchange { } } else { this.checkRequiredCredentials (); - const nonce = this.nonce ().toString (); - const auth = nonce + this.uid + this.apiKey; - const signature = this.encode (this.hmac (this.encode (auth), this.encode (this.secret))); - query = this.extend ({ - 'key': this.apiKey, - 'signature': signature.toUpperCase (), - 'nonce': nonce, - }, query); - body = this.urlencode (query); - headers = { - 'Content-Type': 'application/x-www-form-urlencoded', - }; + const authVersion = this.safeValue (this.options, 'auth', 'v2'); + if ((authVersion === 'v1') || (api === 'v1')) { + const nonce = this.nonce ().toString (); + const auth = nonce + this.uid + this.apiKey; + const signature = this.encode (this.hmac (this.encode (auth), this.encode (this.secret))); + query = this.extend ({ + 'key': this.apiKey, + 'signature': signature.toUpperCase (), + 'nonce': nonce, + }, query); + body = this.urlencode (query); + headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + }; + } else { + const xAuth = 'BITSTAMP ' + this.apiKey; + const xAuthNonce = this.uuid (); + const xAuthTimestamp = this.milliseconds ().toString (); + const xAuthVersion = 'v2'; + let contentType = ''; + headers = { + 'X-Auth': xAuth, + 'X-Auth-Nonce': xAuthNonce, + 'X-Auth-Timestamp': xAuthTimestamp, + 'X-Auth-Version': xAuthVersion, + }; + if (method === 'POST') { + if (Object.keys (query).length) { + body = this.urlencode (query); + contentType = 'application/x-www-form-urlencoded'; + headers['Content-Type'] = contentType; + } + } + const authBody = body ? body : ''; + const auth = xAuth + method + url.replace ('https://', '') + contentType + xAuthNonce + xAuthTimestamp + xAuthVersion + authBody; + const signature = this.encode (this.hmac (this.encode (auth), this.encode (this.secret))); + headers['X-Auth-Signature'] = signature; + } } return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } @@ -22290,7 +23846,7 @@ module.exports = class bitstamp extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],43:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],43:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -22583,7 +24139,7 @@ module.exports = class bitstamp1 extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],44:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],44:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -22603,10 +24159,11 @@ module.exports = class bittrex extends Exchange { 'version': 'v1.1', 'rateLimit': 1500, 'certified': true, + 'pro': true, // new metainfo interface 'has': { - 'CORS': true, - 'createMarketOrder': false, + 'CORS': false, + 'createMarketOrder': true, 'fetchDepositAddress': true, 'fetchClosedOrders': true, 'fetchCurrencies': true, @@ -22648,6 +24205,7 @@ module.exports = class bittrex extends Exchange { 'https://bittrex.zendesk.com/hc/en-us/articles/115003684371-BITTREX-SERVICE-FEES-AND-WITHDRAWAL-LIMITATIONS', 'https://bittrex.zendesk.com/hc/en-us/articles/115000199651-What-fees-does-Bittrex-charge-', ], + 'referral': 'https://bittrex.com/Account/Register?referralCode=1ZE-G0G-M3B', }, 'api': { 'v3': { @@ -22800,6 +24358,9 @@ module.exports = class bittrex extends Exchange { 'INVALID_CURRENCY': ExchangeError, 'INVALID_PERMISSION': AuthenticationError, 'INSUFFICIENT_FUNDS': InsufficientFunds, + 'INVALID_CEILING_MARKET_BUY': InvalidOrder, + 'INVALID_FIAT_ACCOUNT': InvalidOrder, + 'INVALID_ORDER_TYPE': InvalidOrder, 'QUANTITY_NOT_PROVIDED': InvalidOrder, 'MIN_TRADE_REQUIREMENT_NOT_MET': InvalidOrder, 'ORDER_NOT_OPEN': OrderNotFound, @@ -22844,10 +24405,10 @@ module.exports = class bittrex extends Exchange { // see the implementation of fetchClosedOrdersV3 below 'fetchClosedOrdersMethod': 'fetch_closed_orders_v3', 'fetchClosedOrdersFilterBySince': true, + // 'createOrderMethod': 'create_order_v1', }, 'commonCurrencies': { 'BITS': 'SWIFT', - 'CPC': 'Capricoin', }, }); } @@ -23002,9 +24563,6 @@ module.exports = class bittrex extends Exchange { for (let i = 0; i < currencies.length; i++) { const currency = currencies[i]; const id = this.safeString (currency, 'Currency'); - // todo: will need to rethink the fees - // to add support for multiple withdrawal/deposit methods and - // differentiated fees for each particular method const code = this.safeCurrencyCode (id); const precision = 8; // default precision, todo: fix "magic constants" const address = this.safeValue (currency, 'BaseAddress'); @@ -23014,9 +24572,9 @@ module.exports = class bittrex extends Exchange { 'code': code, 'address': address, 'info': currency, - 'type': currency['CoinType'], - 'name': currency['CurrencyLong'], - 'active': currency['IsActive'], + 'type': this.safeString (currency, 'CoinType'), + 'name': this.safeString (currency, 'CurrencyLong'), + 'active': this.safeValue (currency, 'IsActive'), 'fee': fee, 'precision': precision, 'limits': { @@ -23250,6 +24808,74 @@ module.exports = class bittrex extends Exchange { } async createOrder (symbol, type, side, amount, price = undefined, params = {}) { + const uppercaseType = type.toUpperCase (); + const isMarket = (uppercaseType === 'MARKET'); + const isCeilingLimit = (uppercaseType === 'CEILING_LIMIT'); + const isCeilingMarket = (uppercaseType === 'CEILING_MARKET'); + const isV3 = isMarket || isCeilingLimit || isCeilingMarket; + const defaultMethod = isV3 ? 'create_order_v3' : 'create_order_v1'; + const method = this.safeValue (this.options, 'createOrderMethod', defaultMethod); + return await this[method] (symbol, type, side, amount, price, params); + } + + async createOrderV3 (symbol, type, side, amount, price = undefined, params = {}) { + // A ceiling order is a market or limit order that allows you to specify + // the amount of quote currency you want to spend (or receive, if selling) + // instead of the quantity of the market currency (e.g. buy $100 USD of BTC + // at the current market BTC price) + await this.loadMarkets (); + const market = this.market (symbol); + const uppercaseType = type.toUpperCase (); + const reverseId = market['baseId'] + '-' + market['quoteId']; + const request = { + 'marketSymbol': reverseId, + 'direction': side.toUpperCase (), + 'type': uppercaseType, // LIMIT, MARKET, CEILING_LIMIT, CEILING_MARKET + // 'quantity': this.amountToPrecision (symbol, amount), // required for limit orders, excluded for ceiling orders + // 'ceiling': this.priceToPrecision (symbol, price), // required for ceiling orders, excluded for non-ceiling orders + // 'limit': this.priceToPrecision (symbol, price), // required for limit orders, excluded for market orders + // 'timeInForce': 'GOOD_TIL_CANCELLED', // IMMEDIATE_OR_CANCEL, FILL_OR_KILL, POST_ONLY_GOOD_TIL_CANCELLED + // 'useAwards': false, // optional + }; + const isCeilingLimit = (uppercaseType === 'CEILING_LIMIT'); + const isCeilingMarket = (uppercaseType === 'CEILING_MARKET'); + const isCeilingOrder = isCeilingLimit || isCeilingMarket; + if (isCeilingOrder) { + request['ceiling'] = this.priceToPrecision (symbol, price); + // bittrex only accepts IMMEDIATE_OR_CANCEL or FILL_OR_KILL for ceiling orders + request['timeInForce'] = 'IMMEDIATE_OR_CANCEL'; + } else { + request['quantity'] = this.amountToPrecision (symbol, amount); + if (uppercaseType === 'LIMIT') { + request['limit'] = this.priceToPrecision (symbol, price); + request['timeInForce'] = 'GOOD_TIL_CANCELLED'; + } else { + // bittrex does not allow GOOD_TIL_CANCELLED for market orders + request['timeInForce'] = 'IMMEDIATE_OR_CANCEL'; + } + } + const response = await this.v3PostOrders (this.extend (request, params)); + // + // { + // id: 'f03d5e98-b5ac-48fb-8647-dd4db828a297', + // marketSymbol: 'BTC-USDT', + // direction: 'SELL', + // type: 'LIMIT', + // quantity: '0.01', + // limit: '6000', + // timeInForce: 'GOOD_TIL_CANCELLED', + // fillQuantity: '0.00000000', + // commission: '0.00000000', + // proceeds: '0.00000000', + // status: 'OPEN', + // createdAt: '2020-03-18T02:37:33.42Z', + // updatedAt: '2020-03-18T02:37:33.42Z' + // } + // + return this.parseOrderV3 (response, market); + } + + async createOrderV1 (symbol, type, side, amount, price = undefined, params = {}) { if (type !== 'limit') { throw new ExchangeError (this.id + ' allows limit orders only'); } @@ -23295,7 +24921,10 @@ module.exports = class bittrex extends Exchange { // } // } // - return this.extend (this.parseOrder (response), { + const result = this.safeValue (response, 'result', {}); + return this.extend (this.parseOrder (result), { + 'id': id, + 'info': response, 'status': 'canceled', }); } @@ -23563,6 +25192,7 @@ module.exports = class bittrex extends Exchange { } return { 'id': this.safeString (order, 'id'), + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -23581,6 +25211,7 @@ module.exports = class bittrex extends Exchange { 'currency': feeCurrency, }, 'info': order, + 'trades': undefined, }; } @@ -23705,6 +25336,7 @@ module.exports = class bittrex extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -23719,6 +25351,7 @@ module.exports = class bittrex extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; } @@ -23761,6 +25394,7 @@ module.exports = class bittrex extends Exchange { 'datetime': this.iso8601 (timestamp), 'fee': this.safeValue (order, 'fee'), 'info': order, + 'takerOrMaker': undefined, }; } @@ -23908,10 +25542,16 @@ module.exports = class bittrex extends Exchange { } } else if (api === 'v3') { url += path; - if (Object.keys (params).length) { - url += '?' + this.rawencode (params); + let hashString = ''; + if (method === 'POST') { + body = this.json (params); + hashString = body; + } else { + if (Object.keys (params).length) { + url += '?' + this.rawencode (params); + } } - const contentHash = this.hash (this.encode (''), 'sha512', 'hex'); + const contentHash = this.hash (this.encode (hashString), 'sha512', 'hex'); const timestamp = this.milliseconds ().toString (); let auth = timestamp + url + method + contentHash; const subaccountId = this.safeValue (this.options, 'subaccountId'); @@ -23928,6 +25568,9 @@ module.exports = class bittrex extends Exchange { if (subaccountId !== undefined) { headers['Api-Subaccount-Id'] = subaccountId; } + if (method === 'POST') { + headers['Content-Type'] = 'application/json'; + } } else { this.checkRequiredCredentials (); url += api + '/'; @@ -23956,8 +25599,16 @@ module.exports = class bittrex extends Exchange { // { success: false, message: "message" } // if (body[0] === '{') { + const feedback = this.id + ' ' + body; let success = this.safeValue (response, 'success'); if (success === undefined) { + const code = this.safeString (response, 'code'); + if (code !== undefined) { + this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback); + if (code !== undefined) { + this.throwBroadlyMatchedException (this.exceptions['broad'], code, feedback); + } + } // throw new ExchangeError (this.id + ' malformed response ' + this.json (response)); return; } @@ -23967,7 +25618,6 @@ module.exports = class bittrex extends Exchange { } if (!success) { const message = this.safeString (response, 'message'); - const feedback = this.id + ' ' + body; if (message === 'APIKEY_INVALID') { if (this.options['hasAlreadyAuthenticatedSuccessfully']) { throw new DDoSProtection (feedback); @@ -24031,7 +25681,7 @@ module.exports = class bittrex extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],45:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],45:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -24194,6 +25844,7 @@ module.exports = class bitz extends Exchange { // https://github.com/ccxt/ccxt/issues/3881 // https://support.bit-z.pro/hc/en-us/articles/360007500654-BOX-BOX-Token- 'BOX': 'BOX Token', + 'LEO': 'LeoCoin', 'XRB': 'NANO', 'PXC': 'Pixiecoin', 'VTC': 'VoteCoin', @@ -24787,6 +26438,7 @@ module.exports = class bitz extends Exchange { const status = this.parseOrderStatus (this.safeString (order, 'status')); return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -24802,6 +26454,7 @@ module.exports = class bitz extends Exchange { 'trades': undefined, 'fee': undefined, 'info': order, + 'average': undefined, }; } @@ -25244,7 +26897,7 @@ module.exports = class bitz extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],46:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],46:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -25479,103 +27132,83 @@ module.exports = class bl3p extends Exchange { } }; -},{"./base/Exchange":7}],47:[function(require,module,exports){ +},{"./base/Exchange":8}],47:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- - -const bittrex = require ('./bittrex.js'); -const { ExchangeError, AuthenticationError, InvalidOrder, InsufficientFunds } = require ('./base/errors'); +const Exchange = require ('./base/Exchange'); +const { ExchangeError, InvalidOrder, AuthenticationError, InsufficientFunds, BadRequest } = require ('./base/errors'); // --------------------------------------------------------------------------- -module.exports = class bleutrade extends bittrex { +module.exports = class bleutrade extends Exchange { describe () { - const timeframes = { - '15m': '15m', - '20m': '20m', - '30m': '30m', - '1h': '1h', - '2h': '2h', - '3h': '3h', - '4h': '4h', - '6h': '6h', - '8h': '8h', - '12h': '12h', - '1d': '1d', - }; - const result = this.deepExtend (super.describe (), { + return this.deepExtend (super.describe (), { 'id': 'bleutrade', 'name': 'Bleutrade', - 'countries': [ 'BR' ], // Brazil + 'countries': ['BR'], // Brazil 'rateLimit': 1000, - 'version': 'v2', 'certified': false, 'has': { 'CORS': true, + 'cancelOrder': false, // todo + 'createLimitOrder': false, // todo + 'createMarketOrder': false, // todo + 'createOrder': false, // todo + 'editOrder': false, // todo + 'withdraw': false, // todo + 'fetchTrades': false, 'fetchTickers': true, - 'fetchOrders': true, + 'fetchTicker': true, + 'fetchOrders': false, 'fetchClosedOrders': true, - 'fetchOrderTrades': true, + 'fetchOpenOrders': true, + 'fetchWithdrawals': true, + 'fetchOrderTrades': false, 'fetchLedger': true, + 'fetchDepositAddress': true, + }, + 'timeframes': { + '15m': '15m', + '20m': '20m', + '30m': '30m', + '1h': '1h', + '2h': '2h', + '3h': '3h', + '4h': '4h', + '6h': '6h', + '8h': '8h', + '12h': '12h', + '1d': '1d', }, - 'timeframes': timeframes, 'hostname': 'bleutrade.com', 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/30303000-b602dbe6-976d-11e7-956d-36c5049c01e7.jpg', 'api': { - 'public': 'https://{hostname}/api/v2', - 'account': 'https://{hostname}/api/v2', - 'market': 'https://{hostname}/api/v2', 'v3Private': 'https://{hostname}/api/v3/private', 'v3Public': 'https://{hostname}/api/v3/public', }, - 'www': 'https://bleutrade.com', + 'www': ['https://bleutrade.com'], 'doc': [ 'https://app.swaggerhub.com/apis-docs/bleu/white-label/3.0.0', ], - 'fees': 'https://bleutrade.com/help/fees_and_deadlines', + 'fees': 'https://bleutrade.com/fees/', }, 'api': { - 'account': { - 'get': [ - 'balance', - 'balances', - 'depositaddress', - 'deposithistory', - 'order', - 'orders', - 'orderhistory', - 'withdrawhistory', - 'withdraw', - ], - }, - 'public': { - 'get': [ - 'candles', - 'currencies', - 'markethistory', - 'markets', - 'marketsummaries', - 'marketsummary', - 'orderbook', - 'ticker', - ], - }, 'v3Public': { 'get': [ - 'assets', - 'markets', - 'ticker', - 'marketsummary', - 'marketsummaries', - 'orderbook', - 'markethistory', - 'candles', + 'getassets', + 'getmarkets', + 'getticker', + 'getmarketsummary', + 'getmarketsummaries', + 'getorderbook', + 'getmarkethistory', + 'getcandles', ], }, 'v3Private': { - 'get': [ + 'post': [ 'getbalance', 'getbalances', 'buylimit', @@ -25586,6 +27219,7 @@ module.exports = class bleutrade extends bittrex { 'sellstoplimit', 'ordercancel', 'getopenorders', + 'getcloseorders', 'getdeposithistory', 'getdepositaddress', 'getmytransactions', @@ -25596,111 +27230,110 @@ module.exports = class bleutrade extends bittrex { ], }, }, - 'fees': { - 'funding': { - 'withdraw': { - 'ADC': 0.1, - 'BTA': 0.1, - 'BITB': 0.1, - 'BTC': 0.001, - 'BCC': 0.001, - 'BTCD': 0.001, - 'BTG': 0.001, - 'BLK': 0.1, - 'CDN': 0.1, - 'CLAM': 0.01, - 'DASH': 0.001, - 'DCR': 0.05, - 'DGC': 0.1, - 'DP': 0.1, - 'DPC': 0.1, - 'DOGE': 10.0, - 'EFL': 0.1, - 'ETH': 0.01, - 'EXP': 0.1, - 'FJC': 0.1, - 'BSTY': 0.001, - 'GB': 0.1, - 'NLG': 0.1, - 'HTML': 1.0, - 'LTC': 0.001, - 'MONA': 0.01, - 'MOON': 1.0, - 'NMC': 0.015, - 'NEOS': 0.1, - 'NVC': 0.05, - 'OK': 0.1, - 'PPC': 0.1, - 'POT': 0.1, - 'XPM': 0.001, - 'QTUM': 0.1, - 'RDD': 0.1, - 'SLR': 0.1, - 'START': 0.1, - 'SLG': 0.1, - 'TROLL': 0.1, - 'UNO': 0.01, - 'VRC': 0.1, - 'VTC': 0.1, - 'XVP': 0.1, - 'WDC': 0.001, - 'ZET': 0.1, - }, - }, - }, 'commonCurrencies': { 'EPC': 'Epacoin', }, 'exceptions': { 'exact': { - 'Insufficient funds!': InsufficientFunds, - 'Invalid Order ID': InvalidOrder, - 'Invalid apikey or apisecret': AuthenticationError, + 'ERR_INSUFICIENT_BALANCE': InsufficientFunds, + 'ERR_LOW_VOLUME': BadRequest, + }, + 'broad': { + 'Order is not open': InvalidOrder, + 'Invalid Account / Api KEY / Api Secret': AuthenticationError, // also happens when an invalid nonce is used + }, + }, + 'fees': { + 'trading': { + 'tierBased': false, + 'percentage': true, + 'taker': 0.25 / 100, + 'maker': 0.25 / 100, }, }, 'options': { - // price precision by quote currency code - 'pricePrecisionByCode': { - 'USD': 3, - }, 'parseOrderStatus': true, - 'disableNonce': false, 'symbolSeparator': '_', }, }); - // bittrex inheritance override - result['timeframes'] = timeframes; + // undocumented api calls + // https://bleutrade.com/api/v3/public/tradingview/symbols?symbol=ETH_BTC + // https://bleutrade.com/api/v3/public/tradingview/config + // https://bleutrade.com/api/v3/public/tradingview/time + // https://bleutrade.com/api/v3/private/getcloseorders?market=ETH_BTC + // https://bleutrade.com/config contains the fees + } + + async fetchCurrencies (params = {}) { + const response = await this.v3PublicGetGetassets (params); + const items = response['result']; + const result = {}; + for (let i = 0; i < items.length; i++) { + // { Asset: 'USDT', + // AssetLong: 'Tether', + // MinConfirmation: 4, + // WithdrawTxFee: 1, + // WithdrawTxFeePercent: 0, + // SystemProtocol: 'ETHERC20', + // IsActive: true, + // InfoMessage: '', + // MaintenanceMode: false, + // MaintenanceMessage: '', + // FormatPrefix: '', + // FormatSufix: '', + // DecimalSeparator: '.', + // ThousandSeparator: ',', + // DecimalPlaces: 8, + // Currency: 'USDT', + // CurrencyLong: 'Tether', + // CoinType: 'ETHERC20' } + const item = items[i]; + const id = this.safeString (item, 'Asset'); + const code = this.safeCurrencyCode (id); + result[code] = { + 'id': id, + 'code': code, + 'name': this.safeString (item, 'AssetLong'), + 'active': this.safeValue (item, 'IsActive') && !this.safeValue (item, 'MaintenanceMode'), + 'fee': this.safeFloat (item, 'WithdrawTxFee'), + 'precision': this.safeFloat (item, 'DecimalPlaces'), + 'info': item, + 'limits': this.limits, + }; + } return result; } async fetchMarkets (params = {}) { // https://github.com/ccxt/ccxt/issues/5668 - const response = await this.publicGetMarkets (params); + const response = await this.v3PublicGetGetmarkets (params); const result = []; const markets = this.safeValue (response, 'result'); for (let i = 0; i < markets.length; i++) { const market = markets[i]; + // { MarketName: 'LTC_USDT', + // MarketAsset: 'LTC', + // BaseAsset: 'USDT', + // MarketAssetLong: 'Litecoin', + // BaseAssetLong: 'Tether', + // IsActive: true, + // MinTradeSize: 0.0001, + // InfoMessage: '', + // MarketCurrency: 'LTC', + // BaseCurrency: 'USDT', + // MarketCurrencyLong: 'Litecoin', + // BaseCurrencyLong: 'Tether' } const id = this.safeString (market, 'MarketName'); const baseId = this.safeString (market, 'MarketCurrency'); const quoteId = this.safeString (market, 'BaseCurrency'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const symbol = base + '/' + quote; - let pricePrecision = 8; - if (quote in this.options['pricePrecisionByCode']) { - pricePrecision = this.options['pricePrecisionByCode'][quote]; - } const precision = { 'amount': 8, - 'price': pricePrecision, + 'price': 8, }; - // bittrex uses boolean values, bleutrade uses strings - let active = this.safeValue (market, 'IsActive', false); - if ((active !== 'false') && active) { - active = true; - } else { - active = false; - } + const active = this.safeValue (market, 'IsActive', false); result.push ({ 'id': id, 'symbol': symbol, @@ -25711,6 +27344,8 @@ module.exports = class bleutrade extends bittrex { 'active': active, 'info': market, 'precision': precision, + 'maker': this.fees['trading']['maker'], + 'taker': this.fees['trading']['taker'], 'limits': { 'amount': { 'min': this.safeFloat (market, 'MinTradeSize'), @@ -25726,51 +27361,6 @@ module.exports = class bleutrade extends bittrex { return result; } - parseOrderStatus (status) { - const statuses = { - 'OK': 'closed', - 'OPEN': 'open', - 'CANCELED': 'canceled', - }; - return this.safeString (statuses, status, status); - } - - async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - // Possible params - // orderstatus (ALL, OK, OPEN, CANCELED) - // ordertype (ALL, BUY, SELL) - // depth (optional, default is 500, max is 20000) - await this.loadMarkets (); - let market = undefined; - let marketId = 'ALL'; - if (symbol !== undefined) { - market = this.market (symbol); - marketId = market['id']; - } - const request = { - 'market': marketId, - 'orderstatus': 'ALL', - }; - const response = await this.accountGetOrders (this.extend (request, params)); - return this.parseOrders (response['result'], market, since, limit); - } - - async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - const response = await this.fetchOrders (symbol, since, limit, params); - return this.filterBy (response, 'status', 'closed'); - } - - getOrderIdField () { - return 'orderid'; - } - - parseSymbol (id) { - let [ base, quote ] = id.split (this.options['symbolSeparator']); - base = this.safeCurrencyCode (base); - quote = this.safeCurrencyCode (quote); - return base + '/' + quote; - } - async fetchOrderBook (symbol, limit = undefined, params = {}) { await this.loadMarkets (); const request = { @@ -25780,43 +27370,104 @@ module.exports = class bleutrade extends bittrex { if (limit !== undefined) { request['depth'] = limit; // 50 } - const response = await this.publicGetOrderbook (this.extend (request, params)); + const response = await this.v3PublicGetGetorderbook (this.extend (request, params)); const orderbook = this.safeValue (response, 'result'); if (!orderbook) { - throw new ExchangeError (this.id + ' publicGetOrderbook() returneded no result ' + this.json (response)); + throw new ExchangeError (this.id + ' no orderbook data in ' + this.json (response)); } return this.parseOrderBook (orderbook, undefined, 'buy', 'sell', 'Rate', 'Quantity'); } - async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { - // Currently we can't set the makerOrTaker field, but if the user knows the order side then it can be - // determined (if the side of the trade is different to the side of the order, then the trade is maker). - // Similarly, the correct 'side' for the trade is that of the order. - // The trade fee can be set by the user, it is always 0.25% and is taken in the quote currency. + async fetchTicker (symbol, params = {}) { await this.loadMarkets (); + const market = this.market (symbol); const request = { - 'orderid': id, + 'market': market['id'], }; - const response = await this.accountGetOrderhistory (this.extend (request, params)); - return this.parseTrades (response['result'], undefined, since, limit, { - 'order': id, - }); + const response = await this.v3PublicGetGetmarketsummary (this.extend (request, params)); + const ticker = response['result'][0]; + return this.parseTicker (ticker, market); } - async fetchTransactionsByType (type, code = undefined, since = undefined, limit = undefined, params = {}) { + async fetchTickers (symbols = undefined, params = {}) { await this.loadMarkets (); - const method = (type === 'deposit') ? 'accountGetDeposithistory' : 'accountGetWithdrawhistory'; - const response = await this[method] (params); - const result = this.parseTransactions (response['result']); - return this.filterByCurrencySinceLimit (result, code, since, limit); + const response = await this.v3PublicGetGetmarketsummaries (params); + const result = this.safeValue (response, 'result'); + const tickers = []; + for (let i = 0; i < result.length; i++) { + const ticker = this.parseTicker (result[i]); + tickers.push (ticker); + } + return this.filterByArray (tickers, 'symbol', symbols); } - async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { - return await this.fetchTransactionsByType ('deposit', code, since, limit, params); - } - - async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { - return await this.fetchTransactionsByType ('withdrawal', code, since, limit, params); + parseTicker (ticker, market = undefined) { + // { TimeStamp: '2020-01-14 14:32:28', + // MarketName: 'LTC_USDT', + // MarketAsset: 'LTC', + // BaseAsset: 'USDT', + // MarketAssetName: 'Litecoin', + // BaseAssetName: 'Tether', + // PrevDay: 49.2867503, + // High: 56.78622664, + // Low: 49.27384025, + // Last: 53.94, + // Average: 51.37509368, + // Volume: 1.51282404, + // BaseVolume: 77.72147677, + // Bid: 53.62070218, + // Ask: 53.94, + // IsActive: 'true', + // InfoMessage: '', + // MarketCurrency: 'Litecoin', + // BaseCurrency: 'Tether' } + const timestamp = this.parse8601 (this.safeString (ticker, 'TimeStamp')); + let symbol = undefined; + const marketId = this.safeString (ticker, 'MarketName'); + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } else { + symbol = this.parseSymbol (marketId); + } + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const previous = this.safeFloat (ticker, 'PrevDay'); + const last = this.safeFloat (ticker, 'Last'); + let change = undefined; + let percentage = undefined; + if (last !== undefined) { + if (previous !== undefined) { + change = last - previous; + if (previous > 0) { + percentage = (change / previous) * 100; + } + } + } + return { + 'symbol': symbol, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'high': this.safeFloat (ticker, 'High'), + 'low': this.safeFloat (ticker, 'Low'), + 'bid': this.safeFloat (ticker, 'Bid'), + 'bidVolume': undefined, + 'ask': this.safeFloat (ticker, 'Ask'), + 'askVolume': undefined, + 'vwap': undefined, + 'open': previous, + 'close': last, + 'last': last, + 'previousClose': undefined, + 'change': change, + 'percentage': percentage, + 'average': undefined, + 'baseVolume': this.safeFloat (ticker, 'Volume'), + 'quoteVolume': this.safeFloat (ticker, 'BaseVolume'), + 'info': ticker, + }; } parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) { @@ -25839,49 +27490,133 @@ module.exports = class bleutrade extends bittrex { 'market': market['id'], 'count': limit, }; - const response = await this.publicGetCandles (this.extend (request, params)); - if ('result' in response) { - if (response['result']) { - return this.parseOHLCVs (response['result'], market, timeframe, since, limit); - } - } + const response = await this.v3PublicGetGetcandles (this.extend (request, params)); + return this.parseOHLCVs (response['result'], market, timeframe, since, limit); } - parseTrade (trade, market = undefined) { - const timestamp = this.parse8601 (trade['TimeStamp'] + '+00:00'); - let side = undefined; - if (trade['OrderType'] === 'BUY') { - side = 'buy'; - } else if (trade['OrderType'] === 'SELL') { - side = 'sell'; + async createOrder (symbol, type, side, amount, price = undefined, params = {}) { + if (type !== 'limit') { + // todo: STOP-LIMIT and AMI order types are supported + throw new InvalidOrder (this.id + ' allows limit orders only'); } - const id = this.safeString2 (trade, 'TradeID', 'ID'); - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; - } - let cost = undefined; - const price = this.safeFloat (trade, 'Price'); - const amount = this.safeFloat (trade, 'Quantity'); - if (amount !== undefined) { - if (price !== undefined) { - cost = price * amount; - } + await this.loadMarkets (); + const request = { + 'rate': this.priceToPrecision (symbol, price), + 'quantity': this.amountToPrecision (symbol, amount), + 'tradeType': (side === 'buy') ? '1' : '0', + 'market': this.marketId (symbol), + }; + let response = undefined; + if (side === 'buy') { + response = await this.v3PrivatePostBuylimit (this.extend (request, params)); + } else { + response = await this.v3PrivatePostSelllimit (this.extend (request, params)); } + // { success: true, + // message: "", + // result: "161105236" }, return { - 'id': id, - 'info': trade, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': symbol, - 'type': 'limit', - 'side': side, - 'order': undefined, - 'takerOrMaker': undefined, - 'price': price, - 'amount': amount, - 'cost': cost, - 'fee': undefined, + 'info': response, + 'id': this.safeString (response, 'result'), + }; + } + + async cancelOrder (id, symbol = undefined, params = {}) { + const request = { + 'orderid': id, + }; + const response = await this.v3PrivatePostOrdercancel (this.extend (request, params)); + // { success: true, message: '', result: '' } + return response; + } + + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let market = undefined; + const request = {}; + if (symbol !== undefined) { + market = this.market (symbol); + request['market'] = market['id']; + } + const response = await this.v3PrivatePostGetopenorders (this.extend (request, params)); + const items = this.safeValue (response, 'result', []); + return this.parseOrders (items, market, since, limit); + } + + parseSymbol (id) { + let [ base, quote ] = id.split (this.options['symbolSeparator']); + base = this.safeCurrencyCode (base); + quote = this.safeCurrencyCode (quote); + return base + '/' + quote; + } + + async fetchBalance (params = {}) { + await this.loadMarkets (); + const response = await this.v3PrivatePostGetbalances (params); + const result = { 'info': response }; + const items = response['result']; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + const currencyId = this.safeString (item, 'Asset'); + const code = this.safeCurrencyCode (currencyId); + const account = this.account (); + account['free'] = this.safeFloat (item, 'Available'); + account['total'] = this.safeFloat (item, 'Balance'); + result[code] = account; + } + return this.parseBalance (result); + } + + async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = {}; + let market = undefined; + if (symbol !== undefined) { + market = this.market (symbol); + request['market'] = market['id']; + } + const response = await this.v3PrivatePostGetcloseorders (this.extend (request, params)); + const orders = this.safeValue (response, 'result', []); + return this.parseOrders (orders, market, since, limit); + } + + async fetchTransactionsWithMethod (method, code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const response = await this[method] (params); + const transactions = this.safeValue (response, 'result', []); + return this.parseTransactions (transactions, code, since, limit); + } + + async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { + return await this.fetchTransactionsWithMethod ('v3PrivatePostGetdeposithistory', code, since, limit, params); + } + + async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { + return await this.fetchTransactionsWithMethod ('v3PrivatePostGetwithdrawhistory', code, since, limit, params); + } + + async fetchDepositAddress (code, params = {}) { + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'asset': currency['id'], + }; + const response = await this.v3PrivatePostGetdepositaddress (this.extend (request, params)); + // { success: true, + // message: '', + // result: + // { Asset: 'ETH', + // AssetName: 'Ethereum', + // DepositAddress: '0x748c5c8jhksjdfhd507d3aa9', + // Currency: 'ETH', + // CurrencyName: 'Ethereum' } } + const item = response['result']; + const address = this.safeString (item, 'DepositAddress'); + return { + 'currency': code, + 'address': this.checkAddress (address), + // 'tag': tag, + 'info': item, }; } @@ -25959,7 +27694,7 @@ module.exports = class bleutrade extends bittrex { 'currency': code, }; } else if (part.indexOf ('order id') === 0) { - referenceId = part.replace ('order id', ''); + referenceId = part.replace ('order id ', ''); } // // does not belong to Ledger, related to parseTransaction @@ -26002,64 +27737,44 @@ module.exports = class bleutrade extends bittrex { } async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) { - // - // if (code === undefined) { - // throw new ExchangeError (this.id + ' fetchClosedOrders requires a `symbol` argument'); - // } - // await this.loadMarkets (); - const request = {}; - // - // if (code !== undefined) { - // const currency = this.market (code); - // request['asset'] = currency['id']; - // } - // - const response = await this.v3PrivateGetGetmytransactions (this.extend (request, params)); - return this.parseLedger (response['result'], code, since, limit); + // only seems to return 100 items and there is no documented way to change page size or offset + const request = { + }; + const response = await this.v3PrivatePostGetmytransactions (this.extend (request, params)); + const items = response['result']; + return this.parseLedger (items, code, since, limit); } parseOrder (order, market = undefined) { // - // fetchOrders + // fetchClosedOrders // - // { - // OrderId: '107220258', - // Exchange: 'LTC_BTC', - // Type: 'SELL', - // Quantity: '2.13040000', - // QuantityRemaining: '0.00000000', - // Price: '0.01332672', - // Status: 'OK', - // Created: '2018-06-30 04:55:50', - // QuantityBaseTraded: '0.02839125', - // Comments: '' - // } + // { OrderID: 89742658, + // Exchange: 'DOGE_BTC', + // Type: 'BUY', + // Quantity: 10000, + // QuantityRemaining: 0, + // QuantityBaseTraded: 0, + // Price: 6.6e-7, + // Status: 'OK', + // Created: '2018-02-16 08:55:36', + // Comments: '' } // - let side = this.safeString2 (order, 'OrderType', 'Type'); - const isBuyOrder = (side === 'LIMIT_BUY') || (side === 'BUY'); - const isSellOrder = (side === 'LIMIT_SELL') || (side === 'SELL'); - if (isBuyOrder) { - side = 'buy'; - } - if (isSellOrder) { - side = 'sell'; - } - // We parse different fields in a very specific order. - // Order might well be closed and then canceled. - let status = undefined; - if (('Opened' in order) && order['Opened']) { - status = 'open'; - } - if (('Closed' in order) && order['Closed']) { - status = 'closed'; - } - if (('CancelInitiated' in order) && order['CancelInitiated']) { - status = 'canceled'; - } - if (('Status' in order) && this.options['parseOrderStatus']) { - status = this.parseOrderStatus (this.safeString (order, 'Status')); - } + // fetchOpenOrders + // + // { OrderID: 161105302, + // Exchange: 'ETH_BTC', + // Type: 'SELL', + // Quantity: 0.4, + // QuantityRemaining: 0.4, + // QuantityBaseTraded: 0, + // Price: 0.04, + // Status: 'OPEN', + // Created: '2020-01-22 09:21:27', + // Comments: { String: '', Valid: true } + const side = this.safeString (order, 'Type').toLowerCase (); + const status = this.parseOrderStatus (this.safeString (order, 'Status')); let symbol = undefined; const marketId = this.safeString (order, 'Exchange'); if (marketId === undefined) { @@ -26075,41 +27790,9 @@ module.exports = class bleutrade extends bittrex { } } let timestamp = undefined; - if ('Opened' in order) { - timestamp = this.parse8601 (order['Opened'] + '+00:00'); - } if ('Created' in order) { timestamp = this.parse8601 (order['Created'] + '+00:00'); } - let lastTradeTimestamp = undefined; - if (('TimeStamp' in order) && (order['TimeStamp'] !== undefined)) { - lastTradeTimestamp = this.parse8601 (order['TimeStamp'] + '+00:00'); - } - if (('Closed' in order) && (order['Closed'] !== undefined)) { - lastTradeTimestamp = this.parse8601 (order['Closed'] + '+00:00'); - } - if (timestamp === undefined) { - timestamp = lastTradeTimestamp; - } - let fee = undefined; - let commission = undefined; - if ('Commission' in order) { - commission = 'Commission'; - } else if ('CommissionPaid' in order) { - commission = 'CommissionPaid'; - } - if (commission) { - fee = { - 'cost': this.safeFloat (order, commission), - }; - if (market !== undefined) { - fee['currency'] = market['quote']; - } else if (symbol !== undefined) { - const currencyIds = symbol.split ('/'); - const quoteCurrencyId = currencyIds[1]; - fee['currency'] = this.safeCurrencyCode (quoteCurrencyId); - } - } let price = this.safeFloat (order, 'Price'); let cost = undefined; const amount = this.safeFloat (order, 'Quantity'); @@ -26129,13 +27812,14 @@ module.exports = class bleutrade extends bittrex { } } const average = this.safeFloat (order, 'PricePerUnit'); - const id = this.safeString2 (order, 'OrderUuid', 'OrderId'); + const id = this.safeString (order, 'OrderID'); return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), - 'lastTradeTimestamp': lastTradeTimestamp, + 'lastTradeTimestamp': undefined, 'symbol': symbol, 'type': 'limit', 'side': side, @@ -26146,54 +27830,56 @@ module.exports = class bleutrade extends bittrex { 'filled': filled, 'remaining': remaining, 'status': status, - 'fee': fee, + 'fee': undefined, + 'trades': undefined, }; } + parseOrderStatus (status) { + const statuses = { + 'OK': 'closed', + 'OPEN': 'open', + 'CANCELED': 'canceled', + }; + return this.safeString (statuses, status, status); + } + parseTransaction (transaction, currency = undefined) { // // deposit: // - // { - // Id: '96974373', - // Coin: 'DOGE', - // Amount: '12.05752192', - // TimeStamp: '2017-09-29 08:10:09', - // Label: 'DQqSjjhzCm3ozT4vAevMUHgv4vsi9LBkoE', - // } + // { ID: 118698752, + // Timestamp: '2020-01-21 11:16:09', + // Asset: 'ETH', + // Amount: 1, + // TransactionID: '', + // Status: 'CONFIRMED', + // Label: '0x748c5c8228d0c596f4d07f338blah', + // Symbol: 'ETH' } // // withdrawal: // - // { - // Id: '98009125', - // Coin: 'DOGE', - // Amount: '-483858.64312050', - // TimeStamp: '2017-11-22 22:29:05', - // Label: '483848.64312050;DJVJZ58tJC8UeUv9Tqcdtn6uhWobouxFLT;10.00000000', - // TransactionId: '8563105276cf798385fee7e5a563c620fea639ab132b089ea880d4d1f4309432', - // } + // { ID: 689281, + // Timestamp: '2019-07-05 13:14:43', + // Asset: 'BTC', + // Amount: -0.108959, + // TransactionID: 'da48d6901fslfjsdjflsdjfls852b87e362cad1', + // Status: 'CONFIRMED', + // Label: '0.1089590;35wztHPMgrebFvvblah;0.00100000', + // Symbol: 'BTC' } // - // { - // "Id": "95820181", - // "Coin": "BTC", - // "Amount": "-0.71300000", - // "TimeStamp": "2017-07-19 17:14:24", - // "Label": "0.71200000;PER9VM2txt4BTdfyWgvv3GziECRdVEPN63;0.00100000", - // "TransactionId": "CANCELED" - // } - // - const id = this.safeString (transaction, 'Id'); + const id = this.safeString (transaction, 'ID'); let amount = this.safeFloat (transaction, 'Amount'); let type = 'deposit'; if (amount < 0) { amount = Math.abs (amount); type = 'withdrawal'; } - const currencyId = this.safeString (transaction, 'Coin'); + const currencyId = this.safeString (transaction, 'Asset'); const code = this.safeCurrencyCode (currencyId, currency); const label = this.safeString (transaction, 'Label'); - const timestamp = this.parse8601 (this.safeString (transaction, 'TimeStamp')); - let txid = this.safeString (transaction, 'TransactionId'); + const timestamp = this.parse8601 (this.safeString (transaction, 'Timestamp')); + let txid = this.safeString (transaction, 'TransactionID'); let address = undefined; let feeCost = undefined; const labelParts = label.split (';'); @@ -26233,36 +27919,58 @@ module.exports = class bleutrade extends bittrex { }; } + nonce () { + return this.milliseconds (); + } + sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { let url = this.implodeParams (this.urls['api'][api], { 'hostname': this.hostname, }) + '/'; - if (api === 'v3Private' || api === 'account') { + if (api === 'v3Private') { this.checkRequiredCredentials (); - if (api === 'account') { - url += api + '/'; - } - if (((api === 'account') && (path !== 'withdraw')) || (path === 'openorders')) { - url += method.toLowerCase (); - } const request = { 'apikey': this.apiKey, + 'nonce': this.nonce (), }; - request['nonce'] = this.nonce (); url += path + '?' + this.urlencode (this.extend (request, params)); const signature = this.hmac (this.encode (url), this.encode (this.secret), 'sha512'); headers = { 'apisign': signature }; } else { - url += api + '/' + method.toLowerCase () + path; - if (Object.keys (params).length) { - url += '?' + this.urlencode (params); - } + url += path + '?' + this.urlencode (params); } return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } + + handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (response === undefined) { + return; // fallback to default error handler + } + // examples... + // {"success":false,"message":"Erro: Order is not open.","result":""} <-- 'error' is spelt wrong + // {"success":false,"message":"Error: Very low volume.","result":"ERR_LOW_VOLUME"} + // {"success":false,"message":"Error: Insuficient Balance","result":"ERR_INSUFICIENT_BALANCE"} + // + if (body[0] === '{') { + const success = this.safeValue (response, 'success'); + if (success === undefined) { + throw new ExchangeError (this.id + ': malformed response: ' + this.json (response)); + } + if (!success) { + const feedback = this.id + ' ' + body; + const errorCode = this.safeString (response, 'result'); + this.throwBroadlyMatchedException (this.exceptions['broad'], errorCode, feedback); + this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback); + const errorMessage = this.safeString (response, 'message'); + this.throwBroadlyMatchedException (this.exceptions['broad'], errorMessage, feedback); + this.throwExactlyMatchedException (this.exceptions['exact'], errorMessage, feedback); + throw new ExchangeError (feedback); + } + } + } }; -},{"./base/errors":9,"./bittrex.js":44}],48:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],48:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -26717,6 +28425,7 @@ module.exports = class braziliex extends Exchange { const status = (filledPercentage === 1.0) ? 'closed' : 'open'; return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -26732,6 +28441,7 @@ module.exports = class braziliex extends Exchange { 'trades': undefined, 'fee': fee, 'info': info, + 'average': undefined, }; } @@ -26855,7 +28565,7 @@ module.exports = class braziliex extends Exchange { headers = { 'Content-type': 'application/x-www-form-urlencoded', 'Key': this.apiKey, - 'Sign': this.decode (signature), + 'Sign': signature, }; } return { 'url': url, 'method': method, 'body': body, 'headers': headers }; @@ -26880,7 +28590,7 @@ module.exports = class braziliex extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],49:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],49:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -27034,6 +28744,8 @@ module.exports = class btcalpha extends Exchange { }, }, 'info': market, + 'baseId': undefined, + 'quoteId': undefined, }); } return result; @@ -27198,6 +28910,7 @@ module.exports = class btcalpha extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'status': status, @@ -27212,6 +28925,8 @@ module.exports = class btcalpha extends Exchange { 'trades': trades, 'fee': undefined, 'info': order, + 'lastTradeTimestamp': undefined, + 'average': undefined, }; } @@ -27353,7 +29068,7 @@ module.exports = class btcalpha extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],50:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],50:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -27598,7 +29313,16 @@ module.exports = class btcbox extends Exchange { parseOrder (order, market = undefined) { // - // {"id":11,"datetime":"2014-10-21 10:47:20","type":"sell","price":42000,"amount_original":1.2,"amount_outstanding":1.2,"status":"closed","trades":[]} + // { + // "id":11, + // "datetime":"2014-10-21 10:47:20", + // "type":"sell", + // "price":42000, + // "amount_original":1.2, + // "amount_outstanding":1.2, + // "status":"closed", + // "trades":[] + // } // const id = this.safeString (order, 'id'); const datetimeString = this.safeString (order, 'datetime'); @@ -27637,6 +29361,7 @@ module.exports = class btcbox extends Exchange { const side = this.safeString (order, 'type'); return { 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -27652,6 +29377,7 @@ module.exports = class btcbox extends Exchange { 'trades': trades, 'fee': undefined, 'info': order, + 'average': undefined, }; } @@ -27761,383 +29487,14 @@ module.exports = class btcbox extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],51:[function(require,module,exports){ -'use strict'; - -// --------------------------------------------------------------------------- - -const Exchange = require ('./base/Exchange'); - -// --------------------------------------------------------------------------- - -module.exports = class btcchina extends Exchange { - describe () { - return this.deepExtend (super.describe (), { - 'id': 'btcchina', - 'name': 'BTCChina', - 'countries': [ 'CN' ], - 'rateLimit': 1500, - 'version': 'v1', - 'has': { - 'CORS': true, - }, - 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/27766368-465b3286-5ed6-11e7-9a11-0f6467e1d82b.jpg', - 'api': { - 'plus': 'https://plus-api.btcchina.com/market', - 'public': 'https://data.btcchina.com/data', - 'private': 'https://api.btcchina.com/api_trade_v1.php', - }, - 'www': 'https://www.btcchina.com', - 'doc': 'https://www.btcchina.com/apidocs', - }, - 'api': { - 'plus': { - 'get': [ - 'orderbook', - 'ticker', - 'trade', - ], - }, - 'public': { - 'get': [ - 'historydata', - 'orderbook', - 'ticker', - 'trades', - ], - }, - 'private': { - 'post': [ - 'BuyIcebergOrder', - 'BuyOrder', - 'BuyOrder2', - 'BuyStopOrder', - 'CancelIcebergOrder', - 'CancelOrder', - 'CancelStopOrder', - 'GetAccountInfo', - 'getArchivedOrder', - 'getArchivedOrders', - 'GetDeposits', - 'GetIcebergOrder', - 'GetIcebergOrders', - 'GetMarketDepth', - 'GetMarketDepth2', - 'GetOrder', - 'GetOrders', - 'GetStopOrder', - 'GetStopOrders', - 'GetTransactions', - 'GetWithdrawal', - 'GetWithdrawals', - 'RequestWithdrawal', - 'SellIcebergOrder', - 'SellOrder', - 'SellOrder2', - 'SellStopOrder', - ], - }, - }, - 'markets': { - 'BTC/CNY': { 'id': 'btccny', 'symbol': 'BTC/CNY', 'base': 'BTC', 'quote': 'CNY', 'api': 'public', 'plus': false }, - 'LTC/CNY': { 'id': 'ltccny', 'symbol': 'LTC/CNY', 'base': 'LTC', 'quote': 'CNY', 'api': 'public', 'plus': false }, - 'LTC/BTC': { 'id': 'ltcbtc', 'symbol': 'LTC/BTC', 'base': 'LTC', 'quote': 'BTC', 'api': 'public', 'plus': false }, - 'BCH/CNY': { 'id': 'bcccny', 'symbol': 'BCH/CNY', 'base': 'BCH', 'quote': 'CNY', 'api': 'plus', 'plus': true }, - 'ETH/CNY': { 'id': 'ethcny', 'symbol': 'ETH/CNY', 'base': 'ETH', 'quote': 'CNY', 'api': 'plus', 'plus': true }, - }, - }); - } - - async fetchMarkets (params = {}) { - const request = { - 'market': 'all', - }; - const markets = await this.publicGetTicker (this.extend (request, params)); - const result = []; - const keys = Object.keys (markets); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - const market = markets[key]; - const parts = key.split ('_'); - const id = parts[1]; - const baseId = id.slice (0, 3); - const quoteId = id.slice (3, 6); - let base = baseId.toUpperCase (); - let quote = quoteId.toUpperCase (); - base = this.safeCurrencyCode (base); - quote = this.safeCurrencyCode (quote); - const symbol = base + '/' + quote; - result.push ({ - 'id': id, - 'symbol': symbol, - 'base': base, - 'quote': quote, - 'baseId': baseId, - 'quoteId': quoteId, - 'info': market, - }); - } - return result; - } - - async fetchBalance (params = {}) { - await this.loadMarkets (); - const response = await this.privatePostGetAccountInfo (params); - const balances = this.safeValue (response, 'result'); - const result = { 'info': balances }; - const codes = Object.keys (this.currencies); - for (let i = 0; i < codes.length; i++) { - const code = codes[i]; - const currency = this.currency (code); - const account = this.account (); - const currencyId = currency['id']; - if (currencyId in balances['balance']) { - account['total'] = parseFloat (balances['balance'][currencyId]['amount']); - } - if (currencyId in balances['frozen']) { - account['used'] = parseFloat (balances['frozen'][currencyId]['amount']); - } - result[code] = account; - } - return this.parseBalance (result); - } - - createMarketRequest (market) { - const request = {}; - const field = (market['plus']) ? 'symbol' : 'market'; - request[field] = market['id']; - return request; - } - - async fetchOrderBook (symbol, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['api'] + 'GetOrderbook'; - const request = this.createMarketRequest (market); - const response = await this[method] (this.extend (request, params)); - const timestamp = this.safeTimestamp (response, 'date'); - return this.parseOrderBook (response, timestamp); - } - - parseTicker (ticker, market) { - const timestamp = this.safeTimestamp (ticker, 'date'); - const last = this.safeFloat (ticker, 'last'); - return { - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'high': this.safeFloat (ticker, 'high'), - 'low': this.safeFloat (ticker, 'low'), - 'bid': this.safeFloat (ticker, 'buy'), - 'ask': this.safeFloat (ticker, 'sell'), - 'vwap': this.safeFloat (ticker, 'vwap'), - 'open': this.safeFloat (ticker, 'open'), - 'close': last, - 'last': last, - 'previousClose': undefined, - 'change': undefined, - 'percentage': undefined, - 'average': undefined, - 'baseVolume': this.safeFloat (ticker, 'vol'), - 'quoteVolume': undefined, - 'info': ticker, - }; - } - - parseTickerPlus (ticker, market) { - const timestamp = this.safeInteger (ticker, 'Timestamp'); - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; - } - return { - 'symbol': symbol, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'high': this.safeFloat (ticker, 'High'), - 'low': this.safeFloat (ticker, 'Low'), - 'bid': this.safeFloat (ticker, 'BidPrice'), - 'ask': this.safeFloat (ticker, 'AskPrice'), - 'vwap': undefined, - 'open': this.safeFloat (ticker, 'Open'), - 'last': this.safeFloat (ticker, 'Last'), - 'change': undefined, - 'percentage': undefined, - 'average': undefined, - 'baseVolume': this.safeFloat (ticker, 'Volume24H'), - 'quoteVolume': undefined, - 'info': ticker, - }; - } - - async fetchTicker (symbol, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['api'] + 'GetTicker'; - const request = this.createMarketRequest (market); - const response = await this[method] (this.extend (request, params)); - const ticker = this.safeValue (response, 'ticker'); - if (market['plus']) { - return this.parseTickerPlus (ticker, market); - } - return this.parseTicker (ticker, market); - } - - parseTrade (trade, market) { - const timestamp = this.safeTimestamp (trade, 'date'); - const price = this.safeFloat (trade, 'price'); - const amount = this.safeFloat (trade, 'amount'); - let cost = undefined; - if (amount !== undefined) { - if (price !== undefined) { - cost = amount * price; - } - } - const id = this.safeString (trade, 'tid'); - return { - 'id': id, - 'info': trade, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': market['symbol'], - 'type': undefined, - 'side': undefined, - 'price': price, - 'amount': amount, - 'cost': cost, - }; - } - - parseTradePlus (trade, market) { - const timestamp = this.parse8601 (this.safeString (trade, 'timestamp')); - const price = this.safeFloat (trade, 'price'); - const amount = this.safeFloat (trade, 'size'); - let cost = undefined; - if (amount !== undefined) { - if (price !== undefined) { - cost = amount * price; - } - } - const side = this.safeStringLower (trade, 'side'); - return { - 'id': undefined, - 'info': trade, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': market['symbol'], - 'type': undefined, - 'side': side, - 'price': price, - 'amount': amount, - 'cost': cost, - }; - } - - parseTradesPlus (trades, market = undefined) { - const result = []; - for (let i = 0; i < trades.length; i++) { - result.push (this.parseTradePlus (trades[i], market)); - } - return result; - } - - async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - let method = market['api'] + 'GetTrade'; - const request = this.createMarketRequest (market); - if (market['plus']) { - const now = this.milliseconds (); - request['start_time'] = now - 86400000; - request['end_time'] = now; - } else { - method += 's'; // trades vs trade - } - const response = await this[method] (this.extend (request, params)); - if (market['plus']) { - return this.parseTradesPlus (response['trades'], market); - } - return this.parseTrades (response, market, since, limit); - } - - async createOrder (symbol, type, side, amount, price = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = 'privatePost' + this.capitalize (side) + 'Order2'; - const request = {}; - const id = market['id'].toUpperCase (); - if (type === 'market') { - request['params'] = [ undefined, amount, id ]; - } else { - request['params'] = [ price, amount, id ]; - } - const response = await this[method] (this.extend (request, params)); - const orderId = this.safeString (response, 'id'); - return { - 'info': response, - 'id': orderId, - }; - } - - async cancelOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - const market = params['market']; // TODO fixme - const request = { - 'params': [ id, market ], - }; - return await this.privatePostCancelOrder (this.extend (request, params)); - } - - nonce () { - return this.microseconds (); - } - - sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = this.urls['api'][api] + '/' + path; - if (api === 'private') { - this.checkRequiredCredentials (); - let p = []; - if ('params' in params) { - p = params['params']; - } - const nonce = this.nonce (); - const request = { - 'method': path, - 'id': nonce, - 'params': p, - }; - p = p.join (','); - body = this.json (request); - const query = [ - 'tonce=' + nonce, - 'accesskey=' + this.apiKey, - 'requestmethod=' + method.toLowerCase (), - 'id=' + nonce, - 'method=' + path, - 'params=' + p, - ].join ('&'); - const signature = this.hmac (this.encode (query), this.encode (this.secret), 'sha1'); - const auth = this.encode (this.apiKey + ':' + signature); - headers = { - 'Authorization': 'Basic ' + this.stringToBase64 (auth), - 'Json-Rpc-Tonce': nonce, - }; - } else { - if (Object.keys (params).length) { - url += '?' + this.urlencode (params); - } - } - return { 'url': url, 'method': method, 'body': body, 'headers': headers }; - } -}; - -},{"./base/Exchange":7}],52:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],51:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); const { ExchangeError, OrderNotFound, ArgumentsRequired, InvalidOrder, DDoSProtection } = require ('./base/errors'); +const { ROUND } = require ('./base/functions/number'); // --------------------------------------------------------------------------- @@ -28549,7 +29906,7 @@ module.exports = class btcmarkets extends Exchange { } parseTrade (trade, market = undefined) { - const timestamp = this.safeTimestamp (trade, 'timestamp'); + const timestamp = this.safeTimestamp (trade, 'date'); let symbol = undefined; if (market !== undefined) { symbol = market['symbol']; @@ -28601,8 +29958,8 @@ module.exports = class btcmarkets extends Exchange { }); request['currency'] = market['quote']; request['instrument'] = market['base']; - request['price'] = parseInt (price * multiplier); - request['volume'] = parseInt (amount * multiplier); + request['price'] = parseInt (this.decimalToPrecision (price * multiplier, ROUND, 0)); + request['volume'] = parseInt (this.decimalToPrecision (amount * multiplier, ROUND, 0)); request['orderSide'] = orderSide; request['ordertype'] = this.capitalize (type); request['clientRequestId'] = this.nonce ().toString (); @@ -28698,6 +30055,7 @@ module.exports = class btcmarkets extends Exchange { 'currency': feeCurrencyCode, 'cost': feeCost, }, + 'takerOrMaker': undefined, }; } @@ -28745,9 +30103,11 @@ module.exports = class btcmarkets extends Exchange { lastTradeTimestamp = trades[numTrades - 1]['timestamp']; } const id = this.safeString (order, 'id'); + const clientOrderId = this.safeString (order, 'clientRequestId'); return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -28887,7 +30247,7 @@ module.exports = class btcmarkets extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],53:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],52:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -28960,7 +30320,7 @@ module.exports = class btctradeim extends coinegg { } }; -},{"./base/errors":9,"./coinegg.js":66}],54:[function(require,module,exports){ +},{"./base/errors":10,"./coinegg.js":65}],53:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -28978,7 +30338,7 @@ module.exports = class btctradeua extends Exchange { 'countries': [ 'UA' ], // Ukraine, 'rateLimit': 3000, 'has': { - 'CORS': true, + 'CORS': false, 'createMarketOrder': false, 'fetchOpenOrders': true, }, @@ -29283,6 +30643,7 @@ module.exports = class btctradeua extends Exchange { } return { 'id': this.safeString (order, 'id'), + 'clientOrderId': undefined, 'timestamp': timestamp, // until they fix their timestamp 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -29296,6 +30657,9 @@ module.exports = class btctradeua extends Exchange { 'remaining': this.safeFloat (order, 'amnt_trade'), 'trades': undefined, 'info': order, + 'cost': undefined, + 'average': undefined, + 'fee': undefined, }; } @@ -29342,7 +30706,7 @@ module.exports = class btctradeua extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],55:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],54:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -29665,7 +31029,7 @@ module.exports = class btcturk extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],56:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],55:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -30231,6 +31595,7 @@ module.exports = class buda extends Exchange { }; return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -30246,6 +31611,7 @@ module.exports = class buda extends Exchange { 'trades': undefined, 'fee': fee, 'info': order, + 'average': undefined, }; } @@ -30453,13 +31819,13 @@ module.exports = class buda extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],57:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],56:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { BadSymbol, ExchangeError, AuthenticationError, ArgumentsRequired, ExchangeNotAvailable } = require ('./base/errors'); +const { RateLimitExceeded, BadSymbol, OrderNotFound, ExchangeError, AuthenticationError, ArgumentsRequired, ExchangeNotAvailable } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -30533,18 +31899,10 @@ module.exports = class bw extends Exchange { }, 'fees': { 'trading': { - 'tierBased': true, + 'tierBased': false, 'percentage': true, 'taker': 0.2 / 100, 'maker': 0.2 / 100, - 'tiers': { - 'taker': [ - [ 0, 0.2 / 100 ], - ], - 'maker': [ - [ 0, 0.2 / 100 ], - ], - }, }, 'funding': { }, @@ -30553,7 +31911,9 @@ module.exports = class bw extends Exchange { 'exact': { '999': AuthenticationError, '1000': ExchangeNotAvailable, // {"datas":null,"resMsg":{"message":"getKlines error:data not exitsts\uff0cplease wait ,dataType=4002_KLINE_1M","method":null,"code":"1000"}} + '2012': OrderNotFound, // {"datas":null,"resMsg":{"message":"entrust not exists or on dealing with system","method":null,"code":"2012"}} '5017': BadSymbol, // {"datas":null,"resMsg":{"message":"market not exist","method":null,"code":"5017"}} + '10001': RateLimitExceeded, // {"resMsg":{"code":"10001","message":"API frequency limit"}} }, }, 'api': { @@ -30770,7 +32130,7 @@ module.exports = class bw extends Exchange { }, 'withdraw': { 'min': undefined, - 'max': parseFloat (this.safeInteger (currency, 'onceDrawLimit')), + 'max': this.safeFloat (currency, 'onceDrawLimit'), }, }, }; @@ -30799,8 +32159,10 @@ module.exports = class bw extends Exchange { if (marketId in this.markets_by_id) { market = this.markets_by_id[marketId]; } - if ((symbol === undefined) && (market !== undefined)) { + if (market !== undefined) { symbol = market['symbol']; + } else { + symbol = marketId; } const timestamp = this.milliseconds (); const close = parseFloat (this.safeValue (ticker, 1)); @@ -31070,7 +32432,7 @@ module.exports = class bw extends Exchange { const result = { 'info': response }; for (let i = 0; i < balances.length; i++) { const balance = balances[i]; - const currencyId = this.safeInteger (balance, 'currencyTypeId'); + const currencyId = this.safeString (balance, 'currencyTypeId'); const code = this.safeCurrencyCode (currencyId); const account = this.account (); account['free'] = this.safeFloat (balance, 'amount'); @@ -31126,6 +32488,7 @@ module.exports = class bw extends Exchange { 'status': 'open', 'fee': undefined, 'trades': undefined, + 'clientOrderId': undefined, }; } @@ -31195,6 +32558,7 @@ module.exports = class bw extends Exchange { return { 'info': order, 'id': this.safeString (order, 'entrustId'), + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -31642,7 +33006,1934 @@ module.exports = class bw extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],58:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],57:[function(require,module,exports){ +'use strict'; + +// --------------------------------------------------------------------------- + +const Exchange = require ('./base/Exchange'); +const { TICK_SIZE } = require ('./base/functions/number'); +const { AuthenticationError, ExchangeError, ArgumentsRequired, PermissionDenied, InvalidOrder, OrderNotFound, InsufficientFunds, BadRequest, RateLimitExceeded, InvalidNonce } = require ('./base/errors'); + +// --------------------------------------------------------------------------- + +module.exports = class bybit extends Exchange { + describe () { + return this.deepExtend (super.describe (), { + 'id': 'bybit', + 'name': 'Bybit', + 'countries': [ 'VG' ], // British Virgin Islands + 'version': 'v2', + 'userAgent': undefined, + 'rateLimit': 100, + 'has': { + 'CORS': true, + 'fetchMarkets': true, + 'fetchBalance': true, + 'fetchOHLCV': true, + 'editOrder': true, + 'fetchOrder': true, + 'fetchOrders': true, + 'fetchOpenOrders': true, + 'fetchClosedOrders': true, + 'fetchMyTrades': true, + 'fetchTicker': true, + 'fetchTickers': true, + 'fetchOrderTrades': true, + 'createOrder': true, + 'cancelOrder': true, + 'cancelAllOrders': true, + 'fetchTime': true, + 'fetchWithdrawals': true, + 'fetchDeposits': false, + 'fetchTransactions': false, + 'fetchLedger': true, + }, + 'timeframes': { + '1m': '1', + '3m': '3', + '5m': '5', + '15m': '15', + '30m': '30', + '1h': '60', + '2h': '120', + '3h': '180', + '6h': '360', + '12h': '720', + '1d': 'D', + '1w': 'W', + '1M': 'M', + '1y': 'Y', + }, + 'urls': { + 'test': 'https://api-testnet.bybit.com', + 'logo': 'https://user-images.githubusercontent.com/51840849/76547799-daff5b80-649e-11ea-87fb-3be9bac08954.jpg', + 'api': 'https://api.bybit.com', + 'www': 'https://www.bybit.com/', + 'doc': [ + 'https://bybit-exchange.github.io/docs/inverse/', + 'https://github.com/bybit-exchange', + ], + 'fees': 'https://help.bybit.com/hc/en-us/articles/360039261154', + 'referral': 'https://www.bybit.com/app/register?ref=X7Prm', + }, + 'api': { + 'public': { + 'get': [ + 'orderBook/L2', + 'kline/list', + 'tickers', + 'trading-records', + 'symbols', + 'time', + 'announcement', + ], + }, + 'private': { + 'get': [ + 'order', + 'stop-order', + 'position/list', + 'wallet/balance', + 'execution/list', + ], + 'post': [ + 'order/create', + 'order/cancel', + 'order/cancelAll', + 'stop-order/cancelAll', + ], + }, + 'openapi': { + 'get': [ + 'order/list', + 'stop-order/list', + 'wallet/risk-limit/list', + 'wallet/risk-limit', + 'funding/prev-funding-rate', + 'funding/prev-funding', + 'funding/predicted-funding', + 'api-key', + 'wallet/fund/records', + 'wallet/withdraw/list', + ], + 'post': [ + 'order/replace', + 'stop-order/create', + 'stop-order/cancel', + 'stop-order/replace', + 'position/trading-stop', + ], + }, + 'position': { + 'post': [ + 'change-position-margin', + ], + }, + 'user': { + 'get': [ + 'leverage', + ], + 'post': [ + 'leverage/save', + ], + }, + }, + 'httpExceptions': { + '403': RateLimitExceeded, // Forbidden -- You request too many times + }, + 'exceptions': { + 'exact': { + '10001': BadRequest, // parameter error + '10002': InvalidNonce, // request expired, check your timestamp and recv_window + '10003': AuthenticationError, // Invalid apikey + '10004': AuthenticationError, // invalid sign + '10005': PermissionDenied, // permission denied for current apikey + '10006': RateLimitExceeded, // too many requests + '10007': AuthenticationError, // api_key not found in your request parameters + '10010': PermissionDenied, // request ip mismatch + '10017': BadRequest, // request path not found or request method is invalid + '20001': OrderNotFound, // Order not exists + '20003': InvalidOrder, // missing parameter side + '20004': InvalidOrder, // invalid parameter side + '20005': InvalidOrder, // missing parameter symbol + '20006': InvalidOrder, // invalid parameter symbol + '20007': InvalidOrder, // missing parameter order_type + '20008': InvalidOrder, // invalid parameter order_type + '20009': InvalidOrder, // missing parameter qty + '20010': InvalidOrder, // qty must be greater than 0 + '20011': InvalidOrder, // qty must be an integer + '20012': InvalidOrder, // qty must be greater than zero and less than 1 million + '20013': InvalidOrder, // missing parameter price + '20014': InvalidOrder, // price must be greater than 0 + '20015': InvalidOrder, // missing parameter time_in_force + '20016': InvalidOrder, // invalid value for parameter time_in_force + '20017': InvalidOrder, // missing parameter order_id + '20018': InvalidOrder, // invalid date format + '20019': InvalidOrder, // missing parameter stop_px + '20020': InvalidOrder, // missing parameter base_price + '20021': InvalidOrder, // missing parameter stop_order_id + '20022': BadRequest, // missing parameter leverage + '20023': BadRequest, // leverage must be a number + '20031': BadRequest, // leverage must be greater than zero + '20070': BadRequest, // missing parameter margin + '20071': BadRequest, // margin must be greater than zero + '20084': BadRequest, // order_id or order_link_id is required + '30001': BadRequest, // order_link_id is repeated + '30003': InvalidOrder, // qty must be more than the minimum allowed + '30004': InvalidOrder, // qty must be less than the maximum allowed + '30005': InvalidOrder, // price exceeds maximum allowed + '30007': InvalidOrder, // price exceeds minimum allowed + '30008': InvalidOrder, // invalid order_type + '30009': ExchangeError, // no position found + '30010': InsufficientFunds, // insufficient wallet balance + '30011': PermissionDenied, // operation not allowed as position is undergoing liquidation + '30012': PermissionDenied, // operation not allowed as position is undergoing ADL + '30013': PermissionDenied, // position is in liq or adl status + '30014': InvalidOrder, // invalid closing order, qty should not greater than size + '30015': InvalidOrder, // invalid closing order, side should be opposite + '30016': ExchangeError, // TS and SL must be cancelled first while closing position + '30017': InvalidOrder, // estimated fill price cannot be lower than current Buy liq_price + '30018': InvalidOrder, // estimated fill price cannot be higher than current Sell liq_price + '30019': InvalidOrder, // cannot attach TP/SL params for non-zero position when placing non-opening position order + '30020': InvalidOrder, // position already has TP/SL params + '30021': InvalidOrder, // cannot afford estimated position_margin + '30022': InvalidOrder, // estimated buy liq_price cannot be higher than current mark_price + '30023': InvalidOrder, // estimated sell liq_price cannot be lower than current mark_price + '30024': InvalidOrder, // cannot set TP/SL/TS for zero-position + '30025': InvalidOrder, // trigger price should bigger than 10% of last price + '30026': InvalidOrder, // price too high + '30027': InvalidOrder, // price set for Take profit should be higher than Last Traded Price + '30028': InvalidOrder, // price set for Stop loss should be between Liquidation price and Last Traded Price + '30029': InvalidOrder, // price set for Stop loss should be between Last Traded Price and Liquidation price + '30030': InvalidOrder, // price set for Take profit should be lower than Last Traded Price + '30031': InsufficientFunds, // insufficient available balance for order cost + '30032': InvalidOrder, // order has been filled or cancelled + '30033': RateLimitExceeded, // The number of stop orders exceeds maximum limit allowed + '30034': OrderNotFound, // no order found + '30035': RateLimitExceeded, // too fast to cancel + '30036': ExchangeError, // the expected position value after order execution exceeds the current risk limit + '30037': InvalidOrder, // order already cancelled + '30041': ExchangeError, // no position found + '30042': InsufficientFunds, // insufficient wallet balance + '30043': PermissionDenied, // operation not allowed as position is undergoing liquidation + '30044': PermissionDenied, // operation not allowed as position is undergoing AD + '30045': PermissionDenied, // operation not allowed as position is not normal status + '30049': InsufficientFunds, // insufficient available balance + '30050': ExchangeError, // any adjustments made will trigger immediate liquidation + '30051': ExchangeError, // due to risk limit, cannot adjust leverage + '30052': ExchangeError, // leverage can not less than 1 + '30054': ExchangeError, // position margin is invalid + '30057': ExchangeError, // requested quantity of contracts exceeds risk limit + '30063': ExchangeError, // reduce-only rule not satisfied + '30067': InsufficientFunds, // insufficient available balance + '30068': ExchangeError, // exit value must be positive + '34026': ExchangeError, // the limit is no change + }, + 'broad': { + 'unknown orderInfo': OrderNotFound, // {"ret_code":-1,"ret_msg":"unknown orderInfo","ext_code":"","ext_info":"","result":null,"time_now":"1584030414.005545","rate_limit_status":99,"rate_limit_reset_ms":1584030414003,"rate_limit":100} + }, + }, + 'precisionMode': TICK_SIZE, + 'options': { + 'code': 'BTC', + 'fetchBalance': { + 'code': 'BTC', + }, + 'cancelAllOrders': { + 'method': 'privatePostOrderCancelAll', // privatePostStopOrderCancelAll + }, + 'recvWindow': 5 * 1000, // 5 sec default + 'timeDifference': 0, // the difference between system clock and Binance clock + 'adjustForTimeDifference': false, // controls the adjustment logic upon instantiation + }, + 'fees': { + 'trading': { + 'tierBased': false, + 'percentage': true, + 'taker': 0.00075, + 'maker': -0.00025, + }, + 'funding': { + 'tierBased': false, + 'percentage': false, + 'withdraw': {}, + 'deposit': {}, + }, + }, + }); + } + + nonce () { + return this.milliseconds () - this.options['timeDifference']; + } + + async loadTimeDifference () { + const serverTime = await this.fetchTime (); + const after = this.milliseconds (); + this.options['timeDifference'] = after - serverTime; + return this.options['timeDifference']; + } + + async fetchTime (params = {}) { + const response = await this.publicGetTime (params); + // + // { + // ret_code: 0, + // ret_msg: 'OK', + // ext_code: '', + // ext_info: '', + // result: {}, + // time_now: '1583933682.448826' + // } + // + return this.safeTimestamp (response, 'time_now'); + } + + async fetchMarkets (params = {}) { + if (this.options['adjustForTimeDifference']) { + await this.loadTimeDifference (); + } + const response = await this.publicGetSymbols (params); + // + // { + // ret_code: 0, + // ret_msg: 'OK', + // ext_code: '', + // ext_info: '', + // result: [ + // { + // name: 'BTCUSD', + // base_currency: 'BTC', + // quote_currency: 'USD', + // price_scale: 2, + // taker_fee: '0.00075', + // maker_fee: '-0.00025', + // leverage_filter: { min_leverage: 1, max_leverage: 100, leverage_step: '0.01' }, + // price_filter: { min_price: '0.5', max_price: '999999.5', tick_size: '0.5' }, + // lot_size_filter: { max_trading_qty: 1000000, min_trading_qty: 1, qty_step: 1 } + // }, + // ], + // time_now: '1583930495.454196' + // } + // + const markets = this.safeValue (response, 'result', []); + const result = []; + for (let i = 0; i < markets.length; i++) { + const market = markets[i]; + const id = this.safeString (market, 'name'); + const baseId = this.safeString (market, 'base_currency'); + const quoteId = this.safeString (market, 'quote_currency'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + const symbol = base + '/' + quote; + const lotSizeFilter = this.safeValue (market, 'lot_size_filter', {}); + const priceFilter = this.safeValue (market, 'price_filter', {}); + const precision = { + 'amount': this.safeFloat (lotSizeFilter, 'qty_step'), + 'price': this.safeFloat (priceFilter, 'tick_size'), + }; + result.push ({ + 'id': id, + 'symbol': symbol, + 'base': base, + 'quote': quote, + 'active': undefined, + 'precision': precision, + 'taker': this.safeFloat (market, 'taker_fee'), + 'maker': this.safeFloat (market, 'maker_fee'), + 'limits': { + 'amount': { + 'min': this.safeFloat (lotSizeFilter, 'min_trading_qty'), + 'max': this.safeFloat (lotSizeFilter, 'max_trading_qty'), + }, + 'price': { + 'min': this.safeFloat (priceFilter, 'min_price'), + 'max': this.safeFloat (priceFilter, 'max_price'), + }, + 'cost': { + 'min': undefined, + 'max': undefined, + }, + }, + 'type': 'future', + 'spot': false, + 'future': true, + 'option': false, + 'info': market, + }); + } + return result; + } + + async fetchBalance (params = {}) { + await this.loadMarkets (); + const defaultCode = this.safeValue (this.options, 'code', 'BTC'); + const options = this.safeValue (this.options, 'fetchBalance', {}); + const code = this.safeValue (options, 'code', defaultCode); + const currency = this.currency (code); + const request = { + 'coin': currency['id'], + }; + const response = await this.privateGetWalletBalance (this.extend (request, params)); + // + // { + // ret_code: 0, + // ret_msg: 'OK', + // ext_code: '', + // ext_info: '', + // result: { + // BTC: { + // equity: 0, + // available_balance: 0, + // used_margin: 0, + // order_margin: 0, + // position_margin: 0, + // occ_closing_fee: 0, + // occ_funding_fee: 0, + // wallet_balance: 0, + // realised_pnl: 0, + // unrealised_pnl: 0, + // cum_realised_pnl: 0, + // given_cash: 0, + // service_cash: 0 + // } + // }, + // time_now: '1583937810.370020', + // rate_limit_status: 119, + // rate_limit_reset_ms: 1583937810367, + // rate_limit: 120 + // } + // + const result = { + 'info': response, + }; + const balances = this.safeValue (response, 'result', {}); + const currencyIds = Object.keys (balances); + for (let i = 0; i < currencyIds.length; i++) { + const currencyId = currencyIds[i]; + const balance = balances[currencyId]; + const code = this.safeCurrencyCode (currencyId); + const account = this.account (); + account['free'] = this.safeFloat (balance, 'available_balance'); + account['used'] = this.safeFloat (balance, 'used_margin'); + account['total'] = this.safeFloat (balance, 'equity'); + result[code] = account; + } + return this.parseBalance (result); + } + + parseTicker (ticker, market = undefined) { + // + // fetchTicker + // + // { + // symbol: 'BTCUSD', + // bid_price: '7680', + // ask_price: '7680.5', + // last_price: '7680.00', + // last_tick_direction: 'MinusTick', + // prev_price_24h: '7870.50', + // price_24h_pcnt: '-0.024204', + // high_price_24h: '8035.00', + // low_price_24h: '7671.00', + // prev_price_1h: '7780.00', + // price_1h_pcnt: '-0.012853', + // mark_price: '7683.27', + // index_price: '7682.74', + // open_interest: 188829147, + // open_value: '23670.06', + // total_turnover: '25744224.90', + // turnover_24h: '102997.83', + // total_volume: 225448878806, + // volume_24h: 809919408, + // funding_rate: '0.0001', + // predicted_funding_rate: '0.0001', + // next_funding_time: '2020-03-12T00:00:00Z', + // countdown_hour: 7 + // } + // + const timestamp = undefined; + const marketId = this.safeString (ticker, 'symbol'); + let symbol = marketId; + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const last = this.safeFloat (ticker, 'last_price'); + const open = this.safeFloat (ticker, 'prev_price_24h'); + let percentage = this.safeFloat (ticker, 'price_24h_pcnt'); + if (percentage !== undefined) { + percentage *= 100; + } + let change = undefined; + let average = undefined; + if ((last !== undefined) && (open !== undefined)) { + change = last - open; + average = this.sum (open, last) / 2; + } + const baseVolume = this.safeFloat (ticker, 'turnover_24h'); + const quoteVolume = this.safeFloat (ticker, 'volume_24h'); + let vwap = undefined; + if (quoteVolume !== undefined && baseVolume !== undefined) { + vwap = quoteVolume / baseVolume; + } + return { + 'symbol': symbol, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'high': this.safeFloat (ticker, 'high_price_24h'), + 'low': this.safeFloat (ticker, 'low_price_24h'), + 'bid': this.safeFloat (ticker, 'bid_price'), + 'bidVolume': undefined, + 'ask': this.safeFloat (ticker, 'ask_price'), + 'askVolume': undefined, + 'vwap': vwap, + 'open': open, + 'close': last, + 'last': last, + 'previousClose': undefined, + 'change': change, + 'percentage': percentage, + 'average': average, + 'baseVolume': baseVolume, + 'quoteVolume': quoteVolume, + 'info': ticker, + }; + } + + async fetchTicker (symbol, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.publicGetTickers (this.extend (request, params)); + // + // { + // ret_code: 0, + // ret_msg: 'OK', + // ext_code: '', + // ext_info: '', + // result: [ + // { + // symbol: 'BTCUSD', + // bid_price: '7680', + // ask_price: '7680.5', + // last_price: '7680.00', + // last_tick_direction: 'MinusTick', + // prev_price_24h: '7870.50', + // price_24h_pcnt: '-0.024204', + // high_price_24h: '8035.00', + // low_price_24h: '7671.00', + // prev_price_1h: '7780.00', + // price_1h_pcnt: '-0.012853', + // mark_price: '7683.27', + // index_price: '7682.74', + // open_interest: 188829147, + // open_value: '23670.06', + // total_turnover: '25744224.90', + // turnover_24h: '102997.83', + // total_volume: 225448878806, + // volume_24h: 809919408, + // funding_rate: '0.0001', + // predicted_funding_rate: '0.0001', + // next_funding_time: '2020-03-12T00:00:00Z', + // countdown_hour: 7 + // } + // ], + // time_now: '1583948195.818255' + // } + // + const result = this.safeValue (response, 'result', []); + const first = this.safeValue (result, 0); + const timestamp = this.safeTimestamp (response, 'time_now'); + const ticker = this.parseTicker (first, market); + ticker['timestamp'] = timestamp; + ticker['datetime'] = this.iso8601 (timestamp); + return ticker; + } + + async fetchTickers (symbols = undefined, params = {}) { + await this.loadMarkets (); + const response = await this.publicGetTickers (params); + // + // { + // ret_code: 0, + // ret_msg: 'OK', + // ext_code: '', + // ext_info: '', + // result: [ + // { + // symbol: 'BTCUSD', + // bid_price: '7680', + // ask_price: '7680.5', + // last_price: '7680.00', + // last_tick_direction: 'MinusTick', + // prev_price_24h: '7870.50', + // price_24h_pcnt: '-0.024204', + // high_price_24h: '8035.00', + // low_price_24h: '7671.00', + // prev_price_1h: '7780.00', + // price_1h_pcnt: '-0.012853', + // mark_price: '7683.27', + // index_price: '7682.74', + // open_interest: 188829147, + // open_value: '23670.06', + // total_turnover: '25744224.90', + // turnover_24h: '102997.83', + // total_volume: 225448878806, + // volume_24h: 809919408, + // funding_rate: '0.0001', + // predicted_funding_rate: '0.0001', + // next_funding_time: '2020-03-12T00:00:00Z', + // countdown_hour: 7 + // } + // ], + // time_now: '1583948195.818255' + // } + // + const result = this.safeValue (response, 'result', []); + const tickers = {}; + for (let i = 0; i < result.length; i++) { + const ticker = this.parseTicker (result[i]); + const symbol = ticker['symbol']; + tickers[symbol] = ticker; + } + return this.filterByArray (tickers, 'symbol', symbols); + } + + parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) { + // + // { + // symbol: 'BTCUSD', + // interval: '1', + // open_time: 1583952540, + // open: '7760.5', + // high: '7764', + // low: '7757', + // close: '7763.5', + // volume: '1259766', + // turnover: '162.32773718999994' + // }, + // + return [ + this.safeTimestamp (ohlcv, 'open_time'), + this.safeFloat (ohlcv, 'open'), + this.safeFloat (ohlcv, 'high'), + this.safeFloat (ohlcv, 'low'), + this.safeFloat (ohlcv, 'close'), + this.safeFloat (ohlcv, 'turnover'), + ]; + } + + async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + 'interval': this.timeframes[timeframe], + }; + const duration = this.parseTimeframe (timeframe); + const now = this.seconds (); + if (since === undefined) { + if (limit === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument or a limit argument'); + } else { + request['from'] = now - limit * duration; + } + } else { + request['from'] = parseInt (since / 1000); + } + if (limit !== undefined) { + request['limit'] = limit; // max 200, default 200 + } + const response = await this.publicGetKlineList (this.extend (request, params)); + // { + // ret_code: 0, + // ret_msg: 'OK', + // ext_code: '', + // ext_info: '', + // result: [ + // { + // symbol: 'BTCUSD', + // interval: '1', + // open_time: 1583952540, + // open: '7760.5', + // high: '7764', + // low: '7757', + // close: '7763.5', + // volume: '1259766', + // turnover: '162.32773718999994' + // }, + // ], + // time_now: '1583953082.397330' + // } + const result = this.safeValue (response, 'result', {}); + return this.parseOHLCVs (result, market, timeframe, since, limit); + } + + parseTrade (trade, market = undefined) { + // + // fetchTrades (public) + // + // { + // id: 43785688, + // symbol: 'BTCUSD', + // price: 7786, + // qty: 67, + // side: 'Sell', + // time: '2020-03-11T19:18:30.123Z' + // } + // + // fetchMyTrades, fetchOrderTrades (private) + // + // { + // "closed_size": 0, + // "cross_seq": 277136382, + // "exec_fee": "0.0000001", + // "exec_id": "256e5ef8-abfe-5772-971b-f944e15e0d68", + // "exec_price": "8178.5", + // "exec_qty": 1, + // "exec_time": "1571676941.70682", + // "exec_type": "Trade", //Exec Type Enum + // "exec_value": "0.00012227", + // "fee_rate": "0.00075", + // "last_liquidity_ind": "RemovedLiquidity", //Liquidity Enum + // "leaves_qty": 0, + // "nth_fill": 2, + // "order_id": "7ad50cb1-9ad0-4f74-804b-d82a516e1029", + // "order_link_id": "", + // "order_price": "8178", + // "order_qty": 1, + // "order_type": "Market", //Order Type Enum + // "side": "Buy", //Side Enum + // "symbol": "BTCUSD", //Symbol Enum + // "user_id": 1 + // } + // + const id = this.safeString2 (trade, 'id', 'exec_id'); + let symbol = undefined; + let base = undefined; + const marketId = this.safeString (trade, 'symbol'); + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + base = market['base']; + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + base = market['base']; + } + let timestamp = this.parse8601 (this.safeString (trade, 'time')); + if (timestamp === undefined) { + timestamp = this.safeTimestamp (trade, 'exec_time'); + } + const side = this.safeStringLower (trade, 'side'); + const price = this.safeFloat2 (trade, 'price', 'exec_price'); + const amount = this.safeFloat2 (trade, 'qty', 'exec_qty'); + let cost = this.safeFloat (trade, 'exec_value'); + if (cost === undefined) { + if (amount !== undefined) { + if (price !== undefined) { + cost = amount * price; + } + } + } + const lastLiquidityInd = this.safeString (trade, 'last_liquidity_ind'); + const takerOrMaker = (lastLiquidityInd === 'AddedLiquidity') ? 'maker' : 'taker'; + const feeCost = this.safeFloat (trade, 'exec_fee'); + let fee = undefined; + if (feeCost !== undefined) { + fee = { + 'cost': feeCost, + 'currency': base, + 'rate': this.safeFloat (trade, 'fee_rate'), + }; + } + return { + 'id': id, + 'info': trade, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'symbol': symbol, + 'order': this.safeString (trade, 'order_id'), + 'type': this.safeStringLower (trade, 'order_type'), + 'side': side, + 'takerOrMaker': takerOrMaker, + 'price': price, + 'amount': amount, + 'cost': cost, + 'fee': fee, + }; + } + + async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + // 'from': 123, // from id + }; + if (limit !== undefined) { + request['count'] = limit; // default 500, max 1000 + } + const response = await this.publicGetTradingRecords (this.extend (request, params)); + // + // { + // ret_code: 0, + // ret_msg: 'OK', + // ext_code: '', + // ext_info: '', + // result: [ + // { + // id: 43785688, + // symbol: 'BTCUSD', + // price: 7786, + // qty: 67, + // side: 'Sell', + // time: '2020-03-11T19:18:30.123Z' + // }, + // ], + // time_now: '1583954313.393362' + // } + // + const result = this.safeValue (response, 'result', {}); + return this.parseTrades (result, market, since, limit); + } + + parseOrderBook (orderbook, timestamp = undefined, bidsKey = 'Buy', asksKey = 'Sell', priceKey = 'price', amountKey = 'size') { + const bids = []; + const asks = []; + for (let i = 0; i < orderbook.length; i++) { + const bidask = orderbook[i]; + const side = this.safeString (bidask, 'side'); + if (side === 'Buy') { + bids.push (this.parseBidAsk (bidask, priceKey, amountKey)); + } else if (side === 'Sell') { + asks.push (this.parseBidAsk (bidask, priceKey, amountKey)); + } else { + throw new ExchangeError (this.id + ' parseOrderBook encountered an unrecognized bidask format: ' + this.json (bidask)); + } + } + return { + 'bids': this.sortBy (bids, 0, true), + 'asks': this.sortBy (asks, 0), + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'nonce': undefined, + }; + } + + async fetchOrderBook (symbol, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.publicGetOrderBookL2 (this.extend (request, params)); + // + // { + // ret_code: 0, + // ret_msg: 'OK', + // ext_code: '', + // ext_info: '', + // result: [ + // { symbol: 'BTCUSD', price: '7767.5', size: 677956, side: 'Buy' }, + // { symbol: 'BTCUSD', price: '7767', size: 580690, side: 'Buy' }, + // { symbol: 'BTCUSD', price: '7766.5', size: 475252, side: 'Buy' }, + // { symbol: 'BTCUSD', price: '7768', size: 330847, side: 'Sell' }, + // { symbol: 'BTCUSD', price: '7768.5', size: 97159, side: 'Sell' }, + // { symbol: 'BTCUSD', price: '7769', size: 6508, side: 'Sell' }, + // ], + // time_now: '1583954829.874823' + // } + // + const result = this.safeValue (response, 'result', []); + const timestamp = this.safeTimestamp (response, 'time_now'); + return this.parseOrderBook (result, timestamp, 'Buy', 'Sell', 'price', 'size'); + } + + parseOrderStatus (status) { + const statuses = { + // basic orders + 'Created': 'open', + 'Rejected': 'rejected', // order is triggered but failed upon being placed + 'New': 'open', + 'PartiallyFilled': 'open', + 'Filled': 'filled', + 'Cancelled': 'canceled', + 'PendingCancel': 'canceling', // the engine has received the cancellation but there is no guarantee that it will be successful + // conditional orders + 'Active': 'closed', // order is triggered and placed successfully + 'Untriggered': 'open', // order waits to be triggered + 'Triggered': 'closed', // order is triggered + // 'Cancelled': 'canceled', // order is cancelled + // 'Rejected': 'rejected', // order is triggered but fail to be placed + 'Deactivated': 'canceled', // conditional order was cancelled before triggering + }; + return this.safeString (statuses, status, status); + } + + parseOrder (order, market = undefined) { + // + // createOrder + // + // { + // "user_id": 1, + // "order_id": "335fd977-e5a5-4781-b6d0-c772d5bfb95b", + // "symbol": "BTCUSD", + // "side": "Buy", + // "order_type": "Limit", + // "price": 8800, + // "qty": 1, + // "time_in_force": "GoodTillCancel", + // "order_status": "Created", + // "last_exec_time": 0, + // "last_exec_price": 0, + // "leaves_qty": 1, + // "cum_exec_qty": 0, + // "cum_exec_value": 0, + // "cum_exec_fee": 0, + // "reject_reason": "", + // "order_link_id": "", + // "created_at": "2019-11-30T11:03:43.452Z", + // "updated_at": "2019-11-30T11:03:43.455Z" + // } + // + const timestamp = this.parse8601 (this.safeString (order, 'created_at')); + const id = this.safeString (order, 'order_id'); + const price = this.safeFloat (order, 'price'); + const average = this.safeFloat (order, 'average_price'); + const amount = this.safeFloat (order, 'qty'); + let filled = this.safeFloat (order, 'cum_exec_qty'); + let remaining = this.safeFloat (order, 'leaves_qty'); + let lastTradeTimestamp = this.safeTimestamp (order, 'last_exec_time'); + if (lastTradeTimestamp === 0) { + lastTradeTimestamp = undefined; + } + let cost = this.safeFloat (order, 'cum_exec_value'); + if ((filled === undefined) && (amount !== undefined) && (remaining !== undefined)) { + filled = amount - remaining; + } + if (filled !== undefined) { + if ((remaining === undefined) && (amount !== undefined)) { + remaining = amount - filled; + } + if (cost === undefined) { + if (price !== undefined) { + cost = price * filled; + } + } + } + const status = this.parseOrderStatus (this.safeString (order, 'order_status')); + const marketId = this.safeString (order, 'symbol'); + let symbol = undefined; + let base = undefined; + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + base = market['base']; + } + if (market !== undefined) { + if (symbol === undefined) { + symbol = market['symbol']; + } + if (base === undefined) { + base = market['base']; + } + } + const side = this.safeStringLower (order, 'side'); + let feeCost = this.safeFloat (order, 'cum_exec_fee'); + let fee = undefined; + if (feeCost !== undefined) { + feeCost = Math.abs (feeCost); + fee = { + 'cost': feeCost, + 'currency': base, + }; + } + const type = this.safeStringLower (order, 'order_type'); + let clientOrderId = this.safeString (order, 'order_link_id'); + if ((clientOrderId !== undefined) && (clientOrderId.length < 1)) { + clientOrderId = undefined; + } + return { + 'info': order, + 'id': id, + 'clientOrderId': clientOrderId, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': lastTradeTimestamp, + 'symbol': symbol, + 'type': type, + 'side': side, + 'price': price, + 'amount': amount, + 'cost': cost, + 'average': average, + 'filled': filled, + 'remaining': remaining, + 'status': status, + 'fee': fee, + 'trades': undefined, + }; + } + + async fetchOrder (id, symbol = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + // 'order_link_id': 'string', // one of order_id, stop_order_id or order_link_id is required + // regular orders --------------------------------------------- + // 'order_id': id, // one of order_id or order_link_id is required for regular orders + // conditional orders --------------------------------------------- + // 'stop_order_id': id, // one of stop_order_id or order_link_id is required for conditional orders + }; + let method = 'privateGetOrder'; + const stopOrderId = this.safeString (params, 'stop_order_id'); + if (stopOrderId === undefined) { + const orderLinkId = this.safeString (params, 'order_link_id'); + if (orderLinkId === undefined) { + request['order_id'] = id; + } + } else { + method = 'privateGetStopOrder'; + } + const response = await this[method] (this.extend (request, params)); + // + // { + // "ret_code": 0, + // "ret_msg": "OK", + // "ext_code": "", + // "ext_info": "", + // "result": { + // "user_id": 1, + // "symbol": "BTCUSD", + // "side": "Sell", + // "order_type": "Limit", + // "price": "8083", + // "qty": 10, + // "time_in_force": "GoodTillCancel", + // "order_status": "New", + // "ext_fields": { "o_req_num": -308787, "xreq_type": "x_create", "xreq_offset": 4154640 }, + // "leaves_qty": 10, + // "leaves_value": "0.00123716", + // "cum_exec_qty": 0, + // "reject_reason": "", + // "order_link_id": "", + // "created_at": "2019-10-21T07:28:19.396246Z", + // "updated_at": "2019-10-21T07:28:19.396246Z", + // "order_id": "efa44157-c355-4a98-b6d6-1d846a936b93" + // }, + // "time_now": "1571651135.291930", + // "rate_limit_status": 99, // The remaining number of accesses in one minute + // "rate_limit_reset_ms": 1580885703683, + // "rate_limit": 100 + // } + // + // conditional orders + // + // { + // "ret_code": 0, + // "ret_msg": "OK", + // "ext_code": "", + // "ext_info": "", + // "result": { + // "user_id": 1, + // "symbol": "BTCUSD", + // "side": "Buy", + // "order_type": "Limit", + // "price": "8000", + // "qty": 1, + // "time_in_force": "GoodTillCancel", + // "order_status": "Untriggered", + // "ext_fields": {}, + // "leaves_qty": 1, + // "leaves_value": "0.00013333", + // "cum_exec_qty": 0, + // "cum_exec_value": null, + // "cum_exec_fee": null, + // "reject_reason": "", + // "order_link_id": "", + // "created_at": "2019-12-27T19:56:24.052194Z", + // "updated_at": "2019-12-27T19:56:24.052194Z", + // "order_id": "378a1bbc-a93a-4e75-87f4-502ea754ba36" + // }, + // "time_now": "1577476584.386958", + // "rate_limit_status": 99, + // "rate_limit_reset_ms": 1580885703683, + // "rate_limit": 100 + // } + // + const result = this.safeValue (response, 'result'); + return this.parseOrder (result, market); + } + + async createOrder (symbol, type, side, amount, price = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + // orders --------------------------------------------------------- + 'side': this.capitalize (side), + 'symbol': market['id'], + 'order_type': this.capitalize (type), + 'qty': this.amountToPrecision (symbol, amount), // order quantity in USD, integer only + // 'price': this.priceToPrecision (symbol, price), // required for limit orders + 'time_in_force': 'GoodTillCancel', // ImmediateOrCancel, FillOrKill, PostOnly + // 'take_profit': 123.45, // take profit price, only take effect upon opening the position + // 'stop_loss': 123.45, // stop loss price, only take effect upon opening the position + // 'reduce_only': false, // reduce only + // when creating a closing order, bybit recommends a True value for + // close_on_trigger to avoid failing due to insufficient available margin + // 'close_on_trigger': false, + // 'order_link_id': 'string', // unique client order id, max 36 characters + // conditional orders --------------------------------------------- + // base_price is used to compare with the value of stop_px, to decide + // whether your conditional order will be triggered by crossing trigger + // price from upper side or lower side, mainly used to identify the + // expected direction of the current conditional order + // 'base_price': 123.45, // required for conditional orders + // 'stop_px': 123.45, // trigger price, required for conditional orders + // 'trigger_by': 'LastPrice', // IndexPrice, MarkPrice + }; + let priceIsRequired = false; + if (type === 'limit') { + priceIsRequired = true; + } + if (priceIsRequired) { + if (price !== undefined) { + request['price'] = this.priceToPrecision (symbol, price); + } else { + throw new ArgumentsRequired (this.id + ' createOrder requires a price argument for a ' + type + ' order'); + } + } + const stopPx = this.safeValue (params, 'stop_px'); + const basePrice = this.safeValue (params, 'base_price'); + let method = 'privatePostOrderCreate'; + if (stopPx !== undefined) { + if (basePrice === undefined) { + throw new ArgumentsRequired (this.id + ' createOrder requires both the stop_px and base_price params for a conditional ' + type + ' order'); + } else { + method = 'openapiPostStopOrderCreate'; + request['stop_px'] = this.priceToPrecision (symbol, stopPx); + request['base_price'] = this.priceToPrecision (symbol, basePrice); + params = this.omit (params, [ 'stop_px', 'base_price' ]); + } + } else if (basePrice !== undefined) { + throw new ArgumentsRequired (this.id + ' createOrder requires both the stop_px and base_price params for a conditional ' + type + ' order'); + } + const response = await this[method] (this.extend (request, params)); + // + // { + // "ret_code": 0, + // "ret_msg": "OK", + // "ext_code": "", + // "ext_info": "", + // "result": { + // "user_id": 1, + // "order_id": "335fd977-e5a5-4781-b6d0-c772d5bfb95b", + // "symbol": "BTCUSD", + // "side": "Buy", + // "order_type": "Limit", + // "price": 8800, + // "qty": 1, + // "time_in_force": "GoodTillCancel", + // "order_status": "Created", + // "last_exec_time": 0, + // "last_exec_price": 0, + // "leaves_qty": 1, + // "cum_exec_qty": 0, + // "cum_exec_value": 0, + // "cum_exec_fee": 0, + // "reject_reason": "", + // "order_link_id": "", + // "created_at": "2019-11-30T11:03:43.452Z", + // "updated_at": "2019-11-30T11:03:43.455Z" + // }, + // "time_now": "1575111823.458705", + // "rate_limit_status": 98, + // "rate_limit_reset_ms": 1580885703683, + // "rate_limit": 100 + // } + // + // conditional orders + // + // { + // "ret_code": 0, + // "ret_msg": "ok", + // "ext_code": "", + // "result": { + // "user_id": 1, + // "symbol": "BTCUSD", + // "side": "Buy", + // "order_type": "Limit", + // "price": 8000, + // "qty": 1, + // "time_in_force": "GoodTillCancel", + // "stop_order_type": "Stop", + // "trigger_by": "LastPrice", + // "base_price": 7000, + // "order_status": "Untriggered", + // "ext_fields": { + // "stop_order_type": "Stop", + // "trigger_by": "LastPrice", + // "base_price": 7000, + // "expected_direction": "Rising", + // "trigger_price": 7500, + // "op_from": "api", + // "remark": "127.0.01", + // "o_req_num": 0 + // }, + // "leaves_qty": 1, + // "leaves_value": 0.00013333, + // "reject_reason": null, + // "cross_seq": -1, + // "created_at": "2019-12-27T12:48:24.000Z", + // "updated_at": "2019-12-27T12:48:24.000Z", + // "stop_px": 7500, + // "stop_order_id": "a85cd1c0-a9a4-49d3-a1bd-bab5ebe946d5" + // }, + // "ext_info": null, + // "time_now": "1577450904.327654", + // "rate_limit_status": 99, + // "rate_limit_reset_ms": 1577450904335, + // "rate_limit": "100" + // } + // + const result = this.safeValue (response, 'result'); + return this.parseOrder (result, market); + } + + async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' editOrder requires an symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + // 'order_id': id, // only for non-conditional orders + 'symbol': market['id'], + // 'p_r_qty': this.amountToPrecision (symbol, amount), // new order quantity, optional + // 'p_r_price' this.priceToprecision (symbol, price), // new order price, optional + // ---------------------------------------------------------------- + // conditional orders + // 'stop_order_id': id, // only for conditional orders + // 'p_r_trigger_price': 123.45, // new trigger price also known as stop_px + }; + const stopOrderId = this.safeString (params, 'stop_order_id'); + let method = 'openapiPostOrderReplace'; + if (stopOrderId !== undefined) { + method = 'openapiPostStopOrderReplace'; + request['stop_order_id'] = stopOrderId; + params = this.omit (params, [ 'stop_order_id' ]); + } else { + request['order_id'] = id; + } + if (amount !== undefined) { + request['p_r_qty'] = this.amountToPrecision (symbol, amount); + } + if (price !== undefined) { + request['p_r_price'] = this.priceToPrecision (symbol, price); + } + const response = await this[method] (this.extend (request, params)); + // + // { + // "ret_code": 0, + // "ret_msg": "ok", + // "ext_code": "", + // "result": { "order_id": "efa44157-c355-4a98-b6d6-1d846a936b93" }, + // "time_now": "1539778407.210858", + // "rate_limit_status": 99, // remaining number of accesses in one minute + // "rate_limit_reset_ms": 1580885703683, + // "rate_limit": 100 + // } + // + // conditional orders + // + // { + // "ret_code": 0, + // "ret_msg": "ok", + // "ext_code": "", + // "result": { "stop_order_id": "378a1bbc-a93a-4e75-87f4-502ea754ba36" }, + // "ext_info": null, + // "time_now": "1577475760.604942", + // "rate_limit_status": 96, + // "rate_limit_reset_ms": 1577475760612, + // "rate_limit": "100" + // } + // + const result = this.safeValue (response, 'result', {}); + return { + 'info': response, + 'id': this.safeString2 (result, 'order_id', 'stop_order_id'), + 'order_id': this.safeString (result, 'order_id'), + 'stop_order_id': this.safeString (result, 'stop_order_id'), + }; + } + + async cancelOrder (id, symbol = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + // 'order_link_id': 'string', // one of order_id, stop_order_id or order_link_id is required + // regular orders --------------------------------------------- + // 'order_id': id, // one of order_id or order_link_id is required for regular orders + // conditional orders --------------------------------------------- + // 'stop_order_id': id, // one of stop_order_id or order_link_id is required for conditional orders + }; + let method = 'privatePostOrderCancel'; + const stopOrderId = this.safeString (params, 'stop_order_id'); + if (stopOrderId === undefined) { + const orderLinkId = this.safeString (params, 'order_link_id'); + if (orderLinkId === undefined) { + request['order_id'] = id; + } + } else { + method = 'openapiPostStopOrderCancel'; + } + const response = await this[method] (this.extend (request, params)); + const result = this.safeValue (response, 'result', {}); + return this.parseOrder (result, market); + } + + async cancelAllOrders (symbol = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' cancelAllOrders requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const options = this.safeValue (this.options, 'cancelAllOrders'); + const method = this.safeString (options, 'method', 'privatePostOrderCancelAll'); + const response = await this[method] (this.extend (request, params)); + const result = this.safeValue (response, 'result', []); + return this.parseOrders (result, market); + } + + async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'order_id': 'string' + // 'order_link_id': 'string', // unique client order id, max 36 characters + // 'symbol': market['id'], // default BTCUSD + // 'order': 'desc', // asc + // 'page': 1, + // 'limit': 20, // max 50 + // 'order_status': 'Created,New' + // conditional orders --------------------------------------------- + // 'stop_order_id': 'string', + // 'stop_order_status': 'Untriggered', + }; + let market = undefined; + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + } + if (limit !== undefined) { + request['limit'] = limit; + } + const options = this.safeValue (this.options, 'fetchOrders', {}); + let defaultMethod = 'openapiGetOrderList'; + let query = params; + if (('stop_order_id' in params) || ('stop_order_status' in params)) { + let stopOrderStatus = this.safeValue (params, 'stopOrderStatus'); + if (stopOrderStatus !== undefined) { + if (Array.isArray (stopOrderStatus)) { + stopOrderStatus = stopOrderStatus.join (','); + } + request['stop_order_status'] = stopOrderStatus; + query = this.omit (params, 'stop_order_status'); + } + defaultMethod = 'openapiGetStopOrderList'; + } + const method = this.safeString (options, 'method', defaultMethod); + const response = await this[method] (this.extend (request, query)); + // + // { + // "ret_code": 0, + // "ret_msg": "ok", + // "ext_code": "", + // "result": { + // "current_page": 1, + // "last_page": 6, + // "data": [ + // { + // "user_id": 1, + // "symbol": "BTCUSD", + // "side": "Sell", + // "order_type": "Market", + // "price": 7074, + // "qty": 2, + // "time_in_force": "ImmediateOrCancel", + // "order_status": "Filled", + // "ext_fields": { + // "close_on_trigger": true, + // "orig_order_type": "BLimit", + // "prior_x_req_price": 5898.5, + // "op_from": "pc", + // "remark": "127.0.0.1", + // "o_req_num": -34799032763, + // "xreq_type": "x_create" + // }, + // "last_exec_time": "1577448481.696421", + // "last_exec_price": 7070.5, + // "leaves_qty": 0, + // "leaves_value": 0, + // "cum_exec_qty": 2, + // "cum_exec_value": 0.00028283, + // "cum_exec_fee": 0.00002, + // "reject_reason": "NoError", + // "order_link_id": "", + // "created_at": "2019-12-27T12:08:01.000Z", + // "updated_at": "2019-12-27T12:08:01.000Z", + // "order_id": "f185806b-b801-40ff-adec-52289370ed62" + // } + // ] + // }, + // "ext_info": null, + // "time_now": "1577448922.437871", + // "rate_limit_status": 98, + // "rate_limit_reset_ms": 1580885703683, + // "rate_limit": 100 + // } + // + // conditional orders + // + // { + // "ret_code": 0, + // "ret_msg": "ok", + // "ext_code": "", + // "result": { + // "current_page": 1, + // "last_page": 1, + // "data": [ + // { + // "user_id": 1, + // "stop_order_status": "Untriggered", + // "symbol": "BTCUSD", + // "side": "Buy", + // "order_type": "Limit", + // "price": 8000, + // "qty": 1, + // "time_in_force": "GoodTillCancel", + // "stop_order_type": "Stop", + // "trigger_by": "LastPrice", + // "base_price": 7000, + // "order_link_id": "", + // "created_at": "2019-12-27T12:48:24.000Z", + // "updated_at": "2019-12-27T12:48:24.000Z", + // "stop_px": 7500, + // "stop_order_id": "a85cd1c0-a9a4-49d3-a1bd-bab5ebe946d5" + // }, + // ] + // }, + // "ext_info": null, + // "time_now": "1577451658.755468", + // "rate_limit_status": 599, + // "rate_limit_reset_ms": 1577451658762, + // "rate_limit": 600 + // } + // + const result = this.safeValue (response, 'result', {}); + const data = this.safeValue (result, 'data', []); + return this.parseOrders (data, market, since, limit); + } + + async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + const defaultStatuses = [ + 'Rejected', + 'Filled', + 'Cancelled', + // conditional orders + // 'Active', + // 'Triggered', + // 'Cancelled', + // 'Rejected', + // 'Deactivated', + ]; + const options = this.safeValue (this.options, 'fetchClosedOrders', {}); + let status = this.safeValue (options, 'order_status', defaultStatuses); + if (Array.isArray (status)) { + status = status.join (','); + } + const request = {}; + const stopOrderStatus = this.safeValue (params, 'stop_order_status'); + if (stopOrderStatus === undefined) { + request['order_status'] = status; + } else { + request['stop_order_status'] = stopOrderStatus; + } + return await this.fetchOrders (symbol, since, limit, this.extend (request, params)); + } + + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + const defaultStatuses = [ + 'Created', + 'New', + 'PartiallyFilled', + 'PendingCancel', + // conditional orders + // 'Untriggered', + ]; + const options = this.safeValue (this.options, 'fetchOpenOrders', {}); + let status = this.safeValue (options, 'order_status', defaultStatuses); + if (Array.isArray (status)) { + status = status.join (','); + } + const request = {}; + const stopOrderStatus = this.safeValue (params, 'stop_order_status'); + if (stopOrderStatus === undefined) { + request['order_status'] = status; + } else { + request['stop_order_status'] = stopOrderStatus; + } + return await this.fetchOrders (symbol, since, limit, this.extend (request, params)); + } + + async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { + const request = { + 'order_id': id, + }; + return await this.fetchMyTrades (symbol, since, limit, this.extend (request, params)); + } + + async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'order_id': 'f185806b-b801-40ff-adec-52289370ed62', // if not provided will return user's trading records + // 'symbol': market['id'], + // 'start_time': parseInt (since / 1000), + // 'page': 1, + // 'limit' 20, // max 50 + }; + let market = undefined; + if (symbol === undefined) { + const orderId = this.safeString (params, 'order_id'); + if (orderId === undefined) { + throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument or an order_id param'); + } else { + request['order_id'] = orderId; + params = this.omit (params, 'order_id'); + } + } else { + market = this.market (symbol); + request['symbol'] = market['id']; + } + if (since !== undefined) { + request['start_time'] = parseInt (since / 1000); + } + if (limit !== undefined) { + request['limit'] = limit; // default 20, max 50 + } + const response = await this.privateGetExecutionList (this.extend (request, params)); + // + // { + // "ret_code": 0, + // "ret_msg": "OK", + // "ext_code": "", + // "ext_info": "", + // "result": { + // "order_id": "Abandoned!!", // Abandoned!! + // "trade_list": [ + // { + // "closed_size": 0, + // "cross_seq": 277136382, + // "exec_fee": "0.0000001", + // "exec_id": "256e5ef8-abfe-5772-971b-f944e15e0d68", + // "exec_price": "8178.5", + // "exec_qty": 1, + // "exec_time": "1571676941.70682", + // "exec_type": "Trade", //Exec Type Enum + // "exec_value": "0.00012227", + // "fee_rate": "0.00075", + // "last_liquidity_ind": "RemovedLiquidity", //Liquidity Enum + // "leaves_qty": 0, + // "nth_fill": 2, + // "order_id": "7ad50cb1-9ad0-4f74-804b-d82a516e1029", + // "order_link_id": "", + // "order_price": "8178", + // "order_qty": 1, + // "order_type": "Market", //Order Type Enum + // "side": "Buy", //Side Enum + // "symbol": "BTCUSD", //Symbol Enum + // "user_id": 1 + // } + // ] + // }, + // "time_now": "1577483699.281488", + // "rate_limit_status": 118, + // "rate_limit_reset_ms": 1577483699244737, + // "rate_limit": 120 + // } + // + const result = this.safeValue (response, 'result', {}); + const trades = this.safeValue (result, 'trade_list', []); + return this.parseTrades (trades, market, since, limit); + } + + async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { + if (code === undefined) { + throw new ArgumentsRequired (this.id + ' fetchWithdrawals() requires a currency code argument'); + } + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + }; + if (limit !== undefined) { + request['count'] = limit; + } + const response = await this.privateGetGetDeposits (this.extend (request, params)); + // + // { + // "jsonrpc": "2.0", + // "id": 5611, + // "result": { + // "count": 1, + // "data": [ + // { + // "address": "2N35qDKDY22zmJq9eSyiAerMD4enJ1xx6ax", + // "amount": 5, + // "currency": "BTC", + // "received_timestamp": 1549295017670, + // "state": "completed", + // "transaction_id": "230669110fdaf0a0dbcdc079b6b8b43d5af29cc73683835b9bc6b3406c065fda", + // "updated_timestamp": 1549295130159 + // } + // ] + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const data = this.safeValue (result, 'data', []); + return this.parseTransactions (data, currency, since, limit, params); + } + + async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'coin': currency['id'], + // 'start_date': this.iso8601 (since), + // 'end_date': this.iso8601 (till), + // 'status': 'Pending', // ToBeConfirmed, UnderReview, Pending, Success, CancelByUser, Reject, Expire + // 'page': 1, + // 'limit': 20, // max 50 + }; + let currency = undefined; + if (code !== undefined) { + currency = this.currency (code); + request['coin'] = currency['id']; + } + if (since !== undefined) { + request['start_date'] = this.iso8601 (since); + } + if (limit !== undefined) { + request['limit'] = limit; + } + const response = await this.openapiGetWalletWithdrawList (this.extend (request, params)); + // + // { + // "ret_code": 0, + // "ret_msg": "ok", + // "ext_code": "", + // "result": { + // "data": [ + // { + // "id": 137, + // "user_id": 1, + // "coin": "XRP", // Coin Enum + // "status": "Pending", // Withdraw Status Enum + // "amount": "20.00000000", + // "fee": "0.25000000", + // "address": "rH7H595XYEVTEHU2FySYsWnmfACBnZS9zM", + // "tx_id": "", + // "submited_at": "2019-06-11T02:20:24.000Z", + // "updated_at": "2019-06-11T02:20:24.000Z" + // }, + // ], + // "current_page": 1, + // "last_page": 1 + // }, + // "ext_info": null, + // "time_now": "1577482295.125488", + // "rate_limit_status": 119, + // "rate_limit_reset_ms": 1577482295132, + // "rate_limit": 120 + // } + // + const result = this.safeValue (response, 'result', {}); + const data = this.safeValue (result, 'data', []); + return this.parseTransactions (data, currency, since, limit, params); + } + + parseTransactionStatus (status) { + const statuses = { + 'ToBeConfirmed': 'pending', + 'UnderReview': 'pending', + 'Pending': 'pending', + 'Success': 'ok', + 'CancelByUser': 'canceled', + 'Reject': 'rejected', + 'Expire': 'expired', + }; + return this.safeString (statuses, status, status); + } + + parseTransaction (transaction, currency = undefined) { + // + // fetchWithdrawals + // + // { + // "id": 137, + // "user_id": 1, + // "coin": "XRP", // Coin Enum + // "status": "Pending", // Withdraw Status Enum + // "amount": "20.00000000", + // "fee": "0.25000000", + // "address": "rH7H595XYEVTEHU2FySYsWnmfACBnZS9zM", + // "tx_id": "", + // "submited_at": "2019-06-11T02:20:24.000Z", + // "updated_at": "2019-06-11T02:20:24.000Z" + // } + // + const currencyId = this.safeString (transaction, 'coin'); + const code = this.safeCurrencyCode (currencyId, currency); + const timestamp = this.parse8601 (this.safeString (transaction, 'submited_at')); + const updated = this.parse8601 (this.safeString (transaction, 'updated_at')); + const status = this.parseTransactionStatus (this.safeString (transaction, 'status')); + const address = this.safeString (transaction, 'address'); + const feeCost = this.safeFloat (transaction, 'fee'); + let fee = undefined; + if (feeCost !== undefined) { + fee = { + 'cost': feeCost, + 'currency': code, + }; + } + return { + 'info': transaction, + 'id': this.safeString (transaction, 'id'), + 'txid': this.safeString (transaction, 'tx_id'), + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'address': address, + 'addressTo': undefined, + 'addressFrom': undefined, + 'tag': undefined, + 'tagTo': undefined, + 'tagFrom': undefined, + 'type': 'withdrawal', + 'amount': this.safeFloat (transaction, 'amount'), + 'currency': code, + 'status': status, + 'updated': updated, + 'fee': fee, + }; + } + + async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'coin': currency['id'], + // 'currency': currency['id'], // alias + // 'start_date': this.iso8601 (since), + // 'end_date': this.iso8601 (till), + // 'wallet_fund_type': 'Deposit', // Withdraw, RealisedPNL, Commission, Refund, Prize, ExchangeOrderWithdraw, ExchangeOrderDeposit + // 'page': 1, + // 'limit': 20, // max 50 + }; + let currency = undefined; + if (code !== undefined) { + currency = this.currency (code); + request['coin'] = currency['id']; + } + if (since !== undefined) { + request['start_date'] = this.iso8601 (since); + } + if (limit !== undefined) { + request['limit'] = limit; + } + const response = await this.openapiGetWalletFundRecords (this.extend (request, params)); + // + // { + // "ret_code": 0, + // "ret_msg": "ok", + // "ext_code": "", + // "result": { + // "data": [ + // { + // "id": 234467, + // "user_id": 1, + // "coin": "BTC", + // "wallet_id": 27913, + // "type": "Realized P&L", + // "amount": "-0.00000006", + // "tx_id": "", + // "address": "BTCUSD", + // "wallet_balance": "0.03000330", + // "exec_time": "2019-12-09T00:00:25.000Z", + // "cross_seq": 0 + // } + // ] + // }, + // "ext_info": null, + // "time_now": "1577481867.115552", + // "rate_limit_status": 119, + // "rate_limit_reset_ms": 1577481867122, + // "rate_limit": 120 + // } + // + const result = this.safeValue (response, 'result', {}); + const data = this.safeValue (result, 'data', []); + return this.parseLedger (data, currency, since, limit); + } + + parseLedgerEntry (item, currency = undefined) { + // + // { + // "id": 234467, + // "user_id": 1, + // "coin": "BTC", + // "wallet_id": 27913, + // "type": "Realized P&L", + // "amount": "-0.00000006", + // "tx_id": "", + // "address": "BTCUSD", + // "wallet_balance": "0.03000330", + // "exec_time": "2019-12-09T00:00:25.000Z", + // "cross_seq": 0 + // } + // + const currencyId = this.safeString (item, 'coin'); + const code = this.safeCurrencyCode (currencyId, currency); + const amount = this.safeFloat (item, 'amount'); + const after = this.safeFloat (item, 'wallet_balance'); + const direction = (amount < 0) ? 'out' : 'in'; + let before = undefined; + if (after !== undefined && amount !== undefined) { + const difference = (direction === 'out') ? amount : -amount; + before = this.sum (after, difference); + } + const timestamp = this.parse8601 (this.safeString (item, 'exec_time')); + const type = this.parseLedgerEntryType (this.safeString (item, 'type')); + const id = this.safeString (item, 'id'); + const referenceId = this.safeString (item, 'tx_id'); + return { + 'id': id, + 'currency': code, + 'account': this.safeString (item, 'wallet_id'), + 'referenceAccount': undefined, + 'referenceId': referenceId, + 'status': undefined, + 'amount': amount, + 'before': before, + 'after': after, + 'fee': undefined, + 'direction': direction, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'type': type, + 'info': item, + }; + } + + parseLedgerEntryType (type) { + const types = { + 'Deposit': 'transaction', + 'Withdraw': 'transaction', + 'RealisedPNL': 'trade', + 'Commission': 'fee', + 'Refund': 'cashback', + 'Prize': 'prize', // ? + 'ExchangeOrderWithdraw': 'transaction', + 'ExchangeOrderDeposit': 'transaction', + }; + return this.safeString (types, type, type); + } + + sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { + let url = this.urls['api']; + let request = path; + // public v2 + if (api === 'public') { + request = '/' + this.version + '/' + api + '/' + request; + if (Object.keys (params).length) { + request += '?' + this.rawencode (params); + } + } else { + this.checkRequiredCredentials (); + if (api === 'openapi') { + request = '/open-api/' + request; + } else if (api === 'private') { + // private v2 + request = '/' + this.version + '/' + api + '/' + request; + } else { + // position, user + request += '/' + api + '/' + request; + } + const timestamp = this.nonce (); + const query = this.extend (params, { + 'api_key': this.apiKey, + 'recvWindow': this.options['recvWindow'], + 'timestamp': timestamp, + }); + const auth = this.rawencode (this.keysort (query)); + const signature = this.hmac (this.encode (auth), this.encode (this.secret)); + if (method === 'POST') { + body = this.json (this.extend (query, { + 'sign': signature, + })); + headers = { + 'Content-Type': 'application/json', + }; + } else { + request += '?' + auth + '&sign=' + signature; + } + } + url += request; + return { 'url': url, 'method': method, 'body': body, 'headers': headers }; + } + + handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (!response) { + return; // fallback to default error handler + } + // + // { + // ret_code: 10001, + // ret_msg: 'ReadMapCB: expect { or n, but found \u0000, error ' + + // 'found in #0 byte of ...||..., bigger context ' + + // '...||...', + // ext_code: '', + // ext_info: '', + // result: null, + // time_now: '1583934106.590436' + // } + // + const errorCode = this.safeValue (response, 'ret_code'); + if (errorCode !== 0) { + const feedback = this.id + ' ' + body; + this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback); + this.throwBroadlyMatchedException (this.exceptions['broad'], body, feedback); + throw new ExchangeError (feedback); // unknown message + } + } +}; + +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],58:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -31692,10 +34983,10 @@ module.exports = class bytetrade extends Exchange { '1M': '1M', }, 'urls': { - 'test': 'https://api-v2-test.bytetrade.com', + 'test': 'https://api-v2-test.byte-trade.com', 'logo': 'https://user-images.githubusercontent.com/1294454/67288762-2f04a600-f4e6-11e9-9fd6-c60641919491.jpg', - 'api': 'https://api-v2.bytetrade.com', - 'www': 'https://www.bytetrade.com', + 'api': 'https://api-v2.byte-trade.com', + 'www': 'https://www.byte-trade.com', 'doc': 'https://github.com/Bytetrade/bytetrade-official-api-docs/wiki', }, 'api': { @@ -31737,6 +35028,7 @@ module.exports = class bytetrade extends Exchange { }, }, 'commonCurrencies': { + '44': 'ByteHub', '48': 'Blocktonic', }, 'exceptions': { @@ -31761,7 +35053,7 @@ module.exports = class bytetrade extends Exchange { code = this.safeString (currency, 'name'); } const name = this.safeString (currency, 'fullname'); - // in bytetrade.com DEX, request https://api-v2.bytetrade.com/currencies will return currencies, + // in byte-trade.com DEX, request https://api-v2.byte-trade.com/currencies will return currencies, // the api doc is https://github.com/Bytetrade/bytetrade-official-api-docs/wiki/rest-api#get-currencies-get-currencys-supported-in-bytetradecom // we can see the coin name is none-unique in the result, the coin which code is 18 is the CyberMiles ERC20, and the coin which code is 35 is the CyberMiles main chain, but their name is same. // that is because bytetrade is a DEX, supports people create coin with the same name, but the id(code) of coin is unique, so we should use the id or name and id as the identity of coin. @@ -31861,6 +35153,9 @@ module.exports = class bytetrade extends Exchange { const id = this.safeString (market, 'symbol'); let base = this.safeString (market, 'baseName'); let quote = this.safeString (market, 'quoteName'); + const normalBase = base.split ('@')[0]; + const normalQuote = quote.split ('@')[0]; + const normalSymbol = normalBase + '/' + normalQuote; const baseId = this.safeString (market, 'base'); const quoteId = this.safeString (market, 'quote'); if (baseId in this.commonCurrencies) { @@ -31875,9 +35170,6 @@ module.exports = class bytetrade extends Exchange { const price = this.safeValue (limits, 'price', {}); const precision = this.safeValue (market, 'precision', {}); const active = this.safeString (market, 'active'); - const normalBase = base.split ('@')[0]; - const normalQuote = quote.split ('@')[0]; - const normalSymbol = normalBase + '/' + normalQuote; const entry = { 'id': id, 'symbol': symbol, @@ -32185,6 +35477,7 @@ module.exports = class bytetrade extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': datetime, 'lastTradeTimestamp': lastTradeTimestamp, @@ -32199,6 +35492,7 @@ module.exports = class bytetrade extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; } @@ -32220,23 +35514,25 @@ module.exports = class bytetrade extends Exchange { typeNum = 1; } else { typeNum = 2; + price = 0; } const normalSymbol = market['normalSymbol']; const baseId = market['baseId']; const baseCurrency = this.currency (market['base']); const amountTruncated = this.amountToPrecision (symbol, amount); - const amountChain = this.toWei (amountTruncated, 'ether', baseCurrency['precision']['amount']); + const amountChain = this.toWei (amountTruncated, baseCurrency['precision']['amount']); const quoteId = market['quoteId']; const quoteCurrency = this.currency (market['quote']); const priceRounded = this.priceToPrecision (symbol, price); - const priceChain = this.toWei (priceRounded, 'ether', quoteCurrency['precision']['amount']); + const priceChain = this.toWei (priceRounded, quoteCurrency['precision']['amount']); const now = this.milliseconds (); const expiration = this.milliseconds (); let datetime = this.iso8601 (now); datetime = datetime.split ('.')[0]; let expirationDatetime = this.iso8601 (expiration); expirationDatetime = expirationDatetime.split ('.')[0]; - const chainName = 'Sagittarius'; + const defaultDappId = 'Sagittarius'; + const dappId = this.safeString (params, 'dappId', defaultDappId); const defaultFee = this.safeString (this.options, 'fee', '300000000000000'); const fee = this.safeString (params, 'fee', defaultFee); const eightBytes = this.integerPow ('2', '64'); @@ -32267,8 +35563,8 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (parseInt (baseId), 4), this.numberToLE (0, 1), this.numberToLE (1, 1), - this.numberToLE (chainName.length, 1), - this.stringToBinary (this.encode (chainName)), + this.numberToLE (dappId.length, 1), + this.stringToBinary (this.encode (dappId)), this.numberToLE (0, 1), ]; const txByteStringArray = [ @@ -32297,8 +35593,8 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (parseInt (baseId), 4), this.numberToLE (0, 1), this.numberToLE (1, 1), - this.numberToLE (chainName.length, 1), - this.stringToBinary (this.encode (chainName)), + this.numberToLE (dappId.length, 1), + this.stringToBinary (this.encode (dappId)), this.numberToLE (0, 1), ]; const txbytestring = this.binaryConcatArray (txByteStringArray); @@ -32341,7 +35637,7 @@ module.exports = class bytetrade extends Exchange { ], ], 'validate_type': 0, - 'dapp': 'Sagittarius', + 'dapp': dappId, 'signatures': [ mySignature, ], @@ -32370,6 +35666,8 @@ module.exports = class bytetrade extends Exchange { 'cost': undefined, 'trades': undefined, 'fee': undefined, + 'clientOrderId': undefined, + 'average': undefined, }; } @@ -32470,7 +35768,8 @@ module.exports = class bytetrade extends Exchange { datetime = datetime.split ('.')[0]; let expirationDatetime = this.iso8601 (expiration); expirationDatetime = expirationDatetime.split ('.')[0]; - const chainName = 'Sagittarius'; + const defaultDappId = 'Sagittarius'; + const dappId = this.safeString (params, 'dappId', defaultDappId); const byteStringArray = [ this.numberToBE (1, 32), this.numberToLE (Math.floor (now / 1000), 4), @@ -32489,8 +35788,8 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (parseInt (baseId), 4), this.numberToLE (0, 1), this.numberToLE (1, 1), - this.numberToLE (chainName.length, 1), - this.stringToBinary (this.encode (chainName)), + this.numberToLE (dappId.length, 1), + this.stringToBinary (this.encode (dappId)), this.numberToLE (0, 1), ]; const bytestring = this.binaryConcatArray (byteStringArray); @@ -32516,7 +35815,7 @@ module.exports = class bytetrade extends Exchange { ], ], 'validate_type': 0, - 'dapp': 'Sagittarius', + 'dapp': dappId, 'signatures': [ mySignature, ], @@ -32545,10 +35844,12 @@ module.exports = class bytetrade extends Exchange { 'cost': undefined, 'trades': undefined, 'fee': undefined, + 'clientOrderId': undefined, + 'average': undefined, }; } - async transfer (code, amount, address, params = {}) { + async transfer (code, amount, address, message = '', params = {}) { this.checkRequiredDependencies (); if (this.apiKey === undefined) { throw new ArgumentsRequired ('transfer requires this.apiKey'); @@ -32556,7 +35857,7 @@ module.exports = class bytetrade extends Exchange { await this.loadMarkets (); const currency = this.currency (code); const amountTruncate = this.decimalToPrecision (amount, TRUNCATE, currency['info']['transferPrecision'], DECIMAL_PLACES, NO_PADDING); - const amountChain = this.toWei (amountTruncate, 'ether', currency['precision']['amount']); + const amountChain = this.toWei (amountTruncate, currency['precision']['amount']); const assetType = parseInt (currency['id']); const now = this.milliseconds (); const expiration = now; @@ -32565,7 +35866,8 @@ module.exports = class bytetrade extends Exchange { let expirationDatetime = this.iso8601 (expiration); expirationDatetime = expirationDatetime.split ('.')[0]; const feeAmount = '300000000000000'; - const chainName = 'Sagittarius'; + const defaultDappId = 'Sagittarius'; + const dappId = this.safeString (params, 'dappId', defaultDappId); const eightBytes = this.integerPow ('2', '64'); const byteStringArray = [ this.numberToBE (1, 32), @@ -32573,7 +35875,7 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (1, 1), this.numberToLE (Math.floor (expiration / 1000), 4), this.numberToLE (1, 1), - this.numberToLE (0, 1), + this.numberToLE (28, 1), this.numberToLE (0, 8), this.numberToLE (feeAmount, 8), // string for 32 bit php this.numberToLE (this.apiKey.length, 1), @@ -32583,10 +35885,13 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (assetType, 4), this.numberToLE (this.integerDivide (amountChain, eightBytes), 8), this.numberToLE (this.integerModulo (amountChain, eightBytes), 8), + this.numberToLE (1, 1), + this.numberToLE (message.length, 1), + this.stringToBinary (this.encode (message)), this.numberToLE (0, 1), this.numberToLE (1, 1), - this.numberToLE (chainName.length, 1), - this.stringToBinary (this.encode (chainName)), + this.numberToLE (dappId.length, 1), + this.stringToBinary (this.encode (dappId)), this.numberToLE (0, 1), ]; const bytestring = this.binaryConcatArray (byteStringArray); @@ -32600,18 +35905,19 @@ module.exports = class bytetrade extends Exchange { 'to': address, 'asset_type': parseInt (currency['id']), 'amount': amountChain.toString (), + 'message': message, }; const fatty = { 'timestamp': datetime, 'expiration': expirationDatetime, 'operations': [ [ - 0, + 28, operation, ], ], 'validate_type': 0, - 'dapp': 'Sagittarius', + 'dapp': dappId, 'signatures': [ mySignature, ], @@ -32644,6 +35950,9 @@ module.exports = class bytetrade extends Exchange { 'remaining': undefined, 'cost': undefined, 'fee': undefined, + 'clientOrderId': undefined, + 'average': undefined, + 'trades': undefined, }; } @@ -32823,12 +36132,13 @@ module.exports = class bytetrade extends Exchange { datetime = datetime.split ('.')[0]; let expirationDatetime = this.iso8601 (expiration); expirationDatetime = expirationDatetime.split ('.')[0]; - const chainName = 'Sagittarius'; + const defaultDappId = 'Sagittarius'; + const dappId = this.safeString (params, 'dappId', defaultDappId); const feeAmount = '300000000000000'; const currency = this.currency (code); const coinId = currency['id']; const amountTruncate = this.decimalToPrecision (amount, TRUNCATE, currency['info']['transferPrecision'], DECIMAL_PLACES, NO_PADDING); - const amountChain = this.toWei (amountTruncate, 'ether', currency['info']['externalPrecision']); + const amountChain = this.toWei (amountTruncate, currency['info']['externalPrecision']); const eightBytes = this.integerPow ('2', '64'); let assetFee = 0; let byteStringArray = []; @@ -32855,8 +36165,8 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (this.integerModulo (assetFee, eightBytes), 8), this.numberToLE (0, 1), this.numberToLE (1, 1), - this.numberToLE (chainName.length, 1), - this.stringToBinary (this.encode (chainName)), + this.numberToLE (dappId.length, 1), + this.stringToBinary (this.encode (dappId)), this.numberToLE (0, 1), ]; } else { @@ -32885,8 +36195,8 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (this.integerModulo (amountChain, eightBytes), 8), this.numberToLE (0, 1), this.numberToLE (1, 1), - this.numberToLE (chainName.length, 1), - this.stringToBinary (this.encode (chainName)), + this.numberToLE (dappId.length, 1), + this.stringToBinary (this.encode (dappId)), this.numberToLE (0, 1), ]; } @@ -32918,7 +36228,7 @@ module.exports = class bytetrade extends Exchange { ], ], 'validate_type': 0, - 'dapp': 'Sagittarius', + 'dapp': dappId, 'signatures': [ mySignature, ], @@ -32926,7 +36236,7 @@ module.exports = class bytetrade extends Exchange { request = { 'chainType': chainId, 'trObj': this.json (fatty), - 'chainContractAddresss': chainContractAddress, + 'chainContractAddress': chainContractAddress, }; } else { operation = { @@ -32955,7 +36265,7 @@ module.exports = class bytetrade extends Exchange { ], ], 'validate_type': 0, - 'dapp': 'Sagittarius', + 'dapp': dappId, 'signatures': [ mySignature, ], @@ -32965,14 +36275,14 @@ module.exports = class bytetrade extends Exchange { 'chainType': chainId, 'toExternalAddress': 'noneed', 'trObj': this.json (fatty), - 'chainContractAddresss': chainContractAddress, + 'chainContractAddress': chainContractAddress, }; } else { request = { 'chainType': chainId, 'toExternalAddress': address, 'trObj': this.json (fatty), - 'chainContractAddresss': chainContractAddress, + 'chainContractAddress': chainContractAddress, }; } } @@ -33011,13 +36321,13 @@ module.exports = class bytetrade extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],59:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],59:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, ArgumentsRequired, NullResponse, InvalidOrder, NotSupported, InsufficientFunds, InvalidNonce, OrderNotFound, RateLimitExceeded } = require ('./base/errors'); +const { ExchangeError, ArgumentsRequired, AuthenticationError, NullResponse, InvalidOrder, NotSupported, InsufficientFunds, InvalidNonce, OrderNotFound, RateLimitExceeded } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -33029,7 +36339,7 @@ module.exports = class cex extends Exchange { 'countries': [ 'GB', 'EU', 'CY', 'RU' ], 'rateLimit': 1500, 'has': { - 'CORS': true, + 'CORS': false, 'fetchCurrencies': true, 'fetchTickers': true, 'fetchOHLCV': true, @@ -33140,6 +36450,8 @@ module.exports = class cex extends Exchange { 'Invalid Order': InvalidOrder, 'Order not found': OrderNotFound, 'Rate limit exceeded': RateLimitExceeded, + 'Invalid API key': AuthenticationError, + 'There was an error while placing your order': InvalidOrder, }, }, 'options': { @@ -33366,6 +36678,7 @@ module.exports = class cex extends Exchange { 'max': undefined, }, }, + 'active': undefined, }); } return result; @@ -33817,11 +37130,14 @@ module.exports = class cex extends Exchange { 'currency': market['quote'], }, 'info': item, + 'type': undefined, + 'takerOrMaker': undefined, }); } } return { 'id': orderId, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -33837,6 +37153,7 @@ module.exports = class cex extends Exchange { 'trades': trades, 'fee': fee, 'info': order, + 'average': undefined, }; } @@ -34166,12 +37483,12 @@ module.exports = class cex extends Exchange { if (Array.isArray (response)) { return response; // public endpoints may return []-arrays } + if (body === 'true') { + return; + } if (response === undefined) { throw new NullResponse (this.id + ' returned ' + this.json (response)); } - if (response === true || response === 'true') { - return; - } if ('e' in response) { if ('ok' in response) { if (response['ok'] === 'ok') { @@ -34189,7 +37506,7 @@ module.exports = class cex extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],60:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],60:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -34223,870 +37540,7 @@ module.exports = class chilebit extends foxbit { } }; -},{"./foxbit.js":86}],61:[function(require,module,exports){ -'use strict'; - -// --------------------------------------------------------------------------- - -const Exchange = require ('./base/Exchange'); -const { ExchangeError, InvalidAddress, InsufficientFunds, InvalidNonce, InvalidOrder, OrderNotFound, PermissionDenied } = require ('./base/errors'); - -// --------------------------------------------------------------------------- - -module.exports = class cobinhood extends Exchange { - describe () { - return this.deepExtend (super.describe (), { - 'id': 'cobinhood', - 'name': 'COBINHOOD', - 'countries': [ 'TW' ], - 'rateLimit': 1000 / 10, - 'version': 'v1', - 'has': { - 'fetchCurrencies': true, - 'fetchTickers': true, - 'fetchOHLCV': true, - 'fetchOpenOrders': true, - 'fetchClosedOrders': true, - 'fetchOrderTrades': true, - 'fetchOrder': true, - 'fetchDepositAddress': true, - 'createDepositAddress': true, - 'fetchDeposits': true, - 'fetchWithdrawals': true, - 'withdraw': true, - 'fetchMyTrades': true, - 'editOrder': true, - }, - 'requiredCredentials': { - 'apiKey': true, - 'secret': false, - }, - 'timeframes': { - // the first two don't seem to work at all - '1m': '1m', - '5m': '5m', - '15m': '15m', - '30m': '30m', - '1h': '1h', - '3h': '3h', - '6h': '6h', - '12h': '12h', - '1d': '1D', - '1w': '7D', - '2w': '14D', - '1M': '1M', - }, - 'urls': { - 'referral': 'https://cobinhood.com?referrerId=a9d57842-99bb-4d7c-b668-0479a15a458b', - 'logo': 'https://user-images.githubusercontent.com/1294454/35755576-dee02e5c-0878-11e8-989f-1595d80ba47f.jpg', - 'api': 'https://api.cobinhood.com', - 'www': 'https://cobinhood.com', - 'doc': 'https://cobinhood.github.io/api-public', - }, - 'api': { - 'system': { - 'get': [ - 'info', - 'time', - 'messages', - 'messages/{message_id}', - ], - }, - 'admin': { - 'get': [ - 'system/messages', - 'system/messages/{message_id}', - ], - 'post': [ - 'system/messages', - ], - 'patch': [ - 'system/messages/{message_id}', - ], - 'delete': [ - 'system/messages/{message_id}', - ], - }, - 'public': { - 'get': [ - 'market/fundingbook/precisions/{currency_id}', - 'market/fundingbooks/{currency_id}', - 'market/tickers', - 'market/currencies', - 'market/quote_currencies', - 'market/trading_pairs', - 'market/orderbook/precisions/{trading_pair_id}', - 'market/orderbooks/{trading_pair_id}', - 'market/stats', - 'market/tickers', // fetchTickers - 'market/tickers/{trading_pair_id}', - 'market/trades/{trading_pair_id}', - 'market/trades_history/{trading_pair_id}', - 'market/trading_pairs', - 'chart/candles/{trading_pair_id}', - 'system/time', - ], - }, - 'private': { - 'get': [ - 'funding/auto_offerings', - 'funding/auto_offerings/{currency_id}', - 'funding/funding_history', - 'funding/fundings', - 'funding/loans', - 'funding/loans/{loan_id}', - 'trading/orders/{order_id}', - 'trading/orders/{order_id}/trades', - 'trading/orders', - 'trading/order_history', - 'trading/positions', - 'trading/positions/{trading_pair_id}', - 'trading/positions/{trading_pair_id}/claimable_size', - 'trading/trades', - 'trading/trades/{trade_id}', - 'trading/volume', - 'wallet/balances', - 'wallet/ledger', - 'wallet/limits/withdrawal', - 'wallet/generic_deposits', - 'wallet/generic_deposits/{generic_deposit_id}', - 'wallet/generic_withdrawals', - 'wallet/generic_withdrawals/{generic_withdrawal_id}', - // older endpoints - 'wallet/deposit_addresses', - 'wallet/deposit_addresses/iota', - 'wallet/withdrawal_addresses', - 'wallet/withdrawal_frozen', - 'wallet/withdrawals/{withdrawal_id}', - 'wallet/withdrawals', - 'wallet/deposits/{deposit_id}', - 'wallet/deposits', - ], - 'patch': [ - 'trading/positions/{trading_pair_id}', - ], - 'post': [ - 'funding/auto_offerings', - 'funding/fundings', - 'trading/check_order', - 'trading/orders', - // older endpoints - 'wallet/deposit_addresses', - 'wallet/transfer', - 'wallet/withdrawal_addresses', - 'wallet/withdrawals', - 'wallet/withdrawals/fee', - ], - 'put': [ - 'funding/fundings/{funding_id}', - 'trading/orders/{order_id}', - ], - 'delete': [ - 'funding/auto_offerings/{currency_id}', - 'funding/fundings/{funding_id}', - 'funding/loans/{loan_id}', - 'trading/orders/{order_id}', - 'trading/positions/{trading_pair_id}', - 'wallet/generic_withdrawals/{generic_withdrawal_id}', - 'wallet/withdrawal_addresses/{wallet_id}', - ], - }, - }, - 'fees': { - 'trading': { - 'maker': 0.0, - 'taker': 0.0, - }, - }, - 'precision': { - 'amount': 8, - 'price': 8, - }, - 'exceptions': { - 'insufficient_balance': InsufficientFunds, - 'invalid_order_size': InvalidOrder, - 'invalid_nonce': InvalidNonce, - 'unauthorized_scope': PermissionDenied, - 'invalid_address': InvalidAddress, - 'parameter_error': OrderNotFound, - }, - 'commonCurrencies': { - 'SMT': 'SocialMedia.Market', - 'MTN': 'Motion Token', - }, - }); - } - - async fetchCurrencies (params = {}) { - const response = await this.publicGetMarketCurrencies (params); - const currencies = response['result']['currencies']; - const result = {}; - for (let i = 0; i < currencies.length; i++) { - const currency = currencies[i]; - const id = this.safeString (currency, 'currency'); - const name = this.safeString (currency, 'name'); - const code = this.safeCurrencyCode (id); - const minUnit = this.safeFloat (currency, 'min_unit'); - result[code] = { - 'id': id, - 'code': code, - 'name': name, - 'active': true, - 'fiat': false, - 'precision': this.precisionFromString (currency['min_unit']), - 'limits': { - 'amount': { - 'min': minUnit, - 'max': undefined, - }, - 'price': { - 'min': minUnit, - 'max': undefined, - }, - 'deposit': { - 'min': minUnit, - 'max': undefined, - }, - 'withdraw': { - 'min': minUnit, - 'max': undefined, - }, - }, - 'funding': { - 'withdraw': { - 'fee': this.safeFloat (currency, 'withdrawal_fee'), - }, - 'deposit': { - 'fee': this.safeFloat (currency, 'deposit_fee'), - }, - }, - 'info': currency, - }; - } - return result; - } - - async fetchMarkets (params = {}) { - const response = await this.publicGetMarketTradingPairs (params); - const markets = this.safeValue (response['result'], 'trading_pairs'); - const result = []; - for (let i = 0; i < markets.length; i++) { - const market = markets[i]; - const id = this.safeString (market, 'id'); - const [ baseId, quoteId ] = id.split ('-'); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - const symbol = base + '/' + quote; - const precision = { - 'amount': 8, - 'price': this.precisionFromString (market['quote_increment']), - }; - const active = this.safeValue (market, 'is_active', true); - result.push ({ - 'id': id, - 'symbol': symbol, - 'base': base, - 'quote': quote, - 'baseId': baseId, - 'quoteId': quoteId, - 'active': active, - 'precision': precision, - 'limits': { - 'amount': { - 'min': this.safeFloat (market, 'base_min_size'), - 'max': this.safeFloat (market, 'base_max_size'), - }, - 'price': { - 'min': undefined, - 'max': undefined, - }, - 'cost': { - 'min': undefined, - 'max': undefined, - }, - }, - 'info': market, - }); - } - return result; - } - - parseTicker (ticker, market = undefined) { - let symbol = undefined; - if (market === undefined) { - const marketId = this.safeString (ticker, 'trading_pair_id'); - if (marketId in this.markets_by_id) { - market = this.markets_by_id[marketId]; - } else { - const [ baseId, quoteId ] = marketId.split ('-'); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - symbol = base + '/' + quote; - } - } - if (market !== undefined) { - symbol = market['symbol']; - } - const timestamp = this.safeInteger (ticker, 'timestamp'); - const last = this.safeFloat (ticker, 'last_trade_price'); - return { - 'symbol': symbol, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'high': this.safeFloat (ticker, '24h_high'), - 'low': this.safeFloat (ticker, '24h_low'), - 'bid': this.safeFloat (ticker, 'highest_bid'), - 'bidVolume': undefined, - 'ask': this.safeFloat (ticker, 'lowest_ask'), - 'askVolume': undefined, - 'vwap': undefined, - 'open': undefined, - 'close': last, - 'last': last, - 'previousClose': undefined, - 'change': this.safeFloat (ticker, 'percentChanged24hr'), - 'percentage': undefined, - 'average': undefined, - 'baseVolume': this.safeFloat (ticker, '24h_volume'), - 'quoteVolume': this.safeFloat (ticker, 'quote_volume'), - 'info': ticker, - }; - } - - async fetchTicker (symbol, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'trading_pair_id': market['id'], - }; - const response = await this.publicGetMarketTickersTradingPairId (this.extend (request, params)); - const ticker = this.safeValue (response['result'], 'ticker'); - return this.parseTicker (ticker, market); - } - - async fetchTickers (symbols = undefined, params = {}) { - await this.loadMarkets (); - const response = await this.publicGetMarketTickers (params); - const tickers = this.safeValue (response['result'], 'tickers'); - const result = []; - for (let i = 0; i < tickers.length; i++) { - result.push (this.parseTicker (tickers[i])); - } - return this.indexBy (result, 'symbol'); - } - - async fetchOrderBook (symbol, limit = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'trading_pair_id': this.marketId (symbol), - }; - if (limit !== undefined) { - request['limit'] = limit; // 100 - } - const response = await this.publicGetMarketOrderbooksTradingPairId (this.extend (request, params)); - return this.parseOrderBook (response['result']['orderbook'], undefined, 'bids', 'asks', 0, 2); - } - - parseTrade (trade, market = undefined) { - let symbol = undefined; - if (market) { - symbol = market['symbol']; - } - const timestamp = this.safeInteger (trade, 'timestamp'); - const price = this.safeFloat (trade, 'price'); - const amount = this.safeFloat (trade, 'size'); - let cost = undefined; - if (price !== undefined) { - if (amount !== undefined) { - cost = price * amount; - } - } - // you can't determine your side from maker/taker side and vice versa - // you can't determine if your order/trade was a maker or a taker based - // on just the side of your order/trade - // https://github.com/ccxt/ccxt/issues/4300 - // let side = (trade['maker_side'] === 'bid') ? 'sell' : 'buy'; - const side = undefined; - const id = this.safeString (trade, 'id'); - return { - 'info': trade, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': symbol, - 'id': id, - 'order': undefined, - 'type': undefined, - 'side': side, - 'takerOrMaker': undefined, - 'price': price, - 'amount': amount, - 'cost': cost, - 'fee': undefined, - }; - } - - async fetchTrades (symbol, since = undefined, limit = 50, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'trading_pair_id': market['id'], - 'limit': limit, // default 20, but that seems too little - }; - const response = await this.publicGetMarketTradesTradingPairId (this.extend (request, params)); - const trades = this.safeValue (response['result'], 'trades'); - return this.parseTrades (trades, market, since, limit); - } - - parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) { - return [ - // they say that timestamps are Unix Timestamps in seconds, but in fact those are milliseconds - ohlcv['timestamp'], - parseFloat (ohlcv['open']), - parseFloat (ohlcv['high']), - parseFloat (ohlcv['low']), - parseFloat (ohlcv['close']), - parseFloat (ohlcv['volume']), - ]; - } - - async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - // - // they say in their docs that end_time defaults to current server time - // but if you don't specify it, their range limits does not allow you to query anything - // - // they also say that start_time defaults to 0, - // but most calls fail if you do not specify any of end_time - // - // to make things worse, their docs say it should be a Unix Timestamp - // but with seconds it fails, so we set milliseconds (somehow it works that way) - // - const endTime = this.milliseconds (); - const request = { - 'trading_pair_id': market['id'], - 'timeframe': this.timeframes[timeframe], - 'end_time': endTime, - }; - if (since !== undefined) { - request['start_time'] = since; - } - const response = await this.publicGetChartCandlesTradingPairId (this.extend (request, params)); - const ohlcv = this.safeValue (response['result'], 'candles'); - return this.parseOHLCVs (ohlcv, market, timeframe, since, limit); - } - - async fetchBalance (params = {}) { - await this.loadMarkets (); - const response = await this.privateGetWalletBalances (params); - const result = { 'info': response }; - const balances = this.safeValue (response['result'], 'balances'); - for (let i = 0; i < balances.length; i++) { - const balance = balances[i]; - const currencyId = this.safeString (balance, 'currency'); - const code = this.safeCurrencyCode (currencyId); - const account = this.account (); - account['used'] = this.safeFloat (balance, 'on_order'); - account['total'] = this.safeFloat (balance, 'total'); - result[code] = account; - } - return this.parseBalance (result); - } - - parseOrderStatus (status) { - const statuses = { - 'filled': 'closed', - 'rejected': 'closed', - 'partially_filled': 'open', - 'pending_cancellation': 'open', - 'pending_modification': 'open', - 'open': 'open', - 'new': 'open', - 'queued': 'open', - 'cancelled': 'canceled', - 'triggered': 'triggered', - }; - return this.safeString (statuses, status, status); - } - - parseOrder (order, market = undefined) { - // - // { - // 'completed_at': None, - // 'eq_price': '0', - // 'filled': '0', - // 'id': '88426800-beae-4407-b4a1-f65cef693542', - // 'price': '0.00000507', - // 'side': 'bid', - // 'size': '3503.6489', - // 'source': 'exchange', - // 'state': 'open', - // 'timestamp': 1535258403597, - // 'trading_pair_id': 'ACT-BTC', - // 'type': 'limit', - // } - // - let symbol = undefined; - if (market === undefined) { - const marketId = this.safeString2 (order, 'trading_pair', 'trading_pair_id'); - market = this.safeValue (this.markets_by_id, marketId); - } - if (market !== undefined) { - symbol = market['symbol']; - } - const timestamp = this.safeInteger (order, 'timestamp'); - const price = this.safeFloat (order, 'price'); - const average = this.safeFloat (order, 'eq_price'); - const amount = this.safeFloat (order, 'size'); - const filled = this.safeFloat (order, 'filled'); - let remaining = undefined; - let cost = undefined; - if (filled !== undefined && average !== undefined) { - cost = average * filled; - } else if (average !== undefined) { - cost = average * amount; - } - if (amount !== undefined) { - if (filled !== undefined) { - remaining = amount - filled; - } - } - const status = this.parseOrderStatus (this.safeString (order, 'state')); - let side = this.safeString (order, 'side'); - if (side === 'bid') { - side = 'buy'; - } else if (side === 'ask') { - side = 'sell'; - } - return { - 'id': this.safeString (order, 'id'), - 'datetime': this.iso8601 (timestamp), - 'timestamp': timestamp, - 'lastTradeTimestamp': undefined, - 'status': status, - 'symbol': symbol, - 'type': this.safeString (order, 'type'), // market, limit, stop, stop_limit, trailing_stop, fill_or_kill - 'side': side, - 'price': price, - 'cost': cost, - 'average': average, - 'amount': amount, - 'filled': filled, - 'remaining': remaining, - 'trades': undefined, - 'fee': undefined, - 'info': order, - }; - } - - async createOrder (symbol, type, side, amount, price = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - side = (side === 'sell') ? 'ask' : 'bid'; - const request = { - 'trading_pair_id': market['id'], - 'type': type, // market, limit, stop, stop_limit - 'side': side, - 'size': this.amountToPrecision (symbol, amount), - }; - if (type !== 'market') { - request['price'] = this.priceToPrecision (symbol, price); - } - const response = await this.privatePostTradingOrders (this.extend (request, params)); - const order = this.parseOrder (response['result']['order'], market); - const id = order['id']; - this.orders[id] = order; - return order; - } - - async editOrder (id, symbol, type, side, amount, price, params = {}) { - await this.loadMarkets (); - const request = { - 'order_id': id, - 'price': this.priceToPrecision (symbol, price), - 'size': this.amountToPrecision (symbol, amount), - }; - const response = await this.privatePutTradingOrdersOrderId (this.extend (request, params)); - return this.parseOrder (this.extend (response, { - 'id': id, - })); - } - - async cancelOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'order_id': id, - }; - const response = await this.privateDeleteTradingOrdersOrderId (this.extend (request, params)); - return this.parseOrder (this.extend (response, { - 'id': id, - })); - } - - async fetchOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'order_id': id.toString (), - }; - const response = await this.privateGetTradingOrdersOrderId (this.extend (request, params)); - return this.parseOrder (response['result']['order']); - } - - async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const result = await this.privateGetTradingOrders (params); - const orders = this.parseOrders (result['result']['orders'], undefined, since, limit); - if (symbol !== undefined) { - return this.filterBySymbolSinceLimit (orders, symbol, since, limit); - } - return this.filterBySinceLimit (orders, since, limit); - } - - async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const request = {}; - let market = undefined; - if (symbol !== undefined) { - market = this.market (symbol); - request['trading_pair_id'] = market['id']; - } - if (limit !== undefined) { - request['limit'] = limit; // default 50, max 100 - } - const response = await this.privateGetTradingOrderHistory (this.extend (request, params)); - const orders = this.parseOrders (response['result']['orders'], market, since, limit); - if (symbol !== undefined) { - return this.filterBySymbolSinceLimit (orders, symbol, since, limit); - } - return this.filterBySinceLimit (orders, since, limit); - } - - async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'order_id': id, - }; - const response = await this.privateGetTradingOrdersOrderIdTrades (this.extend (request, params)); - const market = (symbol === undefined) ? undefined : this.market (symbol); - return this.parseTrades (response['result']['trades'], market); - } - - async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const request = {}; - if (symbol !== undefined) { - request['trading_pair_id'] = market['id']; - } - const response = await this.privateGetTradingTrades (this.extend (request, params)); - return this.parseTrades (response['result']['trades'], market, since, limit); - } - - async createDepositAddress (code, params = {}) { - await this.loadMarkets (); - const currency = this.currency (code); - // 'ledger_type' is required, see: https://cobinhood.github.io/api-public/#create-new-deposit-address - const ledgerType = this.safeString (params, 'ledger_type', 'exchange'); - const request = { - 'currency': currency['id'], - 'ledger_type': ledgerType, - }; - const response = await this.privatePostWalletDepositAddresses (this.extend (request, params)); - const address = this.safeString (response['result']['deposit_address'], 'address'); - const tag = this.safeString (response['result']['deposit_address'], 'memo'); - this.checkAddress (address); - return { - 'currency': code, - 'address': address, - 'tag': tag, - 'info': response, - }; - } - - async fetchDepositAddress (code, params = {}) { - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'currency': currency['id'], - }; - const response = await this.privateGetWalletDepositAddresses (this.extend (request, params)); - // - // { success: true, - // result: { deposit_addresses: [ { address: "abcdefg", - // blockchain_id: "eosio", - // created_at: 1536768050235, - // currency: "EOS", - // memo: "12345678", - // type: "exchange" } ] } } - // - const addresses = this.safeValue (response['result'], 'deposit_addresses', []); - let address = undefined; - let tag = undefined; - if (addresses.length > 0) { - address = this.safeString (addresses[0], 'address'); - tag = this.safeString2 (addresses[0], 'memo', 'tag'); - } - this.checkAddress (address); - return { - 'currency': code, - 'address': address, - 'tag': tag, - 'info': response, - }; - } - - async withdraw (code, amount, address, tag = undefined, params = {}) { - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'currency': currency['id'], - 'amount': amount, - 'address': address, - }; - if (tag !== undefined) { - request['memo'] = tag; - } - const response = await this.privatePostWalletWithdrawals (this.extend (request, params)); - return { - 'id': undefined, - 'info': response, - }; - } - - async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - if (code === undefined) { - throw new ExchangeError (this.id + ' fetchDeposits() requires a currency code argument'); - } - const currency = this.currency (code); - const request = { - 'currency': currency['id'], - }; - const response = await this.privateGetWalletDeposits (this.extend (request, params)); - return this.parseTransactions (response['result']['deposits'], currency); - } - - async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - if (code === undefined) { - throw new ExchangeError (this.id + ' fetchWithdrawals() requires a currency code argument'); - } - const currency = this.currency (code); - const request = { - 'currency': currency['id'], - }; - const response = await this.privateGetWalletWithdrawals (this.extend (request, params)); - return this.parseTransactions (response['result']['withdrawals'], currency); - } - - parseTransactionStatus (status) { - const statuses = { - 'tx_pending_two_factor_auth': 'pending', - 'tx_pending_email_auth': 'pending', - 'tx_pending_approval': 'pending', - 'tx_approved': 'pending', - 'tx_processing': 'pending', - 'tx_pending': 'pending', - 'tx_sent': 'pending', - 'tx_cancelled': 'canceled', - 'tx_timeout': 'failed', - 'tx_invalid': 'failed', - 'tx_rejected': 'failed', - 'tx_confirmed': 'ok', - }; - return this.safeString (statuses, status, status); - } - - parseTransaction (transaction, currency = undefined) { - const timestamp = this.safeInteger (transaction, 'created_at'); - const currencyId = this.safeString (transaction, 'currency'); - const code = this.safeCurrencyCode (currencyId, currency); - let id = undefined; - const withdrawalId = this.safeString (transaction, 'withdrawal_id'); - const depositId = this.safeString (transaction, 'deposit_id'); - let type = undefined; - let address = undefined; - if (withdrawalId !== undefined) { - type = 'withdrawal'; - id = withdrawalId; - address = this.safeString (transaction, 'to_address'); - } else if (depositId !== undefined) { - type = 'deposit'; - id = depositId; - address = this.safeString (transaction, 'from_address'); - } - const additionalInfo = this.safeValue (transaction, 'additional_info', {}); - const tag = this.safeString (additionalInfo, 'memo'); - return { - 'info': transaction, - 'id': id, - 'txid': this.safeString (transaction, 'txhash'), - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'address': address, - 'tag': tag, // refix it properly - 'type': type, - 'amount': this.safeFloat (transaction, 'amount'), - 'currency': code, - 'status': this.parseTransactionStatus (transaction['status']), - 'updated': undefined, - 'fee': { - 'cost': this.safeFloat (transaction, 'fee'), - 'rate': undefined, - }, - }; - } - - sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = this.urls['api'] + '/' + this.version + '/' + this.implodeParams (path, params); - let query = this.omit (params, this.extractParams (path)); - headers = {}; - if (api === 'private') { - this.checkRequiredCredentials (); - // headers['device_id'] = this.apiKey; - headers['nonce'] = this.nonce ().toString (); - headers['Authorization'] = this.apiKey; - } - if (method === 'GET') { - query = this.urlencode (query); - if (query.length) { - url += '?' + query; - } - } else { - headers['Content-type'] = 'application/json; charset=UTF-8'; - body = this.json (query); - } - return { 'url': url, 'method': method, 'body': body, 'headers': headers }; - } - - handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { - if (code < 400 || code >= 600) { - return; - } - if (body[0] !== '{') { - throw new ExchangeError (this.id + ' ' + body); - } - const feedback = this.id + ' ' + this.json (response); - const errorCode = this.safeValue (response['error'], 'error_code'); - if (method === 'DELETE' || method === 'GET') { - if (errorCode === 'parameter_error') { - if (url.indexOf ('trading/orders/') >= 0) { - // Cobinhood returns vague "parameter_error" on fetchOrder() and cancelOrder() calls - // for invalid order IDs as well as orders that are not "open" - throw new InvalidOrder (feedback); - } - } - } - this.throwExactlyMatchedException (this.exceptions, errorCode, feedback); - throw new ExchangeError (feedback); - } - - nonce () { - return this.milliseconds (); - } -}; - -},{"./base/Exchange":7,"./base/errors":9}],62:[function(require,module,exports){ +},{"./foxbit.js":85}],61:[function(require,module,exports){ 'use strict'; // ---------------------------------------------------------------------------- @@ -36273,7 +38727,7 @@ module.exports = class coinbase extends Exchange { }; -},{"./base/Exchange":7,"./base/errors":9}],63:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],62:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -36287,6 +38741,7 @@ module.exports = class coinbaseprime extends coinbasepro { return this.deepExtend (super.describe (), { 'id': 'coinbaseprime', 'name': 'Coinbase Prime', + 'pro': true, 'urls': { 'test': { 'public': 'https://api-public.sandbox.prime.coinbase.com', @@ -36305,7 +38760,7 @@ module.exports = class coinbaseprime extends coinbasepro { } }; -},{"./coinbasepro.js":64}],64:[function(require,module,exports){ +},{"./coinbasepro.js":63}],63:[function(require,module,exports){ 'use strict'; // ---------------------------------------------------------------------------- @@ -36323,6 +38778,7 @@ module.exports = class coinbasepro extends Exchange { 'countries': [ 'US' ], 'rateLimit': 1000, 'userAgent': this.userAgents['chrome'], + 'pro': true, 'has': { 'cancelAllOrders': true, 'CORS': true, @@ -36889,6 +39345,7 @@ module.exports = class coinbasepro extends Exchange { const side = this.safeString (order, 'side'); return { 'id': id, + 'clientOrderId': undefined, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -36903,6 +39360,8 @@ module.exports = class coinbasepro extends Exchange { 'filled': filled, 'remaining': remaining, 'fee': fee, + 'average': undefined, + 'trades': undefined, }; } @@ -37264,7 +39723,7 @@ module.exports = class coinbasepro extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],65:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],64:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -37459,6 +39918,7 @@ module.exports = class coincheck extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -37473,6 +39933,8 @@ module.exports = class coincheck extends Exchange { 'cost': cost, 'fee': undefined, 'info': order, + 'average': undefined, + 'trades': undefined, }; } @@ -37696,7 +40158,7 @@ module.exports = class coincheck extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],66:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],65:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -38051,6 +40513,7 @@ module.exports = class coinegg extends Exchange { const id = this.safeString (order, 'id'); return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -38066,6 +40529,7 @@ module.exports = class coinegg extends Exchange { 'trades': undefined, 'fee': undefined, 'info': info, + 'average': undefined, }; } @@ -38201,7 +40665,7 @@ module.exports = class coinegg extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],67:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],66:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -38668,6 +41132,7 @@ module.exports = class coinex extends Exchange { const side = this.safeString (order, 'type'); return { 'id': this.safeString (order, 'id'), + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -38928,7 +41393,7 @@ module.exports = class coinex extends Exchange { const code = this.safeCurrencyCode (currencyId, currency); const timestamp = this.safeTimestamp (transaction, 'create_time'); const type = ('coin_withdraw_id' in transaction) ? 'withdraw' : 'deposit'; - const status = this.parseTransactionStatus (this.safeString (transaction, 'status'), type); + const status = this.parseTransactionStatus (this.safeString (transaction, 'status')); const amount = this.safeFloat (transaction, 'amount'); let feeCost = this.safeFloat (transaction, 'tx_fee'); if (type === 'deposit') { @@ -39115,7 +41580,7 @@ module.exports = class coinex extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],68:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],67:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -39393,6 +41858,23 @@ module.exports = class coinfalcon extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "id":"8bdd79f4-8414-40a2-90c3-e9f4d6d1eef4" + // "market":"IOT-BTC" + // "price":"0.0000003" + // "size":"4.0" + // "size_filled":"3.0" + // "fee":"0.0075" + // "fee_currency_code":"iot" + // "funds":"0.0" + // "status":"canceled" + // "order_type":"buy" + // "post_only":false + // "operation_type":"market_order" + // "created_at":"2018-01-12T21:14:06.747828Z" + // } + // if (market === undefined) { const marketId = this.safeString (order, 'market'); if (marketId in this.markets_by_id) { @@ -39426,6 +41908,7 @@ module.exports = class coinfalcon extends Exchange { const side = this.safeString (order, 'order_type'); return { 'id': this.safeString (order, 'id'), + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'status': status, @@ -39440,6 +41923,8 @@ module.exports = class coinfalcon extends Exchange { 'trades': undefined, 'fee': undefined, 'info': order, + 'lastTradeTimestamp': undefined, + 'average': undefined, }; } @@ -39546,7 +42031,7 @@ module.exports = class coinfalcon extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],69:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],68:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -39608,7 +42093,6 @@ module.exports = class coinfloor extends Exchange { 'markets': { 'BTC/GBP': { 'id': 'XBT/GBP', 'symbol': 'BTC/GBP', 'base': 'BTC', 'quote': 'GBP', 'baseId': 'XBT', 'quoteId': 'GBP', 'precision': { 'price': 0, 'amount': 4 }}, 'BTC/EUR': { 'id': 'XBT/EUR', 'symbol': 'BTC/EUR', 'base': 'BTC', 'quote': 'EUR', 'baseId': 'XBT', 'quoteId': 'EUR', 'precision': { 'price': 0, 'amount': 4 }}, - 'ETH/GBP': { 'id': 'ETH/GBP', 'symbol': 'ETH/GBP', 'base': 'ETH', 'quote': 'GBP', 'baseId': 'ETH', 'quoteId': 'GBP', 'precision': { 'price': 0, 'amount': 4 }}, }, 'exceptions': { 'exact': { @@ -39995,6 +42479,7 @@ module.exports = class coinfloor extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -40008,6 +42493,8 @@ module.exports = class coinfloor extends Exchange { 'remaining': undefined, 'cost': cost, 'fee': undefined, + 'average': undefined, + 'trades': undefined, }; } @@ -40067,7 +42554,7 @@ module.exports = class coinfloor extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],70:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],69:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -40416,7 +42903,7 @@ module.exports = class coingi extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],71:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],70:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -40545,10 +43032,13 @@ module.exports = class coinmarketcap extends Exchange { 'KingN Coin': 'KingN Coin', // conflict with KNC (Kyber Network) 'LiteBitcoin': 'LiteBitcoin', // conflict with LBTC (LightningBitcoin) 'Maggie': 'Maggie', + 'Monarch': 'Monarch', // conflict with MyToken (MT) 'MTC Mesh Network': 'MTC Mesh Network', // conflict with MTC Docademic doc.com Token https://github.com/ccxt/ccxt/issues/6081 https://github.com/ccxt/ccxt/issues/3025 'IOTA': 'IOTA', // a special case, most exchanges list it as IOTA, therefore we change just the Coinmarketcap instead of changing them all 'NetCoin': 'NetCoin', 'PCHAIN': 'PCHAIN', // conflict with PAI (Project Pai) + 'Plair': 'Plair', // conflict with PLA (PLANET) + 'PlayChip': 'PlayChip', // conflict with PLA (PLANET) 'Polcoin': 'Polcoin', 'PutinCoin': 'PutinCoin', // conflict with PUT (Profile Utility Token) 'Rcoin': 'Rcoin', // conflict with RCN (Ripio Credit Network) @@ -40586,6 +43076,9 @@ module.exports = class coinmarketcap extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'info': market, + 'active': undefined, + 'precision': this.precision, + 'limits': this.limits, }); } } @@ -40744,13 +43237,13 @@ module.exports = class coinmarketcap extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],72:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],71:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError } = require ('./base/errors'); +const { ExchangeError, ArgumentsRequired, InvalidOrder, OrderNotFound, RateLimitExceeded, InsufficientFunds } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -40763,8 +43256,14 @@ module.exports = class coinmate extends Exchange { 'rateLimit': 1000, 'has': { 'CORS': true, + 'fetchBalance': true, + 'fetchOrders': true, + 'fetchOrder': true, 'fetchMyTrades': true, 'fetchTransactions': true, + 'fetchOpenOrders': true, + 'createOrder': true, + 'cancelOrder': true, }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/27811229-c1efb510-606c-11e7-9a36-84ba2ce412d8.jpg', @@ -40813,6 +43312,7 @@ module.exports = class coinmate extends Exchange { 'openOrders', 'order', 'orderHistory', + 'orderById', 'pusherAuth', 'redeemVoucher', 'replaceByBuyLimit', @@ -40839,8 +43339,74 @@ module.exports = class coinmate extends Exchange { }, 'fees': { 'trading': { - 'maker': 0.05 / 100, - 'taker': 0.15 / 100, + 'tierBased': true, + 'percentage': true, + 'maker': 0.12 / 100, + 'taker': 0.25 / 100, + 'tiers': { + 'taker': [ + [0, 0.25 / 100], + [10000, 0.23 / 100], + [100000, 0.21 / 100], + [250000, 0.20 / 100], + [500000, 0.15 / 100], + [1000000, 0.13 / 100], + [3000000, 0.10 / 100], + [15000000, 0.05 / 100], + ], + 'maker': [ + [0, 0.12 / 100], + [10000, 0.11 / 100], + [1000000, 0.10 / 100], + [250000, 0.08 / 100], + [500000, 0.05 / 100], + [1000000, 0.03 / 100], + [3000000, 0.02 / 100], + [15000000, 0], + ], + }, + }, + 'promotional': { + 'trading': { + 'maker': 0.05 / 100, + 'taker': 0.15 / 100, + 'tiers': { + 'taker': [ + [0, 0.15 / 100], + [10000, 0.14 / 100], + [100000, 0.13 / 100], + [250000, 0.12 / 100], + [500000, 0.11 / 100], + [1000000, 0.1 / 100], + [3000000, 0.08 / 100], + [15000000, 0.05 / 100], + ], + 'maker': [ + [0, 0.05 / 100], + [10000, 0.04 / 100], + [1000000, 0.03 / 100], + [250000, 0.02 / 100], + [500000, 0], + [1000000, 0], + [3000000, 0], + [15000000, 0], + ], + }, + }, + }, + }, + 'options': { + 'promotionalMarkets': ['ETH/EUR', 'ETH/CZK', 'ETH/BTC', 'XRP/EUR', 'XRP/CZK', 'XRP/BTC', 'DASH/EUR', 'DASH/CZK', 'DASH/BTC', 'BCH/EUR', 'BCH/CZK', 'BCH/BTC'], + }, + 'exceptions': { + 'exact': { + 'No order with given ID': OrderNotFound, + }, + 'broad': { + 'Not enough account balance available': InsufficientFunds, + 'Incorrect order ID': InvalidOrder, + 'Minimum Order Size ': InvalidOrder, + 'TOO MANY REQUESTS': RateLimitExceeded, }, }, }); @@ -40877,6 +43443,12 @@ module.exports = class coinmate extends Exchange { const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const symbol = base + '/' + quote; + const promotionalMarkets = this.safeValue (this.options, 'promotionalMarkets', []); + let fees = this.safeValue (this.fees, 'trading'); + if (this.inArray (symbol, promotionalMarkets)) { + const promotionalFees = this.safeValue (this.fees, 'promotional', {}); + fees = this.safeValue (promotionalFees, 'trading', fees); + } result.push ({ 'id': id, 'symbol': symbol, @@ -40885,6 +43457,8 @@ module.exports = class coinmate extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'active': undefined, + 'maker': fees['maker'], + 'taker': fees['taker'], 'info': market, 'precision': { 'price': this.safeInteger (market, 'priceDecimals'), @@ -41073,6 +43647,10 @@ module.exports = class coinmate extends Exchange { const request = { 'limit': limit, }; + if (symbol !== undefined) { + const market = this.market (symbol); + request['currencyPair'] = market['id']; + } if (since !== undefined) { request['timestampFrom'] = since; } @@ -41196,6 +43774,144 @@ module.exports = class coinmate extends Exchange { return this.parseTrades (data, market, since, limit); } + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + const response = await this.privatePostOpenOrders (this.extend ({}, params)); + const extension = { 'status': 'open' }; + return this.parseOrders (response['data'], undefined, since, limit, extension); + } + + async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOrders requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'currencyPair': market['id'], + }; + // offset param that appears in other parts of the API doesn't appear to be supported here + if (limit !== undefined) { + request['limit'] = limit; + } + const response = await this.privatePostOrderHistory (this.extend (request, params)); + return this.parseOrders (response['data'], market, since, limit); + } + + parseOrderStatus (status) { + const statuses = { + 'FILLED': 'closed', + 'CANCELLED': 'canceled', + 'OPEN': 'open', + }; + return this.safeString (statuses, status, status); + } + + parseOrderType (type) { + const types = { + 'LIMIT': 'limit', + 'MARKET': 'market', + }; + return this.safeString (types, type, type); + } + + parseOrder (order, market = undefined) { + // + // limit sell + // + // { + // id: 781246605, + // timestamp: 1584480015133, + // trailingUpdatedTimestamp: null, + // type: 'SELL', + // currencyPair: 'ETH_BTC', + // price: 0.0345, + // amount: 0.01, + // stopPrice: null, + // originalStopPrice: null, + // marketPriceAtLastUpdate: null, + // marketPriceAtOrderCreation: null, + // orderTradeType: 'LIMIT', + // hidden: false, + // trailing: false, + // clientOrderId: null + // } + // + // limit buy + // + // { + // id: 67527001, + // timestamp: 1517931722613, + // trailingUpdatedTimestamp: null, + // type: 'BUY', + // price: 5897.24, + // remainingAmount: 0.002367, + // originalAmount: 0.1, + // stopPrice: null, + // originalStopPrice: null, + // marketPriceAtLastUpdate: null, + // marketPriceAtOrderCreation: null, + // status: 'CANCELLED', + // orderTradeType: 'LIMIT', + // hidden: false, + // avgPrice: null, + // trailing: false, + // } + // + const id = this.safeString (order, 'id'); + const timestamp = this.safeInteger (order, 'timestamp'); + const side = this.safeStringLower (order, 'type'); + const price = this.safeFloat (order, 'price'); + const amount = this.safeFloat2 (order, 'originalAmount', 'amount'); + const remaining = this.safeFloat (order, 'remainingAmount', amount); + const status = this.parseOrderStatus (this.safeString (order, 'status')); + const type = this.parseOrderType (this.safeString (order, 'orderTradeType')); + let filled = undefined; + let cost = undefined; + if ((amount !== undefined) && (remaining !== undefined)) { + filled = amount - remaining; + if (price !== undefined) { + cost = filled * price; + } + } + const average = this.safeFloat (order, 'avgPrice'); + let symbol = undefined; + const marketId = this.safeString (order, 'currencyPair'); + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } else { + const [ baseId, quoteId ] = marketId.split ('_'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const clientOrderId = this.safeString (order, 'clientOrderId'); + return { + 'id': id, + 'clientOrderId': clientOrderId, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': undefined, + 'symbol': symbol, + 'type': type, + 'side': side, + 'price': price, + 'amount': amount, + 'cost': cost, + 'average': average, + 'filled': filled, + 'remaining': remaining, + 'status': status, + 'trades': undefined, + 'info': order, + 'fee': undefined, + }; + } + async createOrder (symbol, type, side, amount, price = undefined, params = {}) { await this.loadMarkets (); let method = 'privatePost' + this.capitalize (side); @@ -41204,25 +43920,45 @@ module.exports = class coinmate extends Exchange { }; if (type === 'market') { if (side === 'buy') { - request['total'] = amount; // amount in fiat + request['total'] = this.amountToPrecision (symbol, amount); // amount in fiat } else { - request['amount'] = amount; // amount in fiat + request['amount'] = this.amountToPrecision (symbol, amount); // amount in fiat } method += 'Instant'; } else { - request['amount'] = amount; // amount in crypto - request['price'] = price; + request['amount'] = this.amountToPrecision (symbol, amount); // amount in crypto + request['price'] = this.priceToPrecision (symbol, price); method += this.capitalize (type); } const response = await this[method] (this.extend (request, params)); + const id = this.safeString (response, 'data'); return { 'info': response, - 'id': response['data'].toString (), + 'id': id, }; } + async fetchOrder (id, symbol = undefined, params = {}) { + await this.loadMarkets (); + const request = { + 'orderId': id, + }; + let market = undefined; + if (symbol) { + market = this.market (symbol); + } + const response = await this.privatePostOrderById (this.extend (request, params)); + const data = this.safeValue (response, 'data'); + return this.parseOrder (data, market); + } + async cancelOrder (id, symbol = undefined, params = {}) { - return await this.privatePostCancelOrder ({ 'orderId': id }); + // {"error":false,"errorMessage":null,"data":{"success":true,"remainingAmount":0.01}} + const request = { 'orderId': id }; + const response = await this.privatePostCancelOrderWithInfo (this.extend (request, params)); + return { + 'info': response, + }; } nonce () { @@ -41253,18 +43989,32 @@ module.exports = class coinmate extends Exchange { return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } - async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - const response = await this.fetch2 (path, api, method, params, headers, body); - if ('error' in response) { - if (response['error']) { - throw new ExchangeError (this.id + ' ' + this.json (response)); + handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (response !== undefined) { + if ('error' in response) { + // {"error":true,"errorMessage":"Minimum Order Size 0.01 ETH","data":null} + if (response['error']) { + const message = this.safeString (response, 'errorMessage'); + const feedback = this.id + ' ' + message; + this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback); + this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback); + throw new ExchangeError (this.id + ' ' + this.json (response)); + } } } - return response; + if (code > 400) { + if (body) { + const feedback = this.id + ' ' + body; + this.throwExactlyMatchedException (this.exceptions['exact'], body, feedback); + this.throwBroadlyMatchedException (this.exceptions['broad'], body, feedback); + throw new ExchangeError (feedback); // unknown message + } + throw new ExchangeError (this.id + ' ' + body); + } } }; -},{"./base/Exchange":7,"./base/errors":9}],73:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],72:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -41572,6 +44322,8 @@ module.exports = class coinone extends Exchange { 'remaining': amount, 'status': 'open', 'fee': undefined, + 'clientOrderId': undefined, + 'trades': undefined, }; this.orders[id] = order; return order; @@ -41623,6 +44375,17 @@ module.exports = class coinone extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "index": "0", + // "orderId": "68665943-1eb5-4e4b-9d76-845fc54f5489", + // "timestamp": "1449037367", + // "price": "444000.0", + // "qty": "0.3456", + // "type": "ask", + // "feeRate": "-0.0015" + // } + // const info = this.safeValue (order, 'info'); const id = this.safeStringUpper (info, 'orderId'); const timestamp = this.safeTimestamp (info, 'timestamp'); @@ -41665,6 +44428,7 @@ module.exports = class coinone extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -41678,6 +44442,8 @@ module.exports = class coinone extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'average': undefined, + 'trades': undefined, }; } @@ -41775,7 +44541,7 @@ module.exports = class coinone extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],74:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],73:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -41948,7 +44714,7 @@ module.exports = class coinspot extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],75:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],74:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -42020,7 +44786,7 @@ module.exports = class coolcoin extends coinegg { } }; -},{"./coinegg.js":66}],76:[function(require,module,exports){ +},{"./coinegg.js":65}],75:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -42856,6 +45622,7 @@ module.exports = class coss extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -42964,7 +45731,7 @@ module.exports = class coss extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],77:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],76:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -43087,6 +45854,7 @@ module.exports = class crex24 extends Exchange { }, 'commonCurrencies': { 'YOYO': 'YOYOW', + 'BULL': 'BuySell', 'BCC': 'BCH', }, // exchange-specific options @@ -43672,6 +46440,7 @@ module.exports = class crex24 extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -44266,14 +47035,14 @@ module.exports = class crex24 extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],78:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],77:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); const { TICK_SIZE } = require ('./base/functions/number'); -const { AuthenticationError, ExchangeError, ArgumentsRequired, PermissionDenied, InvalidOrder, OrderNotFound, DDoSProtection, NotSupported, ExchangeNotAvailable, InsufficientFunds } = require ('./base/errors'); +const { AuthenticationError, ExchangeError, ArgumentsRequired, PermissionDenied, InvalidOrder, OrderNotFound, DDoSProtection, NotSupported, ExchangeNotAvailable, InsufficientFunds, BadRequest, InvalidAddress, OnMaintenance } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -44283,18 +47052,46 @@ module.exports = class deribit extends Exchange { 'id': 'deribit', 'name': 'Deribit', 'countries': [ 'NL' ], // Netherlands - 'version': 'v1', + 'version': 'v2', 'userAgent': undefined, - 'rateLimit': 2000, + 'rateLimit': 500, 'has': { 'CORS': true, 'editOrder': true, + 'fetchBalance': true, 'fetchOrder': true, 'fetchOrders': false, 'fetchOpenOrders': true, 'fetchClosedOrders': true, 'fetchMyTrades': true, - 'fetchTickers': false, + 'fetchTickers': true, + 'fetchOHLCV': true, + 'fetchDepositAddress': true, + 'createDepositAddress': true, + 'fetchOrderTrades': true, + 'createOrder': true, + 'cancelOrder': true, + 'cancelAllOrders': true, + 'withdraw': true, + 'fetchTime': true, + 'fetchStatus': true, + 'fetchDeposits': true, + 'fetchWithdrawals': true, + 'fetchTransactions': false, + }, + 'timeframes': { + '1m': '1', + '3m': '3', + '5m': '5', + '10m': '10', + '15m': '15', + '30m': '30', + '1h': '60', + '2h': '120', + '3h': '180', + '6h': '360', + '12h': '720', + '1d': '1D', }, 'urls': { 'test': 'https://test.deribit.com', @@ -44302,7 +47099,7 @@ module.exports = class deribit extends Exchange { 'api': 'https://www.deribit.com', 'www': 'https://www.deribit.com', 'doc': [ - 'https://docs.deribit.com', + 'https://docs.deribit.com/v2', 'https://github.com/deribit', ], 'fees': 'https://www.deribit.com/pages/information/fees', @@ -44311,193 +47108,461 @@ module.exports = class deribit extends Exchange { 'api': { 'public': { 'get': [ - 'ping', + // Authentication + 'auth', + 'exchange_token', + 'fork_token', + // Session management + 'set_heartbeat', + 'disable_heartbeat', + // Supporting + 'get_time', + 'hello', 'test', - 'getinstruments', - 'index', - 'getcurrencies', - 'getorderbook', - 'getlasttrades', - 'getsummary', - 'stats', - 'getannouncments', + // Subscription management + 'subscribe', + 'unsubscribe', + // Account management + 'get_announcements', + // Market data + 'get_book_summary_by_currency', + 'get_book_summary_by_instrument', + 'get_contract_size', + 'get_currencies', + 'get_funding_chart_data', + 'get_funding_rate_history', + 'get_funding_rate_value', + 'get_historical_volatility', + 'get_index', + 'get_instruments', + 'get_last_settlements_by_currency', + 'get_last_settlements_by_instrument', + 'get_last_trades_by_currency', + 'get_last_trades_by_currency_and_time', + 'get_last_trades_by_instrument', + 'get_last_trades_by_instrument_and_time', + 'get_order_book', + 'get_trade_volumes', + 'get_tradingview_chart_data', + 'ticker', ], }, 'private': { 'get': [ - 'account', - 'getopenorders', - 'positions', - 'orderhistory', - 'orderstate', - 'tradehistory', - 'newannouncements', - ], - 'post': [ + // Authentication + 'logout', + // Session management + 'enable_cancel_on_disconnect', + 'disable_cancel_on_disconnect', + 'get_cancel_on_disconnect', + // Subscription management + 'subscribe', + 'unsubscribe', + // Account management + 'change_api_key_name', + 'change_scope_in_api_key', + 'change_subaccount_name', + 'create_api_key', + 'create_subaccount', + 'disable_api_key', + 'disable_tfa_for_subaccount', + 'enable_api_key', + 'get_account_summary', + 'get_email_language', + 'get_new_announcements', + 'get_position', + 'get_positions', + 'get_subaccounts', + 'list_api_keys', + 'remove_api_key', + 'reset_api_key', + 'set_announcement_as_read', + 'set_api_key_as_default', + 'set_email_for_subaccount', + 'set_email_language', + 'set_password_for_subaccount', + 'toggle_notifications_from_subaccount', + 'toggle_subaccount_login', + // Block Trade + 'execute_block_trade', + 'get_block_trade', + 'get_last_block_trades_by_currency', + 'invalidate_block_trade_signature', + 'verify_block_trade', + // Trading 'buy', 'sell', 'edit', 'cancel', - 'cancelall', + 'cancel_all', + 'cancel_all_by_currency', + 'cancel_all_by_instrument', + 'cancel_by_label', + 'close_position', + 'get_margins', + 'get_open_orders_by_currency', + 'get_open_orders_by_instrument', + 'get_order_history_by_currency', + 'get_order_history_by_instrument', + 'get_order_margin_by_ids', + 'get_order_state', + 'get_stop_order_history', + 'get_user_trades_by_currency', + 'get_user_trades_by_currency_and_time', + 'get_user_trades_by_instrument', + 'get_user_trades_by_instrument_and_time', + 'get_user_trades_by_order', + 'get_settlement_history_by_instrument', + 'get_settlement_history_by_currency', + // Wallet + 'cancel_transfer_by_id', + 'cancel_withdrawal', + 'create_deposit_address', + 'get_current_deposit_address', + 'get_deposits', + 'get_transfers', + 'get_withdrawals', + 'submit_transfer_to_subaccount', + 'submit_transfer_to_user', + 'withdraw', ], }, }, 'exceptions': { - // 0 or absent Success, No error - '9999': PermissionDenied, // "api_not_enabled" User didn't enable API for the Account - '10000': AuthenticationError, // "authorization_required" Authorization issue, invalid or absent signature etc - '10001': ExchangeError, // "error" Some general failure, no public information available - '10002': InvalidOrder, // "qty_too_low" Order quantity is too low - '10003': InvalidOrder, // "order_overlap" Rejection, order overlap is found and self-trading is not enabled - '10004': OrderNotFound, // "order_not_found" Attempt to operate with order that can't be found by specified id - '10005': InvalidOrder, // "price_too_low " Price is too low, defines current limit for the operation - '10006': InvalidOrder, // "price_too_low4idx " Price is too low for current index, defines current bottom limit for the operation - '10007': InvalidOrder, // "price_too_high " Price is too high, defines current up limit for the operation - '10008': InvalidOrder, // "price_too_high4idx " Price is too high for current index, defines current up limit for the operation - '10009': InsufficientFunds, // "not_enough_funds" Account has not enough funds for the operation - '10010': OrderNotFound, // "already_closed" Attempt of doing something with closed order - '10011': InvalidOrder, // "price_not_allowed" This price is not allowed for some reason - '10012': InvalidOrder, // "book_closed" Operation for instrument which order book had been closed - '10013': PermissionDenied, // "pme_max_total_open_orders " Total limit of open orders has been exceeded, it is applicable for PME users - '10014': PermissionDenied, // "pme_max_future_open_orders " Limit of count of futures' open orders has been exceeded, it is applicable for PME users - '10015': PermissionDenied, // "pme_max_option_open_orders " Limit of count of options' open orders has been exceeded, it is applicable for PME users - '10016': PermissionDenied, // "pme_max_future_open_orders_size " Limit of size for futures has been exceeded, it is applicable for PME users - '10017': PermissionDenied, // "pme_max_option_open_orders_size " Limit of size for options has been exceeded, it is applicable for PME users - '10019': PermissionDenied, // "locked_by_admin" Trading is temporary locked by admin - '10020': ExchangeError, // "invalid_or_unsupported_instrument" Instrument name is not valid - '10022': InvalidOrder, // "invalid_quantity" quantity was not recognized as a valid number - '10023': InvalidOrder, // "invalid_price" price was not recognized as a valid number - '10024': InvalidOrder, // "invalid_max_show" max_show parameter was not recognized as a valid number - '10025': InvalidOrder, // "invalid_order_id" Order id is missing or its format was not recognized as valid - '10026': InvalidOrder, // "price_precision_exceeded" Extra precision of the price is not supported - '10027': InvalidOrder, // "non_integer_contract_amount" Futures contract amount was not recognized as integer - '10028': DDoSProtection, // "too_many_requests" Allowed request rate has been exceeded - '10029': OrderNotFound, // "not_owner_of_order" Attempt to operate with not own order - '10030': ExchangeError, // "must_be_websocket_request" REST request where Websocket is expected - '10031': ExchangeError, // "invalid_args_for_instrument" Some of arguments are not recognized as valid - '10032': InvalidOrder, // "whole_cost_too_low" Total cost is too low - '10033': NotSupported, // "not_implemented" Method is not implemented yet - '10034': InvalidOrder, // "stop_price_too_high" Stop price is too high - '10035': InvalidOrder, // "stop_price_too_low" Stop price is too low - '11035': InvalidOrder, // "no_more_stops " Allowed amount of stop orders has been exceeded - '11036': InvalidOrder, // "invalid_stoppx_for_index_or_last" Invalid StopPx (too high or too low) as to current index or market - '11037': InvalidOrder, // "outdated_instrument_for_IV_order" Instrument already not available for trading - '11038': InvalidOrder, // "no_adv_for_futures" Advanced orders are not available for futures - '11039': InvalidOrder, // "no_adv_postonly" Advanced post-only orders are not supported yet - '11040': InvalidOrder, // "impv_not_in_range 0..499%" Implied volatility is out of allowed range - '11041': InvalidOrder, // "not_adv_order" Advanced order properties can't be set if the order is not advanced - '11042': PermissionDenied, // "permission_denied" Permission for the operation has been denied - '11044': OrderNotFound, // "not_open_order" Attempt to do open order operations with the not open order - '11045': ExchangeError, // "invalid_event" Event name has not been recognized - '11046': ExchangeError, // "outdated_instrument" At several minutes to instrument expiration, corresponding advanced implied volatility orders are not allowed - '11047': ExchangeError, // "unsupported_arg_combination" The specified combination of arguments is not supported - '11048': ExchangeError, // "not_on_this_server" The requested operation is not available on this server. - '11050': ExchangeError, // "invalid_request" Request has not been parsed properly - '11051': ExchangeNotAvailable, // "system_maintenance" System is under maintenance - '11030': ExchangeError, // "other_reject " Some rejects which are not considered as very often, more info may be specified in - '11031': ExchangeError, // "other_error " Some errors which are not considered as very often, more info may be specified in + // 0 or absent Success, No error. + '9999': PermissionDenied, // 'api_not_enabled' User didn't enable API for the Account. + '10000': AuthenticationError, // 'authorization_required' Authorization issue, invalid or absent signature etc. + '10001': ExchangeError, // 'error' Some general failure, no public information available. + '10002': InvalidOrder, // 'qty_too_low' Order quantity is too low. + '10003': InvalidOrder, // 'order_overlap' Rejection, order overlap is found and self-trading is not enabled. + '10004': OrderNotFound, // 'order_not_found' Attempt to operate with order that can't be found by specified id. + '10005': InvalidOrder, // 'price_too_low ' Price is too low, defines current limit for the operation. + '10006': InvalidOrder, // 'price_too_low4idx ' Price is too low for current index, defines current bottom limit for the operation. + '10007': InvalidOrder, // 'price_too_high ' Price is too high, defines current up limit for the operation. + '10008': InvalidOrder, // 'price_too_high4idx ' Price is too high for current index, defines current up limit for the operation. + '10009': InsufficientFunds, // 'not_enough_funds' Account has not enough funds for the operation. + '10010': OrderNotFound, // 'already_closed' Attempt of doing something with closed order. + '10011': InvalidOrder, // 'price_not_allowed' This price is not allowed for some reason. + '10012': InvalidOrder, // 'book_closed' Operation for instrument which order book had been closed. + '10013': PermissionDenied, // 'pme_max_total_open_orders ' Total limit of open orders has been exceeded, it is applicable for PME users. + '10014': PermissionDenied, // 'pme_max_future_open_orders ' Limit of count of futures' open orders has been exceeded, it is applicable for PME users. + '10015': PermissionDenied, // 'pme_max_option_open_orders ' Limit of count of options' open orders has been exceeded, it is applicable for PME users. + '10016': PermissionDenied, // 'pme_max_future_open_orders_size ' Limit of size for futures has been exceeded, it is applicable for PME users. + '10017': PermissionDenied, // 'pme_max_option_open_orders_size ' Limit of size for options has been exceeded, it is applicable for PME users. + '10018': PermissionDenied, // 'non_pme_max_future_position_size ' Limit of size for futures has been exceeded, it is applicable for non-PME users. + '10019': PermissionDenied, // 'locked_by_admin' Trading is temporary locked by admin. + '10020': ExchangeError, // 'invalid_or_unsupported_instrument' Instrument name is not valid. + '10021': InvalidOrder, // 'invalid_amount' Amount is not valid. + '10022': InvalidOrder, // 'invalid_quantity' quantity was not recognized as a valid number (for API v1). + '10023': InvalidOrder, // 'invalid_price' price was not recognized as a valid number. + '10024': InvalidOrder, // 'invalid_max_show' max_show parameter was not recognized as a valid number. + '10025': InvalidOrder, // 'invalid_order_id' Order id is missing or its format was not recognized as valid. + '10026': InvalidOrder, // 'price_precision_exceeded' Extra precision of the price is not supported. + '10027': InvalidOrder, // 'non_integer_contract_amount' Futures contract amount was not recognized as integer. + '10028': DDoSProtection, // 'too_many_requests' Allowed request rate has been exceeded. + '10029': OrderNotFound, // 'not_owner_of_order' Attempt to operate with not own order. + '10030': ExchangeError, // 'must_be_websocket_request' REST request where Websocket is expected. + '10031': ExchangeError, // 'invalid_args_for_instrument' Some of arguments are not recognized as valid. + '10032': InvalidOrder, // 'whole_cost_too_low' Total cost is too low. + '10033': NotSupported, // 'not_implemented' Method is not implemented yet. + '10034': InvalidOrder, // 'stop_price_too_high' Stop price is too high. + '10035': InvalidOrder, // 'stop_price_too_low' Stop price is too low. + '10036': InvalidOrder, // 'invalid_max_show_amount' Max Show Amount is not valid. + '10040': ExchangeNotAvailable, // 'retry' Request can't be processed right now and should be retried. + '10041': OnMaintenance, // 'settlement_in_progress' Settlement is in progress. Every day at settlement time for several seconds, the system calculates user profits and updates balances. That time trading is paused for several seconds till the calculation is completed. + '10043': InvalidOrder, // 'price_wrong_tick' Price has to be rounded to a certain tick size. + '10044': InvalidOrder, // 'stop_price_wrong_tick' Stop Price has to be rounded to a certain tick size. + '10045': InvalidOrder, // 'can_not_cancel_liquidation_order' Liquidation order can't be canceled. + '10046': InvalidOrder, // 'can_not_edit_liquidation_order' Liquidation order can't be edited. + '10047': DDoSProtection, // 'matching_engine_queue_full' Reached limit of pending Matching Engine requests for user. + '10048': ExchangeError, // 'not_on_this_server' The requested operation is not available on this server. + '11008': InvalidOrder, // 'already_filled' This request is not allowed in regards to the filled order. + '11029': BadRequest, // 'invalid_arguments' Some invalid input has been detected. + '11030': ExchangeError, // 'other_reject ' Some rejects which are not considered as very often, more info may be specified in . + '11031': ExchangeError, // 'other_error ' Some errors which are not considered as very often, more info may be specified in . + '11035': DDoSProtection, // 'no_more_stops ' Allowed amount of stop orders has been exceeded. + '11036': InvalidOrder, // 'invalid_stoppx_for_index_or_last' Invalid StopPx (too high or too low) as to current index or market. + '11037': BadRequest, // 'outdated_instrument_for_IV_order' Instrument already not available for trading. + '11038': InvalidOrder, // 'no_adv_for_futures' Advanced orders are not available for futures. + '11039': InvalidOrder, // 'no_adv_postonly' Advanced post-only orders are not supported yet. + '11041': InvalidOrder, // 'not_adv_order' Advanced order properties can't be set if the order is not advanced. + '11042': PermissionDenied, // 'permission_denied' Permission for the operation has been denied. + '11043': BadRequest, // 'bad_argument' Bad argument has been passed. + '11044': InvalidOrder, // 'not_open_order' Attempt to do open order operations with the not open order. + '11045': BadRequest, // 'invalid_event' Event name has not been recognized. + '11046': BadRequest, // 'outdated_instrument' At several minutes to instrument expiration, corresponding advanced implied volatility orders are not allowed. + '11047': BadRequest, // 'unsupported_arg_combination' The specified combination of arguments is not supported. + '11048': ExchangeError, // 'wrong_max_show_for_option' Wrong Max Show for options. + '11049': BadRequest, // 'bad_arguments' Several bad arguments have been passed. + '11050': BadRequest, // 'bad_request' Request has not been parsed properly. + '11051': OnMaintenance, // 'system_maintenance' System is under maintenance. + '11052': ExchangeError, // 'subscribe_error_unsubscribed' Subscription error. However, subscription may fail without this error, please check list of subscribed channels returned, as some channels can be not subscribed due to wrong input or lack of permissions. + '11053': ExchangeError, // 'transfer_not_found' Specified transfer is not found. + '11090': InvalidAddress, // 'invalid_addr' Invalid address. + '11091': InvalidAddress, // 'invalid_transfer_address' Invalid addres for the transfer. + '11092': InvalidAddress, // 'address_already_exist' The address already exists. + '11093': DDoSProtection, // 'max_addr_count_exceeded' Limit of allowed addresses has been reached. + '11094': ExchangeError, // 'internal_server_error' Some unhandled error on server. Please report to admin. The details of the request will help to locate the problem. + '11095': ExchangeError, // 'disabled_deposit_address_creation' Deposit address creation has been disabled by admin. + '11096': ExchangeError, // 'address_belongs_to_user' Withdrawal instead of transfer. + '12000': AuthenticationError, // 'bad_tfa' Wrong TFA code + '12001': DDoSProtection, // 'too_many_subaccounts' Limit of subbacounts is reached. + '12002': ExchangeError, // 'wrong_subaccount_name' The input is not allowed as name of subaccount. + '12998': AuthenticationError, // 'tfa_over_limit' The number of failed TFA attempts is limited. + '12003': AuthenticationError, // 'login_over_limit' The number of failed login attempts is limited. + '12004': AuthenticationError, // 'registration_over_limit' The number of registration requests is limited. + '12005': AuthenticationError, // 'country_is_banned' The country is banned (possibly via IP check). + '12100': ExchangeError, // 'transfer_not_allowed' Transfer is not allowed. Possible wrong direction or other mistake. + '12999': AuthenticationError, // 'tfa_used' TFA code is correct but it is already used. Please, use next code. + '13000': AuthenticationError, // 'invalid_login' Login name is invalid (not allowed or it contains wrong characters). + '13001': AuthenticationError, // 'account_not_activated' Account must be activated. + '13002': PermissionDenied, // 'account_blocked' Account is blocked by admin. + '13003': AuthenticationError, // 'tfa_required' This action requires TFA authentication. + '13004': AuthenticationError, // 'invalid_credentials' Invalid credentials has been used. + '13005': AuthenticationError, // 'pwd_match_error' Password confirmation error. + '13006': AuthenticationError, // 'security_error' Invalid Security Code. + '13007': AuthenticationError, // 'user_not_found' User's security code has been changed or wrong. + '13008': ExchangeError, // 'request_failed' Request failed because of invalid input or internal failure. + '13009': AuthenticationError, // 'unauthorized' Wrong or expired authorization token or bad signature. For example, please check scope of the token, 'connection' scope can't be reused for other connections. + '13010': BadRequest, // 'value_required' Invalid input, missing value. + '13011': BadRequest, // 'value_too_short' Input is too short. + '13012': PermissionDenied, // 'unavailable_in_subaccount' Subaccount restrictions. + '13013': BadRequest, // 'invalid_phone_number' Unsupported or invalid phone number. + '13014': BadRequest, // 'cannot_send_sms' SMS sending failed -- phone number is wrong. + '13015': BadRequest, // 'invalid_sms_code' Invalid SMS code. + '13016': BadRequest, // 'invalid_input' Invalid input. + '13017': ExchangeError, // 'subscription_failed' Subscription hailed, invalid subscription parameters. + '13018': ExchangeError, // 'invalid_content_type' Invalid content type of the request. + '13019': ExchangeError, // 'orderbook_closed' Closed, expired order book. + '13020': ExchangeError, // 'not_found' Instrument is not found, invalid instrument name. + '13021': PermissionDenied, // 'forbidden' Not enough permissions to execute the request, forbidden. + '13025': ExchangeError, // 'method_switched_off_by_admin' API method temporarily switched off by administrator. + '-32602': BadRequest, // 'Invalid params' see JSON-RPC spec. + '-32601': BadRequest, // 'Method not found' see JSON-RPC spec. + '-32700': BadRequest, // 'Parse error' see JSON-RPC spec. + '-32000': BadRequest, // 'Missing params' see JSON-RPC spec. }, 'precisionMode': TICK_SIZE, 'options': { - 'fetchTickerQuotes': true, + 'code': 'BTC', + 'fetchBalance': { + 'code': 'BTC', + }, }, }); } + async fetchTime (params = {}) { + const response = await this.publicGetGetTime (params); + // + // { + // jsonrpc: '2.0', + // result: 1583922446019, + // usIn: 1583922446019955, + // usOut: 1583922446019956, + // usDiff: 1, + // testnet: false + // } + // + return this.safeInteger (response, 'result'); + } + + codeFromOptions (methodName) { + const defaultCode = this.safeValue (this.options, 'code', 'BTC'); + const options = this.safeValue (this.options, methodName, {}); + return this.safeValue (options, 'code', defaultCode); + } + + async fetchStatus (params = {}) { + const request = { + // 'expected_result': false, // true will trigger an error for testing purposes + }; + await this.publicGetTest (this.extend (request, params)); + // + // { + // jsonrpc: '2.0', + // result: { version: '1.2.26' }, + // usIn: 1583922623964485, + // usOut: 1583922623964487, + // usDiff: 2, + // testnet: false + // } + // + this.status = this.extend (this.status, { + 'status': 'ok', + 'updated': this.milliseconds (), + }); + return this.status; + } + async fetchMarkets (params = {}) { - const response = await this.publicGetGetinstruments (params); - const markets = this.safeValue (response, 'result'); + const currenciesResponse = await this.publicGetGetCurrencies (params); + // + // { + // jsonrpc: '2.0', + // result: [ + // { + // withdrawal_priorities: [ + // { value: 0.15, name: 'very_low' }, + // { value: 1.5, name: 'very_high' }, + // ], + // withdrawal_fee: 0.0005, + // min_withdrawal_fee: 0.0005, + // min_confirmations: 1, + // fee_precision: 4, + // currency_long: 'Bitcoin', + // currency: 'BTC', + // coin_type: 'BITCOIN' + // } + // ], + // usIn: 1583761588590479, + // usOut: 1583761588590544, + // usDiff: 65, + // testnet: false + // } + // + const currenciesResult = this.safeValue (currenciesResponse, 'result', []); const result = []; - for (let i = 0; i < markets.length; i++) { - const market = markets[i]; - const id = this.safeString (market, 'instrumentName'); - const baseId = this.safeString (market, 'baseCurrency'); - const quoteId = this.safeString (market, 'currency'); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - const type = this.safeString (market, 'kind'); - const future = (type === 'future'); - const option = (type === 'option'); - const active = this.safeValue (market, 'isActive'); - const precision = { - 'amount': this.safeFloat (market, 'minTradeAmount'), - 'price': this.safeFloat (market, 'tickSize'), + for (let i = 0; i < currenciesResult.length; i++) { + const currencyId = this.safeString (currenciesResult[i], 'currency'); + const request = { + 'currency': currencyId, }; - result.push ({ - 'id': id, - 'symbol': id, - 'base': base, - 'quote': quote, - 'active': active, - 'precision': precision, - 'limits': { - 'amount': { - 'min': this.safeFloat (market, 'minTradeAmount'), - 'max': undefined, + const instrumentsResponse = await this.publicGetGetInstruments (this.extend (request, params)); + // + // { + // jsonrpc: '2.0', + // result: [ + // { + // tick_size: 0.0005, + // taker_commission: 0.0004, + // strike: 300, + // settlement_period: 'week', + // quote_currency: 'USD', + // option_type: 'call', + // min_trade_amount: 1, + // maker_commission: 0.0004, + // kind: 'option', + // is_active: true, + // instrument_name: 'ETH-13MAR20-300-C', + // expiration_timestamp: 1584086400000, + // creation_timestamp: 1582790403000, + // contract_size: 1, + // base_currency: 'ETH' + // }, + // ], + // usIn: 1583761889500586, + // usOut: 1583761889505066, + // usDiff: 4480, + // testnet: false + // } + // + const instrumentsResult = this.safeValue (instrumentsResponse, 'result', []); + for (let k = 0; k < instrumentsResult.length; k++) { + const market = instrumentsResult[k]; + const id = this.safeString (market, 'instrument_name'); + const baseId = this.safeString (market, 'base_currency'); + const quoteId = this.safeString (market, 'quote_currency'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + const type = this.safeString (market, 'kind'); + const future = (type === 'future'); + const option = (type === 'option'); + const active = this.safeValue (market, 'is_active'); + const minTradeAmount = this.safeFloat (market, 'min_trade_amount'); + const tickSize = this.safeFloat (market, 'tick_size'); + const precision = { + 'amount': minTradeAmount, + 'price': tickSize, + }; + result.push ({ + 'id': id, + 'symbol': id, + 'base': base, + 'quote': quote, + 'active': active, + 'precision': precision, + 'taker': this.safeFloat (market, 'taker_commission'), + 'maker': this.safeFloat (market, 'maker_commission'), + 'limits': { + 'amount': { + 'min': minTradeAmount, + 'max': undefined, + }, + 'price': { + 'min': tickSize, + 'max': undefined, + }, + 'cost': { + 'min': undefined, + 'max': undefined, + }, }, - 'price': { - 'min': this.safeFloat (market, 'tickSize'), - 'max': undefined, - }, - 'cost': { - 'min': undefined, - 'max': undefined, - }, - }, - 'type': type, - 'spot': false, - 'future': future, - 'option': option, - 'info': market, - }); + 'type': type, + 'spot': false, + 'future': future, + 'option': option, + 'info': market, + }); + } } return result; } async fetchBalance (params = {}) { await this.loadMarkets (); - const response = await this.privateGetAccount (params); + const code = this.codeFromOptions ('fetchBalance'); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + }; + const response = await this.privateGetGetAccountSummary (this.extend (request, params)); // // { - // "usOut":1569048827943520, - // "usIn":1569048827943020, - // "usDiff":500, - // "testnet":false, - // "success":true, - // "result":{ - // "equity":2e-9, - // "maintenanceMargin":0.0, - // "initialMargin":0.0, - // "availableFunds":0.0, - // "balance":0.0, - // "marginBalance":0.0, - // "SUPL":0.0, - // "SRPL":0.0, - // "PNL":0.0, - // "optionsPNL":0.0, - // "optionsSUPL":0.0, - // "optionsSRPL":0.0, - // "optionsD":0.0, - // "optionsG":0.0, - // "optionsV":0.0, - // "optionsTh":0.0, - // "futuresPNL":0.0, - // "futuresSUPL":0.0, - // "futuresSRPL":0.0, - // "deltaTotal":0.0, - // "sessionFunding":0.0, - // "depositAddress":"13tUtNsJSZa1F5GeCmwBywVrymHpZispzw", - // "currency":"BTC" + // jsonrpc: '2.0', + // result: { + // total_pl: 0, + // session_upl: 0, + // session_rpl: 0, + // session_funding: 0, + // portfolio_margining_enabled: false, + // options_vega: 0, + // options_theta: 0, + // options_session_upl: 0, + // options_session_rpl: 0, + // options_pl: 0, + // options_gamma: 0, + // options_delta: 0, + // margin_balance: 0.00062359, + // maintenance_margin: 0, + // limits: { + // non_matching_engine_burst: 300, + // non_matching_engine: 200, + // matching_engine_burst: 20, + // matching_engine: 2 + // }, + // initial_margin: 0, + // futures_session_upl: 0, + // futures_session_rpl: 0, + // futures_pl: 0, + // equity: 0.00062359, + // deposit_address: '13tUtNsJSZa1F5GeCmwBywVrymHpZispzw', + // delta_total: 0, + // currency: 'BTC', + // balance: 0.00062359, + // available_withdrawal_funds: 0.00062359, + // available_funds: 0.00062359 // }, - // "message":"" + // usIn: 1583775838115975, + // usOut: 1583775838116520, + // usDiff: 545, + // testnet: false // } // const result = { 'info': response, }; const balance = this.safeValue (response, 'result', {}); - const currencyId = this.safeString (balance, 'currency'); - const code = this.safeCurrencyCode (currencyId); const account = this.account (); account['free'] = this.safeFloat (balance, 'availableFunds'); account['used'] = this.safeFloat (balance, 'maintenanceMargin'); @@ -44506,15 +47571,63 @@ module.exports = class deribit extends Exchange { return this.parseBalance (result); } + async createDepositAddress (code, params = {}) { + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + }; + const response = await this.privateGetCreateDepositAddress (this.extend (request, params)); + // + // { + // 'jsonrpc': '2.0', + // 'id': 7538, + // 'result': { + // 'address': '2N8udZGBc1hLRCFsU9kGwMPpmYUwMFTuCwB', + // 'creation_timestamp': 1550575165170, + // 'currency': 'BTC', + // 'type': 'deposit' + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const address = this.safeString (result, 'address'); + this.checkAddress (address); + return { + 'currency': code, + 'address': address, + 'tag': undefined, + 'info': response, + }; + } + async fetchDepositAddress (code, params = {}) { await this.loadMarkets (); const currency = this.currency (code); const request = { 'currency': currency['id'], }; - const response = await this.privateGetAccount (this.extend (request, params)); + const response = await this.privateGetGetCurrentDepositAddress (this.extend (request, params)); + // + // { + // jsonrpc: '2.0', + // result: { + // type: 'deposit', + // status: 'ready', + // requires_confirmation: true, + // currency: 'BTC', + // creation_timestamp: 1514694684651, + // address: '13tUtNsJSZa1F5GeCmwBywVrymHpZispzw' + // }, + // usIn: 1583785137274288, + // usOut: 1583785137274454, + // usDiff: 166, + // testnet: false + // } + // const result = this.safeValue (response, 'result', {}); - const address = this.safeString (result, 'depositAddress'); + const address = this.safeString (result, 'address'); + this.checkAddress (address); return { 'currency': code, 'address': address, @@ -44524,47 +47637,73 @@ module.exports = class deribit extends Exchange { } parseTicker (ticker, market = undefined) { + // + // fetchTicker /public/ticker // // { - // "currentFunding":0.0, - // "funding8h":0.0000017213784611422821, - // "instrumentName":"BTC-PERPETUAL", - // "openInterest":7600223, - // "openInterestAmount":76002230, - // "high":7665.5, - // "low":7450.0, - // "volume":12964792.0, - // "volumeUsd":129647920, - // "volumeBtc":17214.63595316, - // "last":7520.5, - // "bidPrice":7520.0, - // "askPrice":7520.5, - // "midPrice":7520.25, - // "estDelPrice":"", - // "markPrice":7521.0, - // "created":"2019-12-09 15:17:00 GMT" + // timestamp: 1583778859480, + // stats: { volume: 60627.57263769, low: 7631.5, high: 8311.5 }, + // state: 'open', + // settlement_price: 7903.21, + // open_interest: 111543850, + // min_price: 7634, + // max_price: 7866.51, + // mark_price: 7750.02, + // last_price: 7750.5, + // instrument_name: 'BTC-PERPETUAL', + // index_price: 7748.01, + // funding_8h: 0.0000026, + // current_funding: 0, + // best_bid_price: 7750, + // best_bid_amount: 19470, + // best_ask_price: 7750.5, + // best_ask_amount: 343280 // } // - const timestamp = this.safeInteger (ticker, 'created'); - let symbol = undefined; - const marketId = this.safeString (ticker, 'instrumentName'); + // fetchTicker /public/get_book_summary_by_instrument + // fetchTickers /public/get_book_summary_by_currency + // + // { + // volume: 124.1, + // underlying_price: 7856.445926872601, + // underlying_index: 'SYN.BTC-10MAR20', + // quote_currency: 'USD', + // open_interest: 121.8, + // mid_price: 0.01975, + // mark_price: 0.01984559, + // low: 0.0095, + // last: 0.0205, + // interest_rate: 0, + // instrument_name: 'BTC-10MAR20-7750-C', + // high: 0.0295, + // estimated_delivery_price: 7856.29, + // creation_timestamp: 1583783678366, + // bid_price: 0.0185, + // base_currency: 'BTC', + // ask_price: 0.021 + // }, + // + const timestamp = this.safeInteger2 (ticker, 'timestamp', 'creation_timestamp'); + const marketId = this.safeString (ticker, 'instrument_name'); + let symbol = marketId; if (marketId in this.markets_by_id) { market = this.markets_by_id[marketId]; } if ((symbol === undefined) && (market !== undefined)) { symbol = market['symbol']; } - const last = this.safeFloat (ticker, 'last'); + const last = this.safeFloat2 (ticker, 'last_price', 'last'); + const stats = this.safeValue (ticker, 'stats', ticker); return { 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), - 'high': this.safeFloat (ticker, 'high'), - 'low': this.safeFloat (ticker, 'low'), - 'bid': this.safeFloat (ticker, 'bidPrice'), - 'bidVolume': undefined, - 'ask': this.safeFloat (ticker, 'askPrice'), - 'askVolume': undefined, + 'high': this.safeFloat2 (stats, 'high', 'max_price'), + 'low': this.safeFloat2 (stats, 'low', 'min_price'), + 'bid': this.safeFloat2 (ticker, 'best_bid_price', 'bid_price'), + 'bidVolume': this.safeFloat (ticker, 'best_bid_amount'), + 'ask': this.safeFloat2 (ticker, 'best_ask_price', 'ask_price'), + 'askVolume': this.safeFloat (ticker, 'best_ask_amount'), 'vwap': undefined, 'open': undefined, 'close': last, @@ -44574,7 +47713,7 @@ module.exports = class deribit extends Exchange { 'percentage': undefined, 'average': undefined, 'baseVolume': undefined, - 'quoteVolume': this.safeFloat (ticker, 'volume'), + 'quoteVolume': this.safeFloat (stats, 'volume'), 'info': ticker, }; } @@ -44583,39 +47722,136 @@ module.exports = class deribit extends Exchange { await this.loadMarkets (); const market = this.market (symbol); const request = { - 'instrument': market['id'], + 'instrument_name': market['id'], }; - const response = await this.publicGetGetsummary (this.extend (request, params)); + const response = await this.publicGetTicker (this.extend (request, params)); // // { - // "usOut":1575904620528163, - // "usIn":1575904620528129, - // "usDiff":34, - // "testnet":false, - // "success":true, - // "result": { - // "currentFunding":0.0, - // "funding8h":0.0000017213784611422821, - // "instrumentName":"BTC-PERPETUAL", - // "openInterest":7600223, - // "openInterestAmount":76002230, - // "high":7665.5, - // "low":7450.0, - // "volume":12964792.0, - // "volumeUsd":129647920, - // "volumeBtc":17214.63595316, - // "last":7520.5, - // "bidPrice":7520.0, - // "askPrice":7520.5, - // "midPrice":7520.25, - // "estDelPrice":"", - // "markPrice":7521.0, - // "created":"2019-12-09 15:17:00 GMT" + // jsonrpc: '2.0', + // result: { + // timestamp: 1583778859480, + // stats: { volume: 60627.57263769, low: 7631.5, high: 8311.5 }, + // state: 'open', + // settlement_price: 7903.21, + // open_interest: 111543850, + // min_price: 7634, + // max_price: 7866.51, + // mark_price: 7750.02, + // last_price: 7750.5, + // instrument_name: 'BTC-PERPETUAL', + // index_price: 7748.01, + // funding_8h: 0.0000026, + // current_funding: 0, + // best_bid_price: 7750, + // best_bid_amount: 19470, + // best_ask_price: 7750.5, + // best_ask_amount: 343280 // }, - // "message":"" + // usIn: 1583778859483941, + // usOut: 1583778859484075, + // usDiff: 134, + // testnet: false // } // - return this.parseTicker (response['result'], market); + const result = this.safeValue (response, 'result'); + return this.parseTicker (result, market); + } + + async fetchTickers (symbols = undefined, params = {}) { + await this.loadMarkets (); + const code = this.codeFromOptions ('fetchTickers'); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + }; + const response = await this.publicGetGetBookSummaryByCurrency (this.extend (request, params)); + // + // { + // jsonrpc: '2.0', + // result: [ + // { + // volume: 124.1, + // underlying_price: 7856.445926872601, + // underlying_index: 'SYN.BTC-10MAR20', + // quote_currency: 'USD', + // open_interest: 121.8, + // mid_price: 0.01975, + // mark_price: 0.01984559, + // low: 0.0095, + // last: 0.0205, + // interest_rate: 0, + // instrument_name: 'BTC-10MAR20-7750-C', + // high: 0.0295, + // estimated_delivery_price: 7856.29, + // creation_timestamp: 1583783678366, + // bid_price: 0.0185, + // base_currency: 'BTC', + // ask_price: 0.021 + // }, + // ], + // usIn: 1583783678361966, + // usOut: 1583783678372069, + // usDiff: 10103, + // testnet: false + // } + // + const result = this.safeValue (response, 'result', []); + const tickers = {}; + for (let i = 0; i < result.length; i++) { + const ticker = this.parseTicker (result[i]); + const symbol = ticker['symbol']; + tickers[symbol] = ticker; + } + return this.filterByArray (tickers, 'symbol', symbols); + } + + async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'instrument_name': market['id'], + 'resolution': this.timeframes[timeframe], + }; + const duration = this.parseTimeframe (timeframe); + const now = this.milliseconds (); + if (since === undefined) { + if (limit === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument or a limit argument'); + } else { + request['start_timestamp'] = now - (limit - 1) * duration * 1000; + request['end_timestamp'] = now; + } + } else { + request['start_timestamp'] = since; + if (limit === undefined) { + request['end_timestamp'] = now; + } else { + request['end_timestamp'] = this.sum (since, limit * duration * 1000); + } + } + const response = await this.publicGetGetTradingviewChartData (this.extend (request, params)); + // + // { + // jsonrpc: '2.0', + // result: { + // volume: [ 3.6680847969999992, 22.682721123, 3.011587939, 0 ], + // ticks: [ 1583916960000, 1583917020000, 1583917080000, 1583917140000 ], + // status: 'ok', + // open: [ 7834, 7839, 7833.5, 7833 ], + // low: [ 7834, 7833.5, 7832.5, 7833 ], + // high: [ 7839.5, 7839, 7833.5, 7833 ], + // cost: [ 28740, 177740, 23590, 0 ], + // close: [ 7839.5, 7833.5, 7833, 7833 ] + // }, + // usIn: 1583917166709801, + // usOut: 1583917166710175, + // usDiff: 374, + // testnet: false + // } + // + const result = this.safeValue (response, 'result', {}); + const ohlcvs = this.convertTradingViewToOHLCV (result, 'ticks', 'open', 'high', 'low', 'close', 'volume', true); + return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit); } parseTrade (trade, market = undefined) { @@ -44623,59 +47859,72 @@ module.exports = class deribit extends Exchange { // fetchTrades (public) // // { - // "tradeId":23197559, - // "instrument":"BTC-28JUN19", - // "timeStamp":1559643011379, - // "tradeSeq":1997200, - // "quantity":2, - // "amount":20.0, - // "price":8010.0, - // "direction":"sell", - // "tickDirection":2, - // "indexPrice":7969.01 + // 'trade_seq': 39201926, + // 'trade_id':' 64135724', + // 'timestamp': 1583174775400, + // 'tick_direction': 1, + // 'price': 8865.0, + // 'instrument_name': 'BTC-PERPETUAL', + // 'index_price': 8863.31, + // 'direction': 'buy', + // 'amount': 10.0 // } // - // fetchMyTrades (private) + // fetchMyTrades, fetchOrderTrades (private) // // { - // "quantity":54, - // "amount":540.0, - // "tradeId":23087297, - // "instrument":"BTC-PERPETUAL", - // "timeStamp":1559604178803, - // "tradeSeq":8265011, - // "price":8213.0, - // "side":"sell", - // "orderId":12373631800, - // "matchingId":0, - // "liquidity":"T", - // "fee":0.000049312, - // "feeCurrency":"BTC", - // "tickDirection":3, - // "indexPrice":8251.94, - // "selfTrade":false + // "trade_seq": 3, + // "trade_id": "ETH-34066", + // "timestamp": 1550219814585, + // "tick_direction": 1, + // "state": "open", + // "self_trade": false, + // "reduce_only": false, + // "price": 0.04, + // "post_only": false, + // "order_type": "limit", + // "order_id": "ETH-334607", + // "matching_id": null, + // "liquidity": "M", + // "iv": 56.83, + // "instrument_name": "ETH-22FEB19-120-C", + // "index_price": 121.37, + // "fee_currency": "ETH", + // "fee": 0.0011, + // "direction": "buy", + // "amount": 11 // } // - const id = this.safeString (trade, 'tradeId'); - const orderId = this.safeString (trade, 'orderId'); + const id = this.safeString (trade, 'trade_id'); let symbol = undefined; - if (market !== undefined) { + const marketId = this.safeString (trade, 'instrument_name'); + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; symbol = market['symbol']; } - const timestamp = this.safeInteger (trade, 'timeStamp'); - const side = this.safeString2 (trade, 'side', 'direction'); + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const timestamp = this.safeInteger (trade, 'timestamp'); + const side = this.safeString (trade, 'direction'); const price = this.safeFloat (trade, 'price'); - const amount = this.safeFloat (trade, 'quantity'); + const amount = this.safeFloat (trade, 'amount'); let cost = undefined; if (amount !== undefined) { if (price !== undefined) { cost = amount * price; } } + const liquidity = this.safeString (trade, 'liquidity'); + let takerOrMaker = undefined; + if (liquidity !== undefined) { + // M = maker, T = taker, MT = both + takerOrMaker = (liquidity === 'M') ? 'maker' : 'taker'; + } + const feeCost = this.safeFloat (trade, 'feeCost'); let fee = undefined; - const feeCost = this.safeFloat (trade, 'fee'); if (feeCost !== undefined) { - const feeCurrencyId = this.safeString (trade, 'feeCurrency'); + const feeCurrencyId = this.safeString (trade, 'fee_currency'); const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); fee = { 'cost': feeCost, @@ -44688,10 +47937,10 @@ module.exports = class deribit extends Exchange { 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'symbol': symbol, - 'order': orderId, - 'type': undefined, + 'order': this.safeString (trade, 'order_id'), + 'type': this.safeString (trade, 'order_type'), 'side': side, - 'takerOrMaker': undefined, + 'takerOrMaker': takerOrMaker, 'price': price, 'amount': amount, 'cost': cost, @@ -44703,54 +47952,102 @@ module.exports = class deribit extends Exchange { await this.loadMarkets (); const market = this.market (symbol); const request = { - 'instrument': market['id'], + 'instrument_name': market['id'], + 'include_old': true, }; - if (limit !== undefined) { - request['limit'] = limit; - } else { - request['limit'] = 10000; + const method = (since === undefined) ? 'publicGetGetLastTradesByInstrument' : 'publicGetGetLastTradesByInstrumentAndTime'; + if (since !== undefined) { + request['start_timestamp'] = since; } - const response = await this.publicGetGetlasttrades (this.extend (request, params)); + if (limit !== undefined) { + request['count'] = limit; // default 10 + } + const response = await this[method] (this.extend (request, params)); // // { - // "usOut":1559643108984527, - // "usIn":1559643108984470, - // "usDiff":57, - // "testnet":false, - // "success":true, - // "result": [ - // { - // "tradeId":23197559, - // "instrument":"BTC-28JUN19", - // "timeStamp":1559643011379, - // "tradeSeq":1997200, - // "quantity":2, - // "amount":20.0, - // "price":8010.0, - // "direction":"sell", - // "tickDirection":2, - // "indexPrice":7969.01 - // } - // ], - // "message":"" + // 'jsonrpc': '2.0', + // 'result': { + // 'trades': [ + // { + // 'trade_seq': 39201926, + // 'trade_id':' 64135724', + // 'timestamp': 1583174775400, + // 'tick_direction': 1, + // 'price': 8865.0, + // 'instrument_name': 'BTC-PERPETUAL', + // 'index_price': 8863.31, + // 'direction': 'buy', + // 'amount': 10.0 + // }, + // ], + // 'has_more': true, + // }, + // 'usIn': 1583779594843931, + // 'usOut': 1583779594844446, + // 'usDiff': 515, + // 'testnet': false // } // - const result = this.safeValue (response, 'result', []); - return this.parseTrades (result, market, since, limit); + const result = this.safeValue (response, 'result', {}); + const trades = this.safeValue (result, 'trades', []); + return this.parseTrades (trades, market, since, limit); } async fetchOrderBook (symbol, limit = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = { - 'instrument': market['id'], + 'instrument_name': market['id'], }; - const response = await this.publicGetGetorderbook (this.extend (request, params)); - const timestamp = this.safeInteger (response, 'usOut') / 1000; - const orderbook = this.parseOrderBook (response['result'], timestamp, 'bids', 'asks', 'price', 'quantity'); - return this.extend (orderbook, { - 'nonce': this.safeInteger (response, 'tstamp'), - }); + if (limit !== undefined) { + request['depth'] = limit; + } + const response = await this.publicGetGetOrderBook (this.extend (request, params)); + // + // { + // jsonrpc: '2.0', + // result: { + // timestamp: 1583781354740, + // stats: { volume: 61249.66735634, low: 7631.5, high: 8311.5 }, + // state: 'open', + // settlement_price: 7903.21, + // open_interest: 111536690, + // min_price: 7695.13, + // max_price: 7929.49, + // mark_price: 7813.06, + // last_price: 7814.5, + // instrument_name: 'BTC-PERPETUAL', + // index_price: 7810.12, + // funding_8h: 0.0000031, + // current_funding: 0, + // change_id: 17538025952, + // bids: [ + // [7814, 351820], + // [7813.5, 207490], + // [7813, 32160], + // ], + // best_bid_price: 7814, + // best_bid_amount: 351820, + // best_ask_price: 7814.5, + // best_ask_amount: 11880, + // asks: [ + // [7814.5, 11880], + // [7815, 18100], + // [7815.5, 2640], + // ], + // }, + // usIn: 1583781354745804, + // usOut: 1583781354745932, + // usDiff: 128, + // testnet: false + // } + // + const result = this.safeValue (response, 'result', {}); + const timestamp = this.safeInteger (result, 'timestamp'); + const nonce = this.safeInteger (result, 'change_id'); + const orderbook = this.parseOrderBook (result, timestamp); + orderbook['nonce'] = nonce; + return orderbook; } parseOrderStatus (status) { @@ -44758,48 +48055,51 @@ module.exports = class deribit extends Exchange { 'open': 'open', 'cancelled': 'canceled', 'filled': 'closed', + 'rejected': 'rejected', + // 'untriggered': 'open', }; return this.safeString (statuses, status, status); } parseOrder (order, market = undefined) { + // + // createOrder // // { - // "orderId": 5258039, // ID of the order - // "type": "limit", // not documented, but present in the actual response - // "instrument": "BTC-26MAY17", // instrument name (market id) - // "direction": "sell", // order direction, "buy" or "sell" - // "price": 1860, // float, USD for futures, BTC for options - // "label": "", // label set by the owner, up to 32 chars - // "quantity": 10, // quantity, in contracts ($10 per contract for futures, ฿1 — for options) - // "filledQuantity": 3, // filled quantity, in contracts ($10 per contract for futures, ฿1 — for options) - // "avgPrice": 1860, // average fill price of the order - // "commission": -0.000001613, // in BTC units - // "created": 1494491899308, // creation timestamp - // "state": "open", // open, cancelled, etc - // "postOnly": false // true for post-only orders only - // open orders -------------------------------------------------------- - // "lastUpdate": 1494491988754, // timestamp of the last order state change (before this cancelorder of course) - // closed orders ------------------------------------------------------ - // "tstamp": 1494492913288, // timestamp of the last order state change, documented, but may be missing in the actual response - // "modified": 1494492913289, // timestamp of the last db write operation, e.g. trade that doesn't change order status, documented, but may missing in the actual response - // "adv": false // advanced type (false, or "usd" or "implv") - // "trades": [], // not documented, injected from the outside of the parseOrder method into the order + // "time_in_force": "good_til_cancelled", + // "reduce_only": false, + // "profit_loss": 0, + // "price": "market_price", + // "post_only": false, + // "order_type": "market", + // "order_state": "filled", + // "order_id": "ETH-349249", + // "max_show": 40, + // "last_update_timestamp": 1550657341322, + // "label": "market0000234", + // "is_liquidation": false, + // "instrument_name": "ETH-PERPETUAL", + // "filled_amount": 40, + // "direction": "buy", + // "creation_timestamp": 1550657341322, + // "commission": 0.000139, + // "average_price": 143.81, + // "api": true, + // "amount": 40, + // "trades": [], // injected by createOrder // } // - const timestamp = this.safeInteger (order, 'created'); - const lastUpdate = this.safeInteger (order, 'lastUpdate'); - let lastTradeTimestamp = this.safeInteger2 (order, 'tstamp', 'modified'); - const id = this.safeString (order, 'orderId'); + const timestamp = this.safeInteger (order, 'creation_timestamp'); + const lastUpdate = this.safeInteger (order, 'last_update_timestamp'); + const id = this.safeString (order, 'order_id'); const price = this.safeFloat (order, 'price'); - const average = this.safeFloat (order, 'avgPrice'); - const amount = this.safeFloat (order, 'quantity'); - const filled = this.safeFloat (order, 'filledQuantity'); - if (lastTradeTimestamp === undefined) { - if (filled !== undefined) { - if (filled > 0) { - lastTradeTimestamp = lastUpdate; - } + const average = this.safeFloat (order, 'average_price'); + const amount = this.safeFloat (order, 'amount'); + const filled = this.safeFloat (order, 'filled_amount'); + let lastTradeTimestamp = undefined; + if (filled !== undefined) { + if (filled > 0) { + lastTradeTimestamp = lastUpdate; } } let remaining = undefined; @@ -44812,26 +48112,43 @@ module.exports = class deribit extends Exchange { cost = price * filled; } } - const status = this.parseOrderStatus (this.safeString (order, 'state')); - const side = this.safeStringLower (order, 'direction'); - let feeCost = this.safeFloat (order, 'commission'); - if (feeCost !== undefined) { - feeCost = Math.abs (feeCost); - } - const fee = { - 'cost': feeCost, - 'currency': 'BTC', - }; - const type = this.safeString (order, 'type'); - const marketId = this.safeString (order, 'instrument'); + const status = this.parseOrderStatus (this.safeString (order, 'order_state')); + const marketId = this.safeString (order, 'instrument_name'); let symbol = undefined; + let base = undefined; if (marketId in this.markets_by_id) { market = this.markets_by_id[marketId]; symbol = market['symbol']; + base = market['base']; + } + if (market !== undefined) { + if (symbol === undefined) { + symbol = market['symbol']; + } + if (base === undefined) { + base = market['base']; + } + } + const side = this.safeStringLower (order, 'direction'); + let feeCost = this.safeFloat (order, 'commission'); + let fee = undefined; + if (feeCost !== undefined) { + feeCost = Math.abs (feeCost); + fee = { + 'cost': feeCost, + 'currency': base, + }; + } + const type = this.safeString (order, 'order_type'); + // injected in createOrder + let trades = this.safeValue (order, 'trades'); + if (trades !== undefined) { + trades = this.parseTrades (trades, market); } return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -44846,169 +48163,561 @@ module.exports = class deribit extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, - 'trades': undefined, // todo: parse trades + 'trades': trades, }; } async fetchOrder (id, symbol = undefined, params = {}) { await this.loadMarkets (); const request = { - 'orderId': id, + 'order_id': id, }; - const response = await this.privateGetOrderstate (this.extend (request, params)); + const response = await this.privateGetGetOrderState (this.extend (request, params)); + // + // { + // "jsonrpc": "2.0", + // "id": 4316, + // "result": { + // "time_in_force": "good_til_cancelled", + // "reduce_only": false, + // "profit_loss": 0.051134, + // "price": 118.94, + // "post_only": false, + // "order_type": "limit", + // "order_state": "filled", + // "order_id": "ETH-331562", + // "max_show": 37, + // "last_update_timestamp": 1550219810944, + // "label": "", + // "is_liquidation": false, + // "instrument_name": "ETH-PERPETUAL", + // "filled_amount": 37, + // "direction": "sell", + // "creation_timestamp": 1550219749176, + // "commission": 0.000031, + // "average_price": 118.94, + // "api": false, + // "amount": 37 + // } + // } + // const result = this.safeValue (response, 'result'); - if (result === undefined) { - throw new OrderNotFound (this.id + ' fetchOrder() ' + this.json (response)); - } return this.parseOrder (result); } async createOrder (symbol, type, side, amount, price = undefined, params = {}) { await this.loadMarkets (); + const market = this.market (symbol); const request = { - 'instrument': this.marketId (symbol), - 'quantity': amount, - 'type': type, - // 'post_only': 'false' or 'true', https://github.com/ccxt/ccxt/issues/5159 + 'instrument_name': market['id'], + // for perpetual and futures the amount is in USD + // for options it is in corresponding cryptocurrency contracts, e.g., BTC or ETH + 'amount': this.amountToPrecision (symbol, amount), + 'type': type, // limit, stop_limit, market, stop_market, default is limit + // 'label': 'string', // user-defined label for the order (maximum 64 characters) + // 'price': this.priceToPrecision (symbol, 123.45), // only for limit and stop_limit orders + // 'time_in_force' : 'good_til_cancelled', // fill_or_kill, immediate_or_cancel + // 'max_show': 123.45, // max amount within an order to be shown to other customers, 0 for invisible order + // 'post_only': false, // if the new price would cause the order to be filled immediately (as taker), the price will be changed to be just below the spread. + // 'reject_post_only': false, // if true the order is put to order book unmodified or request is rejected + // 'reduce_only': false, // if true, the order is intended to only reduce a current position + // 'stop_price': false, // stop price, required for stop_limit orders + // 'trigger': 'index_price', // mark_price, last_price, required for stop_limit orders + // 'advanced': 'usd', // 'implv', advanced option order type, options only }; - if (price !== undefined) { - request['price'] = price; + let priceIsRequired = false; + let stopPriceIsRequired = false; + if (type === 'limit') { + priceIsRequired = true; + } else if (type === 'stop_limit') { + priceIsRequired = true; + stopPriceIsRequired = true; } - const method = 'privatePost' + this.capitalize (side); + if (priceIsRequired) { + if (price !== undefined) { + request['price'] = this.priceToPrecision (symbol, price); + } else { + throw new ArgumentsRequired (this.id + ' createOrder requires a price argument for a ' + type + ' order'); + } + } + if (stopPriceIsRequired) { + const stopPrice = this.safeFloat2 (params, 'stop_price', 'stopPrice'); + if (stopPrice === undefined) { + throw new ArgumentsRequired (this.id + ' createOrder requires a stop_price or stopPrice param for a ' + type + ' order'); + } else { + request['stop_price'] = this.priceToPrecision (symbol, stopPrice); + } + } + const method = 'privateGet' + this.capitalize (side); const response = await this[method] (this.extend (request, params)); - const order = this.safeValue (response['result'], 'order'); - if (order === undefined) { - return response; - } - return this.parseOrder (order); + // + // { + // "jsonrpc": "2.0", + // "id": 5275, + // "result": { + // "trades": [ + // { + // "trade_seq": 14151, + // "trade_id": "ETH-37435", + // "timestamp": 1550657341322, + // "tick_direction": 2, + // "state": "closed", + // "self_trade": false, + // "price": 143.81, + // "order_type": "market", + // "order_id": "ETH-349249", + // "matching_id": null, + // "liquidity": "T", + // "label": "market0000234", + // "instrument_name": "ETH-PERPETUAL", + // "index_price": 143.73, + // "fee_currency": "ETH", + // "fee": 0.000139, + // "direction": "buy", + // "amount": 40 + // } + // ], + // "order": { + // "time_in_force": "good_til_cancelled", + // "reduce_only": false, + // "profit_loss": 0, + // "price": "market_price", + // "post_only": false, + // "order_type": "market", + // "order_state": "filled", + // "order_id": "ETH-349249", + // "max_show": 40, + // "last_update_timestamp": 1550657341322, + // "label": "market0000234", + // "is_liquidation": false, + // "instrument_name": "ETH-PERPETUAL", + // "filled_amount": 40, + // "direction": "buy", + // "creation_timestamp": 1550657341322, + // "commission": 0.000139, + // "average_price": 143.81, + // "api": true, + // "amount": 40 + // } + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const order = this.safeValue (result, 'order'); + const trades = this.safeValue (result, 'trades', []); + order['trades'] = trades; + return this.parseOrder (order, market); } async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) { + if (amount === undefined) { + throw new ArgumentsRequired (this.id + ' editOrder requires an amount argument'); + } + if (price === undefined) { + throw new ArgumentsRequired (this.id + ' editOrder requires a price argument'); + } await this.loadMarkets (); const request = { - 'orderId': id, + 'order_id': id, + // for perpetual and futures the amount is in USD + // for options it is in corresponding cryptocurrency contracts, e.g., BTC or ETH + 'amount': this.amountToPrecision (symbol, amount), + 'price': this.priceToPrecision (symbol, price), // required + // 'post_only': false, // if the new price would cause the order to be filled immediately (as taker), the price will be changed to be just below the spread. + // 'reject_post_only': false, // if true the order is put to order book unmodified or request is rejected + // 'reduce_only': false, // if true, the order is intended to only reduce a current position + // 'stop_price': false, // stop price, required for stop_limit orders + // 'advanced': 'usd', // 'implv', advanced option order type, options only }; - if (amount !== undefined) { - request['quantity'] = amount; - } - if (price !== undefined) { - request['price'] = price; - } - const response = await this.privatePostEdit (this.extend (request, params)); - return this.parseOrder (response['result']['order']); + const response = await this.privateGetEdit (this.extend (request, params)); + const result = this.safeValue (response, 'result', {}); + const order = this.safeValue (result, 'order'); + const trades = this.safeValue (result, 'trades', []); + order['trades'] = trades; + return this.parseOrder (order); } async cancelOrder (id, symbol = undefined, params = {}) { await this.loadMarkets (); const request = { - 'orderId': id, + 'order_id': id, }; - const response = await this.privatePostCancel (this.extend (request, params)); - return this.parseOrder (response['result']['order']); + const response = await this.privateGetCancel (this.extend (request, params)); + const result = this.safeValue (response, 'result', {}); + return this.parseOrder (result); + } + + async cancelAllOrders (symbol = undefined, params = {}) { + await this.loadMarkets (); + const request = {}; + let method = undefined; + if (symbol === undefined) { + method = 'privateGetCancelAll'; + } else { + method = 'privateGetCancelAllByInstrument'; + const market = this.market (symbol); + request['instrument_name'] = market['id']; + } + const response = await this[method] (this.extend (request, params)); + return response; } async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchClosedOrders() requires a `symbol` argument'); - } await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'instrument': market['id'], - }; - const response = await this.privateGetGetopenorders (this.extend (request, params)); - return this.parseOrders (response['result'], market, since, limit); + const request = {}; + let market = undefined; + let method = undefined; + if (symbol === undefined) { + const code = this.codeFromOptions ('fetchOpenOrders'); + const currency = this.currency (code); + request['currency'] = currency['id']; + method = 'privateGetGetOpenOrdersByCurrency'; + } else { + market = this.market (symbol); + request['instrument_name'] = market['id']; + method = 'privateGetGetOpenOrdersByInstrument'; + } + const response = await this[method] (this.extend (request, params)); + const result = this.safeValue (response, 'result', []); + return this.parseOrders (result, market, since, limit); } async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchClosedOrders() requires a `symbol` argument'); - } await this.loadMarkets (); - const market = this.market (symbol); + const request = {}; + let market = undefined; + let method = undefined; + if (symbol === undefined) { + const code = this.codeFromOptions ('fetchClosedOrders'); + const currency = this.currency (code); + request['currency'] = currency['id']; + method = 'privateGetGetOrderHistoryByCurrency'; + } else { + market = this.market (symbol); + request['instrument_name'] = market['id']; + method = 'privateGetGetOrderHistoryByInstrument'; + } + const response = await this[method] (this.extend (request, params)); + const result = this.safeValue (response, 'result', []); + return this.parseOrders (result, market, since, limit); + } + + async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); const request = { - 'instrument': market['id'], + 'order_id': id, }; - const response = await this.privateGetOrderhistory (this.extend (request, params)); - return this.parseOrders (response['result'], market, since, limit); + const response = await this.privateGetGetUserTradesByOrder (this.extend (request, params)); + // + // { + // "jsonrpc": "2.0", + // "id": 9367, + // "result": { + // "trades": [ + // { + // "trade_seq": 3, + // "trade_id": "ETH-34066", + // "timestamp": 1550219814585, + // "tick_direction": 1, + // "state": "open", + // "self_trade": false, + // "reduce_only": false, + // "price": 0.04, + // "post_only": false, + // "order_type": "limit", + // "order_id": "ETH-334607", + // "matching_id": null, + // "liquidity": "M", + // "iv": 56.83, + // "instrument_name": "ETH-22FEB19-120-C", + // "index_price": 121.37, + // "fee_currency": "ETH", + // "fee": 0.0011, + // "direction": "buy", + // "amount": 11 + // }, + // ], + // "has_more": true + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const trades = this.safeValue (result, 'trades', []); + return this.parseTrades (trades, undefined, since, limit); } async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); - const market = this.market (symbol); const request = { - 'instrument': market['id'], + 'include_old': true, }; - if (limit !== undefined) { - request['count'] = limit; // default = 20 + let market = undefined; + let method = undefined; + if (symbol === undefined) { + const code = this.codeFromOptions ('fetchMyTrades'); + const currency = this.currency (code); + request['currency'] = currency['id']; + if (since === undefined) { + method = 'privateGetGetUserTradesByCurrency'; + } else { + method = 'privateGetGetUserTradesByCurrencyAndTime'; + request['start_timestamp'] = since; + } + } else { + market = this.market (symbol); + request['instrument_name'] = market['id']; + if (since === undefined) { + method = 'privateGetGetUserTradesByInstrument'; + } else { + method = 'privateGetGetUserTradesByInstrumentAndTime'; + request['start_timestamp'] = since; + } } - const response = await this.privateGetTradehistory (this.extend (request, params)); + if (limit !== undefined) { + request['count'] = limit; // default 10 + } + const response = await this[method] (this.extend (request, params)); // // { - // "usOut":1559611553394836, - // "usIn":1559611553394000, - // "usDiff":836, - // "testnet":false, - // "success":true, - // "result": [ - // { - // "quantity":54, - // "amount":540.0, - // "tradeId":23087297, - // "instrument":"BTC-PERPETUAL", - // "timeStamp":1559604178803, - // "tradeSeq":8265011, - // "price":8213.0, - // "side":"sell", - // "orderId":12373631800, - // "matchingId":0, - // "liquidity":"T", - // "fee":0.000049312, - // "feeCurrency":"BTC", - // "tickDirection":3, - // "indexPrice":8251.94, - // "selfTrade":false - // } - // ], - // "message":"", - // "has_more":true + // "jsonrpc": "2.0", + // "id": 9367, + // "result": { + // "trades": [ + // { + // "trade_seq": 3, + // "trade_id": "ETH-34066", + // "timestamp": 1550219814585, + // "tick_direction": 1, + // "state": "open", + // "self_trade": false, + // "reduce_only": false, + // "price": 0.04, + // "post_only": false, + // "order_type": "limit", + // "order_id": "ETH-334607", + // "matching_id": null, + // "liquidity": "M", + // "iv": 56.83, + // "instrument_name": "ETH-22FEB19-120-C", + // "index_price": 121.37, + // "fee_currency": "ETH", + // "fee": 0.0011, + // "direction": "buy", + // "amount": 11 + // }, + // ], + // "has_more": true + // } // } // - const trades = this.safeValue (response, 'result', []); + const result = this.safeValue (response, 'result', {}); + const trades = this.safeValue (result, 'trades', []); return this.parseTrades (trades, market, since, limit); } + async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { + if (code === undefined) { + throw new ArgumentsRequired (this.id + ' fetchDeposits() requires a currency code argument'); + } + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + }; + if (limit !== undefined) { + request['count'] = limit; + } + const response = await this.privateGetGetDeposits (this.extend (request, params)); + // + // { + // "jsonrpc": "2.0", + // "id": 5611, + // "result": { + // "count": 1, + // "data": [ + // { + // "address": "2N35qDKDY22zmJq9eSyiAerMD4enJ1xx6ax", + // "amount": 5, + // "currency": "BTC", + // "received_timestamp": 1549295017670, + // "state": "completed", + // "transaction_id": "230669110fdaf0a0dbcdc079b6b8b43d5af29cc73683835b9bc6b3406c065fda", + // "updated_timestamp": 1549295130159 + // } + // ] + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const data = this.safeValue (result, 'data', []); + return this.parseTransactions (data, currency, since, limit, params); + } + + async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { + if (code === undefined) { + throw new ArgumentsRequired (this.id + ' fetchWithdrawals() requires a currency code argument'); + } + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + }; + if (limit !== undefined) { + request['count'] = limit; + } + const response = await this.privateGetGetWithdrawals (this.extend (request, params)); + // + // { + // "jsonrpc": "2.0", + // "id": 2745, + // "result": { + // "count": 1, + // "data": [ + // { + // "address": "2NBqqD5GRJ8wHy1PYyCXTe9ke5226FhavBz", + // "amount": 0.5, + // "confirmed_timestamp": null, + // "created_timestamp": 1550571443070, + // "currency": "BTC", + // "fee": 0.0001, + // "id": 1, + // "priority": 0.15, + // "state": "unconfirmed", + // "transaction_id": null, + // "updated_timestamp": 1550571443070 + // } + // ] + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const data = this.safeValue (result, 'data', []); + return this.parseTransactions (data, currency, since, limit, params); + } + + parseTransactionStatus (status) { + const statuses = { + 'completed': 'ok', + 'unconfirmed': 'pending', + }; + return this.safeString (statuses, status, status); + } + + parseTransaction (transaction, currency = undefined) { + // + // fetchWithdrawals + // + // { + // "address": "2NBqqD5GRJ8wHy1PYyCXTe9ke5226FhavBz", + // "amount": 0.5, + // "confirmed_timestamp": null, + // "created_timestamp": 1550571443070, + // "currency": "BTC", + // "fee": 0.0001, + // "id": 1, + // "priority": 0.15, + // "state": "unconfirmed", + // "transaction_id": null, + // "updated_timestamp": 1550571443070 + // } + // + // fetchDeposits + // + // { + // "address": "2N35qDKDY22zmJq9eSyiAerMD4enJ1xx6ax", + // "amount": 5, + // "currency": "BTC", + // "received_timestamp": 1549295017670, + // "state": "completed", + // "transaction_id": "230669110fdaf0a0dbcdc079b6b8b43d5af29cc73683835b9bc6b3406c065fda", + // "updated_timestamp": 1549295130159 + // } + // + const currencyId = this.safeString (transaction, 'currency'); + const code = this.safeCurrencyCode (currencyId, currency); + const timestamp = this.safeInteger2 (transaction, 'created_timestamp', 'received_timestamp'); + const updated = this.safeInteger (transaction, 'updated_timestamp'); + const status = this.parseTransactionStatus (this.safeString (transaction, 'state')); + const address = this.safeString (transaction, 'address'); + const feeCost = this.safeFloat (transaction, 'fee'); + let type = 'deposit'; + let fee = undefined; + if (feeCost !== undefined) { + type = 'withdrawal'; + fee = { + 'cost': feeCost, + 'currency': code, + }; + } + return { + 'info': transaction, + 'id': this.safeString (transaction, 'id'), + 'txid': this.safeString (transaction, 'transaction_id'), + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'address': address, + 'addressTo': address, + 'addressFrom': undefined, + 'tag': undefined, + 'tagTo': undefined, + 'tagFrom': undefined, + 'type': type, + 'amount': this.safeFloat (transaction, 'amount'), + 'currency': code, + 'status': status, + 'updated': updated, + 'fee': fee, + }; + } + + async withdraw (code, amount, address, tag = undefined, params = {}) { + this.checkAddress (address); + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + 'address': address, // must be in the address book + 'amount': amount, + // 'priority': 'high', // low, mid, high, very_high, extreme_high, insane + // 'tfa': '123456', // if enabled + }; + if (this.twofa !== undefined) { + request['tfa'] = this.oath (); + } + const response = await this.privateGetWithdraw (this.extend (request, params)); + return { + 'info': response, + 'id': this.safeString (response, 'id'), + }; + } + nonce () { return this.milliseconds (); } sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - const query = '/' + 'api/' + this.version + '/' + api + '/' + path; - let url = this.urls['api'] + query; + let request = '/' + 'api/' + this.version + '/' + api + '/' + path; if (api === 'public') { if (Object.keys (params).length) { - url += '?' + this.urlencode (params); - } - } else { - this.checkRequiredCredentials (); - const nonce = this.nonce ().toString (); - let auth = '_=' + nonce + '&_ackey=' + this.apiKey + '&_acsec=' + this.secret + '&_action=' + query; - if (Object.keys (params).length) { - params = this.keysort (params); - auth += '&' + this.urlencode (params); - } - const hash = this.hash (this.encode (auth), 'sha256', 'base64'); - const signature = this.apiKey + '.' + nonce + '.' + this.decode (hash); - headers = { - 'x-deribit-sig': signature, - }; - if (method !== 'GET') { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; - body = this.urlencode (params); - } else if (Object.keys (params).length) { - url += '?' + this.urlencode (params); + request += '?' + this.urlencode (params); } } + if (api === 'private') { + this.checkRequiredCredentials (); + const nonce = this.nonce ().toString (); + const timestamp = this.milliseconds ().toString (); + const requestBody = ''; + if (Object.keys (params).length) { + request += '?' + this.urlencode (params); + } + const requestData = method + "\n" + request + "\n" + requestBody + "\n"; // eslint-disable-line quotes + const auth = timestamp + "\n" + nonce + "\n" + requestData; // eslint-disable-line quotes + const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256'); + headers = { + 'Authorization': 'deri-hmac-sha256 id=' + this.apiKey + ',ts=' + timestamp + ',sig=' + signature + ',' + 'nonce=' + nonce, + }; + } + const url = this.urls['api'] + request; return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } @@ -45017,18 +48726,30 @@ module.exports = class deribit extends Exchange { return; // fallback to default error handler } // - // {"usOut":1535877098645376,"usIn":1535877098643364,"usDiff":2012,"testnet":false,"success":false,"message":"order_not_found","error":10004} + // { + // jsonrpc: '2.0', + // error: { + // message: 'Invalid params', + // data: { reason: 'invalid currency', param: 'currency' }, + // code: -32602 + // }, + // testnet: false, + // usIn: 1583763842150374, + // usOut: 1583763842150410, + // usDiff: 36 + // } // - const error = this.safeString (response, 'error'); - if ((error !== undefined) && (error !== '0')) { + const error = this.safeValue (response, 'error'); + if (error !== undefined) { + const errorCode = this.safeString (error, 'code'); const feedback = this.id + ' ' + body; - this.throwExactlyMatchedException (this.exceptions, error, feedback); + this.throwExactlyMatchedException (this.exceptions, errorCode, feedback); throw new ExchangeError (feedback); // unknown message } } }; -},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],79:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],78:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -45074,7 +48795,7 @@ module.exports = class digifinex extends Exchange { 'doc': [ 'https://docs.digifinex.vip', ], - 'fees': 'https://digifinex.zendesk.com/hc/en-us/articles/360000328482-Fee-Structure-on-DigiFinex', + 'fees': 'https://digifinex.zendesk.com/hc/en-us/articles/360000328422-Fee-Structure-on-DigiFinex', 'referral': 'https://www.digifinex.vip/en-ww/from/DhOzBg/3798****5114', }, 'api': { @@ -45131,6 +48852,14 @@ module.exports = class digifinex extends Exchange { ], }, }, + 'fees': { + 'trading': { + 'tierBased': false, + 'percentage': true, + 'maker': 0.002, + 'taker': 0.002, + }, + }, 'exceptions': { 'exact': { '10001': [ BadRequest, "Wrong request method, please check it's a GET ot POST request" ], @@ -45167,6 +48896,9 @@ module.exports = class digifinex extends Exchange { 'defaultType': 'spot', 'types': [ 'spot', 'margin', 'otc' ], }, + 'commonCurrencies': { + 'BHT': 'Black House Test', + }, }); } @@ -45869,6 +49601,7 @@ module.exports = class digifinex extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -45883,6 +49616,7 @@ module.exports = class digifinex extends Exchange { 'average': average, 'status': status, 'fee': undefined, + 'trades': undefined, }; } @@ -46194,7 +49928,7 @@ module.exports = class digifinex extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],80:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],79:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -46229,7 +49963,7 @@ module.exports = class dsx extends Exchange { 'withdraw': true, }, 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/27990275-1413158a-645a-11e7-931c-94717f7510e3.jpg', + 'logo': 'https://user-images.githubusercontent.com/51840849/76909626-cb2bb100-68bc-11ea-99e0-28ba54f04792.jpg', 'api': { 'public': 'https://dsx.uk/mapi', // market data 'private': 'https://dsx.uk/tapi', // trading @@ -46911,6 +50645,9 @@ module.exports = class dsx extends Exchange { 'filled': filled, 'fee': undefined, // 'trades': this.parseTrades (order['trades'], market), + 'clientOrderId': undefined, + 'average': undefined, + 'trades': undefined, }; } @@ -47022,6 +50759,7 @@ module.exports = class dsx extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -47036,6 +50774,7 @@ module.exports = class dsx extends Exchange { 'status': status, 'fee': fee, 'trades': trades, + 'average': undefined, }; } @@ -47461,7 +51200,7 @@ module.exports = class dsx extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],81:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],80:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -47567,159 +51306,185 @@ module.exports = class exmo extends Exchange { 'error': '', 'data': { 'limits': [ - { 'pair': 'BTC/USD', 'min_q': '0.001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'BTC/EUR', 'min_q': '0.001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'BTC/RUB', 'min_q': '0.001', 'max_q': '1000', 'min_p': '1', 'max_p': '2000000', 'min_a': '10', 'max_a': '50000000' }, - { 'pair': 'BTC/UAH', 'min_q': '0.001', 'max_q': '1000', 'min_p': '1', 'max_p': '1500000', 'min_a': '10', 'max_a': '15000000' }, - { 'pair': 'BTC/PLN', 'min_q': '0.001', 'max_q': '1000', 'min_p': '0.001', 'max_p': '90000', 'min_a': '1', 'max_a': '2000000' }, - { 'pair': 'BTC/TRY', 'min_q': '0.001', 'max_q': '1000', 'min_p': '1', 'max_p': '800000', 'min_a': '40', 'max_a': '6000000' }, - { 'pair': 'ROOBEE/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.0001', 'max_a': '10' }, - { 'pair': 'ROOBEE/ETH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'USDC/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'USDC/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '1000' }, - { 'pair': 'USDC/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'USDC/USDT', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'ETZ/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '10' }, - { 'pair': 'ETZ/ETH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'ETZ/USDT', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '1000' }, - { 'pair': 'PTI/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' }, - { 'pair': 'PTI/USDT', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' }, - { 'pair': 'PTI/EOS', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '5000', 'min_a': '0.01', 'max_a': '20000' }, - { 'pair': 'ATMCASH/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' }, - { 'pair': 'TRX/UAH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, - { 'pair': 'ETH/TRY', 'min_q': '0.01', 'max_q': '5000', 'min_p': '0.1', 'max_p': '80000', 'min_a': '10', 'max_a': '6000000' }, - { 'pair': 'XRP/TRY', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '6000000' }, - { 'pair': 'XLM/TRY', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '6000000' }, - { 'pair': 'MNC/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' }, - { 'pair': 'MNC/ETH', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '1000' }, - { 'pair': 'MNC/USD', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' }, - { 'pair': 'DAI/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'DAI/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '5000' }, - { 'pair': 'DAI/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'DAI/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '0.5', 'max_a': '30000000' }, - { 'pair': 'MKR/BTC', 'min_q': '0.001', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.000001', 'max_a': '100' }, - { 'pair': 'MKR/DAI', 'min_q': '0.001', 'max_q': '1000', 'min_p': '0.5', 'max_p': '500000', 'min_a': '0.005', 'max_a': '500000' }, - { 'pair': 'QTUM/BTC', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'QTUM/ETH', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' }, - { 'pair': 'QTUM/USD', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '10000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'HB/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' }, - { 'pair': 'SMART/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'SMART/USD', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'SMART/EUR', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'SMART/RUB', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '10', 'max_a': '50000000' }, - { 'pair': 'XEM/BTC', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00015', 'max_a': '100' }, - { 'pair': 'XEM/USD', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'XEM/EUR', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'GUSD/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' }, - { 'pair': 'GUSD/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'GUSD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' }, - { 'pair': 'LSK/BTC', 'min_q': '1', 'max_q': '200000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' }, - { 'pair': 'LSK/USD', 'min_q': '1', 'max_q': '200000', 'min_p': '0.1', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'LSK/RUB', 'min_q': '1', 'max_q': '200000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '50000000' }, - { 'pair': 'NEO/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'NEO/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'NEO/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1500000', 'min_a': '50', 'max_a': '50000000' }, - { 'pair': 'ADA/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'ADA/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'ADA/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000' }, - { 'pair': 'ZRX/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'ZRX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, - { 'pair': 'GNT/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'GNT/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, - { 'pair': 'TRX/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'TRX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'TRX/RUB', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, - { 'pair': 'GAS/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'GAS/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'INK/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'INK/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000' }, - { 'pair': 'INK/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'MNX/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'MNX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, - { 'pair': 'MNX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, - { 'pair': 'OMG/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'OMG/ETH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, - { 'pair': 'OMG/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, - { 'pair': 'XLM/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'XLM/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'XLM/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, - { 'pair': 'EOS/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'EOS/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, - { 'pair': 'BTG/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'BTG/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'DXT/BTC', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'DXT/USD', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'BTCZ/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.1', 'max_a': '100' }, - { 'pair': 'BCH/BTC', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '5', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'BCH/USD', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '30000', 'min_a': '0.0001', 'max_a': '500000' }, - { 'pair': 'BCH/RUB', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '2000000', 'min_a': '0.0001', 'max_a': '50000000' }, - { 'pair': 'BCH/ETH', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.0000001', 'max_p': '200', 'min_a': '0.0001', 'max_a': '5000' }, - { 'pair': 'DASH/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'DASH/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'DASH/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, + { 'pair': 'EXM/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, + { 'pair': 'EXM/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' }, + { 'pair': 'BTC/USD', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'BTC/KZT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1000', 'max_p': '12000000', 'min_a': '1000', 'max_a': '100000000' }, + { 'pair': 'ETH/KZT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '4', 'max_p': '40000000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'USDT/KZT', 'min_q': '1', 'max_q': '500000', 'min_p': '200', 'max_p': '4000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'ONT/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '15000000' }, + { 'pair': 'ONT/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' }, + { 'pair': 'ONT/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '6000000' }, + { 'pair': 'ONT/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '250000' }, + { 'pair': 'ONG/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '15000000' }, + { 'pair': 'ONG/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' }, + { 'pair': 'ONG/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '250000' }, + { 'pair': 'ONG/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '6000000' }, + { 'pair': 'CRON/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'CRON/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' }, + { 'pair': 'CRON/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, + { 'pair': 'CRON/EXM', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, + { 'pair': 'BTC/RUB', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '2000000', 'min_a': '10', 'max_a': '50000000' }, + { 'pair': 'BTC/EUR', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'BTC/UAH', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '15000000', 'min_a': '10', 'max_a': '15000000' }, + { 'pair': 'BTC/PLN', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '20000000', 'min_a': '50', 'max_a': '2000000' }, + { 'pair': 'BTC/TRY', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '800000', 'min_a': '40', 'max_a': '6000000' }, + { 'pair': 'BTC/USDT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.01', 'max_p': '30000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'ETH/BTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'ETH/LTC', 'min_q': '0.01', 'max_q': '5000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '100000' }, - { 'pair': 'ETH/USD', 'min_q': '0.01', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'ETH/EUR', 'min_q': '0.01', 'max_q': '5000', 'min_p': '0.001', 'max_p': '10000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'ETH/RUB', 'min_q': '0.01', 'max_q': '5000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '1', 'max_a': '50000000' }, - { 'pair': 'ETH/UAH', 'min_q': '0.01', 'max_q': '5000', 'min_p': '0.01', 'max_p': '1000000', 'min_a': '90', 'max_a': '15000000' }, - { 'pair': 'ETH/PLN', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.001', 'max_p': '8000', 'min_a': '1', 'max_a': '2000000' }, - { 'pair': 'ETC/BTC', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '0.5', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'ETC/USD', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'ETC/RUB', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '50000000' }, - { 'pair': 'LTC/BTC', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'LTC/USD', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'LTC/EUR', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'LTC/RUB', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, - { 'pair': 'ZEC/BTC', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'ZEC/USD', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'ZEC/EUR', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'ZEC/RUB', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'ETH/USD', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'ETH/RUB', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, { 'pair': 'XRP/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, { 'pair': 'XRP/USD', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, { 'pair': 'XRP/RUB', 'min_q': '1', 'max_q': '100000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '50000000' }, - { 'pair': 'XMR/BTC', 'min_q': '0.03', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'XMR/USD', 'min_q': '0.03', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'XMR/EUR', 'min_q': '0.03', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'BTC/USDT', 'min_q': '0.001', 'max_q': '1000', 'min_p': '0.01', 'max_p': '30000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'ETH/USDT', 'min_q': '0.01', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'USDT/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'USDT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' }, - { 'pair': 'USD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' }, - { 'pair': 'DOGE/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'WAVES/BTC', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'WAVES/RUB', 'min_q': '0.5', 'max_q': '10000', 'min_p': '1', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' }, - { 'pair': 'KICK/BTC', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'KICK/ETH', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' }, - { 'pair': 'KICK/USDT', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, - { 'pair': 'EOS/EUR', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'ADA/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ADA/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000' }, + { 'pair': 'ADA/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'BCH/USD', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '30000', 'min_a': '0.0001', 'max_a': '500000' }, + { 'pair': 'BCH/RUB', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '2000000', 'min_a': '0.0001', 'max_a': '50000000' }, { 'pair': 'BCH/EUR', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'XRP/EUR', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, - { 'pair': 'XRP/UAH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '15000000' }, - { 'pair': 'XEM/UAH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' }, - { 'pair': 'BCH/USDT', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'DASH/USDT', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'BCH/UAH', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.1', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' }, - { 'pair': 'XRP/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, - { 'pair': 'USDT/UAH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '1', 'max_p': '3000', 'min_a': '2', 'max_a': '15000000' }, - { 'pair': 'USDT/EUR', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'ZRX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'BCH/BTC', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '5', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'BCH/ETH', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.0000001', 'max_p': '200', 'min_a': '0.0001', 'max_a': '5000' }, + { 'pair': 'BCH/USDT', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'BTCZ/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'BTG/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'BTG/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'BTG/ETH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.01', 'max_a': '5000' }, - { 'pair': 'WAVES/USD', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.001', 'max_p': '3500', 'min_a': '0.5', 'max_a': '500000' }, - { 'pair': 'DOGE/USD', 'min_q': '100', 'max_q': '1000000000', 'min_p': '0.0000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'XRP/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' }, - { 'pair': 'DASH/UAH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '200000', 'min_a': '10', 'max_a': '15000000' }, - { 'pair': 'XMR/ETH', 'min_q': '0.03', 'max_q': '1000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' }, - { 'pair': 'WAVES/ETH', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.00001', 'max_p': '30', 'min_a': '0.0035', 'max_a': '3500' }, - { 'pair': 'DCR/BTC', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'DCR/RUB', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '3000000' }, - { 'pair': 'DCR/UAH', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.25', 'max_a': '1000000' }, - { 'pair': 'ZAG/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'EXM/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0000001', 'max_a': '100' }, - { 'pair': 'VLX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'BTT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, { 'pair': 'BTT/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' }, { 'pair': 'BTT/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' }, + { 'pair': 'BTT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'DAI/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'DAI/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '0.5', 'max_a': '30000000' }, + { 'pair': 'DAI/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'DAI/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '5000' }, + { 'pair': 'DASH/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'DASH/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, + { 'pair': 'DASH/UAH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '200000', 'min_a': '10', 'max_a': '15000000' }, + { 'pair': 'DASH/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'DASH/USDT', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'DCR/RUB', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '3000000' }, + { 'pair': 'DCR/UAH', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.25', 'max_a': '1000000' }, + { 'pair': 'DCR/BTC', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'DOGE/USD', 'min_q': '100', 'max_q': '1000000000', 'min_p': '0.0000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'DOGE/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'DXT/USD', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'DXT/BTC', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'EOS/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'EOS/EUR', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'EOS/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ETC/USD', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'ETC/RUB', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '50000000' }, + { 'pair': 'ETC/BTC', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '0.5', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ETH/EUR', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'ETH/UAH', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '1000000', 'min_a': '90', 'max_a': '15000000' }, + { 'pair': 'ETH/PLN', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '2000000' }, + { 'pair': 'ETH/TRY', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.1', 'max_p': '80000', 'min_a': '10', 'max_a': '6000000' }, + { 'pair': 'ETH/USDT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'ETH/LTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '100000', 'min_a': '0.05', 'max_a': '100000' }, + { 'pair': 'ETZ/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '10' }, + { 'pair': 'ETZ/ETH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ETZ/USDT', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '1000' }, + { 'pair': 'GAS/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'GAS/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'GNT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'GNT/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, + { 'pair': 'GUSD/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'GUSD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' }, + { 'pair': 'GUSD/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' }, + { 'pair': 'HP/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'HB/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' }, + { 'pair': 'INK/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'INK/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'INK/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000' }, + { 'pair': 'KICK/RUB', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' }, + { 'pair': 'KICK/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, + { 'pair': 'KICK/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'KICK/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' }, + { 'pair': 'LSK/USD', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.1', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'LSK/RUB', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '50000000' }, + { 'pair': 'LSK/BTC', 'min_q': '1', 'max_q': '200000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' }, + { 'pair': 'LTC/USD', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'LTC/RUB', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, + { 'pair': 'LTC/EUR', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'LTC/UAH', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '5', 'max_a': '18000000' }, + { 'pair': 'LTC/BTC', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'MKR/BTC', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.000001', 'max_a': '100' }, + { 'pair': 'MKR/DAI', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.5', 'max_p': '500000', 'min_a': '0.005', 'max_a': '500000' }, + { 'pair': 'MNC/USD', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' }, + { 'pair': 'MNC/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' }, + { 'pair': 'MNC/ETH', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '1000' }, + { 'pair': 'MNX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'MNX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'MNX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, + { 'pair': 'NEO/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'NEO/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1500000', 'min_a': '50', 'max_a': '50000000' }, + { 'pair': 'NEO/BTC', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'OMG/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'OMG/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'OMG/ETH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, + { 'pair': 'PTI/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '600000', 'min_a': '10', 'max_a': '600000' }, + { 'pair': 'PTI/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' }, + { 'pair': 'PTI/EOS', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '5000', 'min_a': '0.01', 'max_a': '20000' }, + { 'pair': 'PTI/USDT', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' }, + { 'pair': 'QTUM/USD', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '10000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'QTUM/BTC', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'QTUM/ETH', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' }, + { 'pair': 'ROOBEE/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'SMART/USD', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'SMART/RUB', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '100000', 'min_a': '10', 'max_a': '50000000' }, + { 'pair': 'SMART/EUR', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'SMART/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'TRX/USD', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'TRX/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'TRX/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'TRX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'USDC/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'USDC/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'USDC/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '1000' }, + { 'pair': 'USDC/USDT', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'USDT/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'USDT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' }, + { 'pair': 'USDT/EUR', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'USDT/UAH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '1', 'max_p': '3000', 'min_a': '2', 'max_a': '15000000' }, + { 'pair': 'VLX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'WAVES/USD', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.001', 'max_p': '3500', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'WAVES/RUB', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' }, + { 'pair': 'WAVES/BTC', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'WAVES/ETH', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.00001', 'max_p': '30', 'min_a': '0.0035', 'max_a': '3500' }, + { 'pair': 'XEM/USD', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'XEM/EUR', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'XEM/UAH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' }, + { 'pair': 'XEM/BTC', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00015', 'max_a': '100' }, + { 'pair': 'XLM/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'XLM/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'XLM/TRY', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '6000000' }, + { 'pair': 'XLM/BTC', 'min_q': '1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'XMR/USD', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'XMR/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '600000', 'min_a': '10', 'max_a': '16000000' }, + { 'pair': 'XMR/EUR', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'XMR/UAH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '300000', 'min_a': '5', 'max_a': '16000000' }, + { 'pair': 'XMR/BTC', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'XMR/ETH', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' }, + { 'pair': 'XRP/EUR', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, + { 'pair': 'XRP/TRY', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '6000000' }, + { 'pair': 'XRP/UAH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '15000000' }, + { 'pair': 'XRP/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, + { 'pair': 'XRP/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' }, + { 'pair': 'XTZ/USD', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '100000' }, + { 'pair': 'XTZ/RUB', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'XTZ/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' }, + { 'pair': 'XTZ/ETH', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '1000' }, + { 'pair': 'ZEC/USD', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'ZEC/RUB', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'ZEC/EUR', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'ZEC/BTC', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.00001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ZRX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'ZRX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ZRX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, + { 'pair': 'ZAG/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'USD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' }, + { 'pair': 'EXM/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0000001', 'max_a': '1' }, + { 'pair': 'ATMCASH/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' }, ], 'fees': [ { @@ -47772,75 +51537,79 @@ module.exports = class exmo extends Exchange { { 'prov': 'ZAG', 'dep': '0%', 'wd': '0%' }, { 'prov': 'BTT', 'dep': '0%', 'wd': '100 BTT' }, { 'prov': 'VLX', 'dep': '0%', 'wd': '1 VLX' }, + { 'prov': 'CRON', 'dep': '0%', 'wd': '5 CRON' }, + { 'prov': 'ONT', 'dep': '0%', 'wd': '1 ONT' }, + { 'prov': 'ONG', 'dep': '0%', 'wd': '5 ONG' }, ], }, { 'group': 'usd', 'title': 'USD', 'items': [ - { 'prov': 'Payeer', 'dep': '3.95%', 'wd': '-' }, { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, - { 'prov': 'Perfect Money', 'dep': '-', 'wd': '0.5%' }, - { 'prov': 'AdvCash', 'dep': '3.45%', 'wd': '2.95%' }, + { 'prov': 'Payeer', 'dep': '3.95%', 'wd': '-' }, + { 'prov': 'AdvCash', 'dep': '0%', 'wd': '3.99%' }, + { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 0.5 USD', 'wd': '-' }, { 'prov': 'Visa', 'dep': '3.45%', 'wd': '-' }, - { 'prov': 'CryptoCapital', 'dep': '-', 'wd': '0.45%' }, - { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5%', 'wd': '-' }, ], }, { 'group': 'eur', 'title': 'EUR', 'items': [ - { 'prov': 'Visa', 'dep': '3.45%', 'wd': '-' }, - { 'prov': 'CryptoCapital', 'dep': '-', 'wd': '0.45%' }, - { 'prov': 'AdvCash', 'dep': '0.45%', 'wd': '-' }, - { 'prov': 'Wire Transfer', 'dep': '6.95 EUR', 'wd': '-' }, - { 'prov': 'SEPA', 'dep': '6.95 EUR', 'wd': '-' }, - { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5%', 'wd': '-' }, - { 'prov': 'Payeer', 'dep': '3.95%', 'wd': '-' }, { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, + { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 0.5 EUR', 'wd': '-' }, + { 'prov': 'Visa', 'dep': '2.95%', 'wd': '-' }, + { 'prov': 'SEPA', 'dep': '10 EUR', 'wd': '50 EUR' }, ], }, { 'group': 'rub', 'title': 'RUB', 'items': [ - { 'prov': 'Yandex Money', 'dep': '2.95%', 'wd': '1.95%' }, - { 'prov': 'Payeer', 'dep': '3.95%', 'wd': '-' }, - { 'prov': 'AdvCash', 'dep': '3.95%', 'wd': '0.95%' }, - { 'prov': 'Qiwi', 'dep': '3.95%', 'wd': '2.95%' }, - { 'prov': 'Visa/MasterCard', 'dep': '3.95%', 'wd': '4.95% + 60 RUB' }, - { 'prov': 'WebMoney', 'dep': '-', 'wd': '3.5%' }, + { 'prov': 'Payeer', 'dep': '2.49%', 'wd': '-' }, { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, + { 'prov': 'Qiwi', 'dep': '0.99%', 'wd': '2%' }, + { 'prov': 'Yandex Money', 'dep': '1.95%', 'wd': '-' }, + { 'prov': 'Enfins', 'dep': '0%', 'wd': '1.49%' }, + { 'prov': 'AdvCash', 'dep': '0%', 'wd': '2.49%' }, + { 'prov': 'Visa/MasterCard', 'dep': '1.99%', 'wd': '4.49% + 60 RUB' }, ], }, { 'group': 'pln', 'title': 'PLN', 'items': [ - { 'prov': 'CryptoCapital', 'dep': '-', 'wd': '0.45%' }, - { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5%', 'wd': '-' }, { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, + { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 1 PLN', 'wd': '-' }, ], }, { 'group': 'try', 'title': 'TRY', 'items': [ - { 'prov': 'QR ile yatırma', 'dep': '5.95%', 'wd': '-' }, - { 'prov': 'Visa', 'dep': '3.45%', 'wd': '-' }, { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, + { 'prov': 'Visa', 'dep': '3.05%', 'wd': '-' }, + { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 2 TRY', 'wd': '-' }, ], }, { 'group': 'uah', 'title': 'UAH', 'items': [ - { 'prov': 'Terminal', 'dep': '2.6%', 'wd': '-' }, { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, - { 'prov': 'AdvCash', 'dep': '-', 'wd': '2.95%' }, - { 'prov': 'Visa/MasterCard', 'dep': '2.6%', 'wd': '3.95% + 20 UAH' }, + { 'prov': 'Terminal', 'dep': '2.6%', 'wd': '-' }, { 'prov': 'Enfins', 'dep': '0%', 'wd': '1.95%' }, + { 'prov': 'Visa/MasterCard', 'dep': '1% + 5 UAH', 'wd': '2.99%' }, + ], + }, + { + 'group': 'kzt', + 'title': 'KZT', + 'items': [ + { 'prov': 'Visa/MasterCard RoyalPay', 'dep': '-', 'wd': '2.99% + 450 KZT' }, + { 'prov': 'Visa/MasterCard', 'dep': '3.5%', 'wd': '-' }, + { 'prov': 'AdvCash', 'dep': '0%', 'wd': '1.49%' }, ], }, ], @@ -47854,6 +51623,7 @@ module.exports = class exmo extends Exchange { '40015': ExchangeError, // API function do not exist '40016': OnMaintenance, // {"result":false,"error":"Error 40016: Maintenance work in progress"} '40017': AuthenticationError, // Wrong API Key + '40034': RateLimitExceeded, // {"result":false,"error":"Error 40034: Access is denied, rate limit is exceeded"} '50052': InsufficientFunds, '50054': InsufficientFunds, '50304': OrderNotFound, // "Order was not found '123456789'" (fetching order trades for an order that does not have trades yet) @@ -48333,6 +52103,8 @@ module.exports = class exmo extends Exchange { 'filled': 0.0, 'fee': undefined, 'trades': undefined, + 'clientOrderId': undefined, + 'average': undefined, }; this.orders[id] = order; return order; @@ -48600,6 +52372,7 @@ module.exports = class exmo extends Exchange { }; return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': lastTradeTimestamp, @@ -48876,7 +52649,7 @@ module.exports = class exmo extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],82:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],81:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -49151,6 +52924,20 @@ module.exports = class exx extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "fees": 0, + // "total_amount": 1, + // "trade_amount": 0, + // "price": 30, + // "currency": “eth_hsr", + // "id": "13878", + // "trade_money": 0, + // "type": "buy", + // "trade_date": 1509728897772, + // "status": 0 + // } + // const symbol = market['symbol']; const timestamp = parseInt (order['trade_date']); const price = this.safeFloat (order, 'price'); @@ -49175,6 +52962,7 @@ module.exports = class exx extends Exchange { } return { 'id': this.safeString (order, 'id'), + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -49190,6 +52978,7 @@ module.exports = class exx extends Exchange { 'trades': undefined, 'fee': fee, 'info': order, + 'average': undefined, }; } @@ -49313,7 +53102,7 @@ module.exports = class exx extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],83:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],82:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -49830,6 +53619,22 @@ module.exports = class fcoin extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "id": "string", + // "symbol": "string", + // "type": "limit", + // "side": "buy", + // "price": "string", + // "amount": "string", + // "state": "submitted", + // "executed_value": "string", + // "fill_fees": "string", + // "filled_amount": "string", + // "created_at": 0, + // "source": "web" + // } + // const id = this.safeString (order, 'id'); const side = this.safeString (order, 'side'); const status = this.parseOrderStatus (this.safeString (order, 'state')); @@ -49878,6 +53683,7 @@ module.exports = class fcoin extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -50030,7 +53836,7 @@ module.exports = class fcoin extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],84:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],83:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -50056,7 +53862,7 @@ module.exports = class fcoinjp extends fcoin { } }; -},{"./fcoin.js":83}],85:[function(require,module,exports){ +},{"./fcoin.js":82}],84:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -50075,7 +53881,7 @@ module.exports = class flowbtc extends Exchange { 'version': 'v1', 'rateLimit': 1000, 'has': { - 'CORS': true, + 'CORS': false, }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/28162465-cd815d4c-67cf-11e7-8e57-438bea0523a2.jpg', @@ -50167,6 +53973,7 @@ module.exports = class flowbtc extends Exchange { }, }, 'info': market, + 'active': undefined, }; } return result; @@ -50256,6 +54063,8 @@ module.exports = class flowbtc extends Exchange { 'price': price, 'amount': amount, 'cost': cost, + 'takerOrMaker': undefined, + 'fee': undefined, }; } @@ -50332,7 +54141,7 @@ module.exports = class flowbtc extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],86:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],85:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -50591,7 +54400,7 @@ module.exports = class foxbit extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],87:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],86:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -50610,10 +54419,14 @@ module.exports = class ftx extends Exchange { 'countries': [ 'HK' ], 'rateLimit': 100, 'certified': true, + 'pro': true, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/67149189-df896480-f2b0-11e9-8816-41593e17f9ec.jpg', 'www': 'https://ftx.com', - 'api': 'https://ftx.com', + 'api': { + 'public': 'https://ftx.com', + 'private': 'https://ftx.com', + }, 'doc': 'https://github.com/ftexchange/ftx', 'fees': 'https://ftexchange.zendesk.com/hc/en-us/articles/360024479432-Fees', 'referral': 'https://ftx.com/#a=1623029', @@ -50753,6 +54566,19 @@ module.exports = class ftx extends Exchange { }, }, 'precisionMode': TICK_SIZE, + 'options': { + // support for canceling conditional orders + // https://github.com/ccxt/ccxt/issues/6669 + 'cancelOrder': { + 'method': 'privateDeleteOrdersOrderId', // privateDeleteConditionalOrdersOrderId + }, + 'fetchOpenOrders': { + 'method': 'privateGetOrders', // privateGetConditionalOrders + }, + 'fetchOrders': { + 'method': 'privateGetOrdersHistory', // privateGetConditionalOrdersHistory + }, + }, }); } @@ -50928,14 +54754,16 @@ module.exports = class ftx extends Exchange { } else { const base = this.safeCurrencyCode (this.safeString (ticker, 'baseCurrency')); const quote = this.safeCurrencyCode (this.safeString (ticker, 'quoteCurrency')); - symbol = base + '/' + quote; + if ((base !== undefined) && (quote !== undefined)) { + symbol = base + '/' + quote; + } } } if ((symbol === undefined) && (market !== undefined)) { symbol = market['symbol']; } const last = this.safeFloat (ticker, 'last'); - const timestamp = this.milliseconds (); + const timestamp = this.safeTimestamp (ticker, 'time', this.milliseconds ()); return { 'symbol': symbol, 'timestamp': timestamp, @@ -50943,9 +54771,9 @@ module.exports = class ftx extends Exchange { 'high': this.safeFloat (ticker, 'high'), 'low': this.safeFloat (ticker, 'low'), 'bid': this.safeFloat (ticker, 'bid'), - 'bidVolume': undefined, + 'bidVolume': this.safeFloat (ticker, 'bidSize'), 'ask': this.safeFloat (ticker, 'ask'), - 'askVolume': undefined, + 'askVolume': this.safeFloat (ticker, 'askSize'), 'vwap': undefined, 'open': undefined, 'close': last, @@ -51096,11 +54924,16 @@ module.exports = class ftx extends Exchange { 'market_name': market['id'], 'resolution': this.timeframes[timeframe], }; - if (limit !== undefined) { + // max 1501 candles, including the current candle when since is not specified + limit = (limit === undefined) ? 1501 : limit; + if (since === undefined) { + request['end_time'] = this.seconds (); request['limit'] = limit; - } - if (since !== undefined) { + request['start_time'] = request['end_time'] - limit * this.parseTimeframe (timeframe); + } else { request['start_time'] = parseInt (since / 1000); + request['limit'] = limit; + request['end_time'] = this.sum (request['start_time'], limit * this.parseTimeframe (timeframe)); } const response = await this.publicGetMarketsMarketNameCandles (this.extend (request, params)); // @@ -51350,7 +55183,7 @@ module.exports = class ftx extends Exchange { parseOrder (order, market = undefined) { // - // fetchOrder, fetchOrders, fetchOpenOrders, createOrder ("limit", "market") + // limit orders - fetchOrder, fetchOrders, fetchOpenOrders, createOrder // // { // "createdAt": "2019-03-05T09:56:55.728933+00:00", @@ -51370,6 +55203,27 @@ module.exports = class ftx extends Exchange { // "clientId": null, // } // + // market orders - fetchOrder, fetchOrders, fetchOpenOrders, createOrder + // + // { + // "avgFillPrice": 2666.0, + // "clientId": None, + // "createdAt": "2020-02-12T00: 53: 49.009726+00: 00", + // "filledSize": 0.0007, + // "future": None, + // "id": 3109208514, + // "ioc": True, + // "market": "BNBBULL/USD", + // "postOnly": False, + // "price": None, + // "reduceOnly": False, + // "remainingSize": 0.0, + // "side": "buy", + // "size": 0.0007, + // "status": "closed", + // "type": "market" + // } + // // createOrder (conditional, "stop", "trailingStop", or "takeProfit") // // { @@ -51406,15 +55260,18 @@ module.exports = class ftx extends Exchange { const side = this.safeString (order, 'side'); const type = this.safeString (order, 'type'); const amount = this.safeFloat (order, 'size'); + const average = this.safeFloat (order, 'avgFillPrice'); + const price = this.safeFloat2 (order, 'price', 'triggerPrice', average); let cost = undefined; - if (filled !== undefined && amount !== undefined) { - cost = filled * amount; + if (filled !== undefined && price !== undefined) { + cost = filled * price; } - const price = this.safeFloat2 (order, 'price', 'triggerPrice'); const lastTradeTimestamp = this.parse8601 (this.safeString (order, 'triggeredAt')); + const clientOrderId = this.safeString (order, 'clientId'); return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -51424,7 +55281,7 @@ module.exports = class ftx extends Exchange { 'price': price, 'amount': amount, 'cost': cost, - 'average': undefined, + 'average': average, 'filled': filled, 'remaining': remaining, 'status': status, @@ -51527,7 +55384,17 @@ module.exports = class ftx extends Exchange { const request = { 'order_id': parseInt (id), }; - const response = await this.privateDeleteOrdersOrderId (this.extend (request, params)); + // support for canceling conditional orders + // https://github.com/ccxt/ccxt/issues/6669 + const options = this.safeValue (this.options, 'cancelOrder', {}); + const defaultMethod = this.safeString (options, 'method', 'privateDeleteOrdersOrderId'); + let method = this.safeString (params, 'method', defaultMethod); + const type = this.safeValue (params, 'type'); + if ((type === 'stop') || (type === 'trailingStop') || (type === 'takeProfit')) { + method = 'privateDeleteConditionalOrdersOrderId'; + } + const query = this.omit (params, [ 'method', 'type' ]); + const response = await this[method] (this.extend (request, query)); // // { // "success": true, @@ -51602,7 +55469,17 @@ module.exports = class ftx extends Exchange { market = this.market (symbol); request['market'] = market['id']; } - const response = await this.privateGetOrders (this.extend (request, params)); + // support for canceling conditional orders + // https://github.com/ccxt/ccxt/issues/6669 + const options = this.safeValue (this.options, 'fetchOpenOrders', {}); + const defaultMethod = this.safeString (options, 'method', 'privateGetOrders'); + let method = this.safeString (params, 'method', defaultMethod); + const type = this.safeValue (params, 'type'); + if ((type === 'stop') || (type === 'trailingStop') || (type === 'takeProfit')) { + method = 'privateGetConditionalOrders'; + } + const query = this.omit (params, [ 'method', 'type' ]); + const response = await this[method] (this.extend (request, query)); // // { // "success": true, @@ -51646,7 +55523,17 @@ module.exports = class ftx extends Exchange { if (since !== undefined) { request['start_time'] = parseInt (since / 1000); } - const response = await this.privateGetOrdersHistory (this.extend (request, params)); + // support for canceling conditional orders + // https://github.com/ccxt/ccxt/issues/6669 + const options = this.safeValue (this.options, 'fetchOrders', {}); + const defaultMethod = this.safeString (options, 'method', 'privateGetOrdersHistory'); + let method = this.safeString (params, 'method', defaultMethod); + const type = this.safeValue (params, 'type'); + if ((type === 'stop') || (type === 'trailingStop') || (type === 'takeProfit')) { + method = 'privateGetConditionalOrdersHistory'; + } + const query = this.omit (params, [ 'method', 'type' ]); + const response = await this[method] (this.extend (request, query)); // // { // "success": true, @@ -51903,7 +55790,7 @@ module.exports = class ftx extends Exchange { sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { let request = '/api/' + this.implodeParams (path, params); const query = this.omit (params, this.extractParams (path)); - let url = this.urls['api'] + request; + let url = this.urls['api'][api] + request; if (method !== 'POST') { if (Object.keys (query).length) { const suffix = '?' + this.urlencode (query); @@ -51949,7 +55836,7 @@ module.exports = class ftx extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],88:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],87:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -52146,7 +56033,7 @@ module.exports = class fybse extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],89:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],88:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -52164,6 +56051,7 @@ module.exports = class gateio extends Exchange { 'countries': [ 'CN' ], 'version': '2', 'rateLimit': 1000, + 'pro': true, 'has': { 'CORS': false, 'createMarketOrder': false, @@ -52217,6 +56105,7 @@ module.exports = class gateio extends Exchange { 'pairs', 'marketinfo', 'marketlist', + 'coininfo', 'tickers', 'ticker/{id}', 'orderBook/{id}', @@ -52238,6 +56127,7 @@ module.exports = class gateio extends Exchange { 'getOrder', 'openOrders', 'tradeHistory', + 'feelist', 'withdraw', ], }, @@ -52301,6 +56191,10 @@ module.exports = class gateio extends Exchange { }, }, }, + 'commonCurrencies': { + 'BTCBEAR': 'BEAR', + 'BTCBULL': 'BULL', + }, }); } @@ -52522,6 +56416,18 @@ module.exports = class gateio extends Exchange { } parseTrade (trade, market = undefined) { + // { + // "tradeID": 3175762, + // "date": "2017-08-25 07:24:28", + // "type": "sell", + // "rate": 29011, + // "amount": 0.0019, + // "total": 55.1209, + // "fee": "0", + // "fee_coin": "btc", + // "gt_fee":"0", + // "point_fee":"0.1213", + // }, let timestamp = this.safeTimestamp2 (trade, 'timestamp', 'time_unix'); timestamp = this.safeTimestamp (trade, 'time', timestamp); const id = this.safeString2 (trade, 'tradeID', 'id'); @@ -52530,6 +56436,7 @@ module.exports = class gateio extends Exchange { const price = this.safeFloat2 (trade, 'rate', 'price'); const amount = this.safeFloat (trade, 'amount'); const type = this.safeString (trade, 'type'); + const takerOrMaker = this.safeString (trade, 'role'); let cost = undefined; if (price !== undefined) { if (amount !== undefined) { @@ -52540,6 +56447,25 @@ module.exports = class gateio extends Exchange { if (market !== undefined) { symbol = market['symbol']; } + let fee = undefined; + let feeCurrency = this.safeCurrencyCode (this.safeString (trade, 'fee_coin')); + let feeCost = this.safeFloat (trade, 'point_fee'); + if ((feeCost === undefined) || (feeCost === 0)) { + feeCost = this.safeFloat (trade, 'gt_fee'); + if ((feeCost === undefined) || (feeCost === 0)) { + feeCost = this.safeFloat (trade, 'fee'); + } else { + feeCurrency = this.safeCurrencyCode ('GT'); + } + } else { + feeCurrency = this.safeCurrencyCode ('POINT'); + } + if (feeCost !== undefined) { + fee = { + 'cost': feeCost, + 'currency': feeCurrency, + }; + } return { 'id': id, 'info': trade, @@ -52549,11 +56475,11 @@ module.exports = class gateio extends Exchange { 'order': orderId, 'type': undefined, 'side': type, - 'takerOrMaker': undefined, + 'takerOrMaker': takerOrMaker, 'price': price, 'amount': amount, 'cost': cost, - 'fee': undefined, + 'fee': fee, }; } @@ -52645,6 +56571,7 @@ module.exports = class gateio extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': lastTradeTimestamp, @@ -52939,7 +56866,7 @@ module.exports = class gateio extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],90:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],89:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -52987,7 +56914,11 @@ module.exports = class gemini extends Exchange { 'https://docs.gemini.com/rest-api', 'https://docs.sandbox.gemini.com', ], - 'test': 'https://api.sandbox.gemini.com', + 'test': { + 'public': 'https://api.sandbox.gemini.com', + 'private': 'https://api.sandbox.gemini.com', + 'web': 'https://docs.sandbox.gemini.com', + }, 'fees': [ 'https://gemini.com/api-fee-schedule', 'https://gemini.com/trading-fees', @@ -53232,6 +57163,7 @@ module.exports = class gemini extends Exchange { 'max': undefined, }, }, + 'active': undefined, }); } return result; @@ -53393,8 +57325,10 @@ module.exports = class gemini extends Exchange { } const id = this.safeString (order, 'order_id'); const side = this.safeStringLower (order, 'side'); + const clientOrderId = this.safeString (order, 'client_order_id'); return { 'id': id, + 'clientOrderId': clientOrderId, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -53410,6 +57344,7 @@ module.exports = class gemini extends Exchange { 'filled': filled, 'remaining': remaining, 'fee': fee, + 'trades': undefined, }; } @@ -53634,14 +57569,14 @@ module.exports = class gemini extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],91:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],90:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { BadSymbol, ExchangeError, InsufficientFunds, OrderNotFound, InvalidOrder } = require ('./base/errors'); - +const { BadSymbol, PermissionDenied, ExchangeError, ExchangeNotAvailable, OrderNotFound, InsufficientFunds, InvalidOrder, RequestTimeout, AuthenticationError } = require ('./base/errors'); +const { TRUNCATE, DECIMAL_PLACES } = require ('./base/functions/number'); // --------------------------------------------------------------------------- module.exports = class hitbtc extends Exchange { @@ -53651,1048 +57586,12 @@ module.exports = class hitbtc extends Exchange { 'name': 'HitBTC', 'countries': [ 'HK' ], 'rateLimit': 1500, - 'version': '1', - 'has': { - 'CORS': false, - 'fetchTrades': true, - 'fetchTickers': true, - 'fetchOrder': true, - 'fetchOpenOrders': true, - 'fetchClosedOrders': true, - 'fetchOrderTrades': true, - 'withdraw': true, - }, - 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/27766555-8eaec20e-5edc-11e7-9c5b-6dc69fc42f5e.jpg', - 'api': 'https://api.hitbtc.com', - 'www': 'https://hitbtc.com', - 'referral': 'https://hitbtc.com/?ref_id=5a5d39a65d466', - 'doc': 'https://github.com/hitbtc-com/hitbtc-api/blob/master/APIv1.md', - 'fees': [ - 'https://hitbtc.com/fees-and-limits', - 'https://support.hitbtc.com/hc/en-us/articles/115005148605-Fees-and-limits', - ], - }, - 'api': { - 'public': { - 'get': [ - '{symbol}/orderbook', - '{symbol}/ticker', - '{symbol}/trades', - '{symbol}/trades/recent', - 'symbols', - 'ticker', - 'time', - ], - }, - 'trading': { - 'get': [ - 'balance', - 'orders/active', - 'orders/recent', - 'order', - 'trades/by/order', - 'trades', - ], - 'post': [ - 'new_order', - 'cancel_order', - 'cancel_orders', - ], - }, - 'payment': { - 'get': [ - 'balance', - 'address/{currency}', - 'transactions', - 'transactions/{transaction}', - ], - 'post': [ - 'transfer_to_trading', - 'transfer_to_main', - 'address/{currency}', - 'payout', - ], - }, - }, - // hardcoded fees are deprecated and should only be used when there's no other way to get fee info - 'fees': { - 'trading': { - 'tierBased': false, - 'percentage': true, - 'maker': 0.07 / 100, - 'taker': 0.07 / 100, - }, - 'funding': { - 'tierBased': false, - 'percentage': false, - 'withdraw': { - 'BTC': 0.001, - 'BCC': 0.0018, - 'ETH': 0.00215, - 'BCH': 0.0018, - 'USDT': 100, - 'DASH': 0.03, - 'BTG': 0.0005, - 'LTC': 0.003, - 'ZEC': 0.0001, - 'XMR': 0.09, - '1ST': 0.84, - 'ADX': 5.7, - 'AE': 6.7, - 'AEON': 0.01006, - 'AIR': 565, - 'AMP': 9, - 'ANT': 6.7, - 'ARDR': 1, - 'ARN': 18.5, - 'ART': 26, - 'ATB': 0.0004, - 'ATL': 27, - 'ATM': 504, - 'ATS': 860, - 'AVT': 1.9, - 'BAS': 113, - 'BCN': 0.1, - 'DAO.Casino': 124, // id = 'BET' - 'BKB': 46, - 'BMC': 32, - 'BMT': 100, - 'BNT': 2.57, - 'BQX': 4.7, - 'BTM': 40, - 'BTX': 0.04, - 'BUS': 0.004, - 'CCT': 115, - 'CDT': 100, - 'CDX': 30, - 'CFI': 61, - 'CLD': 0.88, - 'CND': 574, - 'CNX': 0.04, - 'COSS': 65, - 'CSNO': 16, - 'CTR': 15, - 'CTX': 146, - 'CVC': 8.46, - 'DBIX': 0.0168, - 'DCN': 120000, - 'DCT': 0.02, - 'DDF': 342, - 'DENT': 6240, - 'DGB': 0.4, - 'DGD': 0.01, - 'DICE': 0.32, - 'DLT': 0.26, - 'DNT': 0.21, - 'DOGE': 2, - 'DOV': 34, - 'DRPU': 24, - 'DRT': 240, - 'DSH': 0.017, - 'EBET': 84, - 'EBTC': 20, - 'EBTCOLD': 6.6, - 'ECAT': 14, - 'EDG': 2, - 'EDO': 2.9, - 'ELE': 0.00172, - 'ELM': 0.004, - 'EMC': 0.03, - 'EMGO': 14, - 'ENJ': 163, - 'EOS': 1.5, - 'ERO': 34, - 'ETBS': 15, - 'ETC': 0.002, - 'ETP': 0.004, - 'EVX': 5.4, - 'EXN': 456, - 'FRD': 65, - 'FUEL': 123.00105, - 'FUN': 202.9598309, - 'FYN': 1.849, - 'FYP': 66.13, - 'GNO': 0.0034, - 'GUP': 4, - 'GVT': 1.2, - 'HAC': 144, - 'HDG': 7, - 'HGT': 1082, - 'HPC': 0.4, - 'HVN': 120, - 'ICN': 0.55, - 'ICO': 34, - 'ICOS': 0.35, - 'IND': 76, - 'INDI': 5913, - 'ITS': 15.0012, - 'IXT': 11, - 'KBR': 143, - 'KICK': 112, - 'LA': 41, - 'LAT': 1.44, - 'LIFE': 13000, - 'LRC': 27, - 'LSK': 0.3, - 'LUN': 0.34, - 'MAID': 5, - 'MANA': 143, - 'MCAP': 5.44, - 'MIPS': 43, - 'MNE': 1.33, - 'MSP': 121, - 'MTH': 92, - 'MYB': 3.9, - 'NDC': 165, - 'NEBL': 0.04, - 'NET': 3.96, - 'NTO': 998, - 'NXC': 13.39, - 'NXT': 3, - 'OAX': 15, - 'ODN': 0.004, - 'OMG': 2, - 'OPT': 335, - 'ORME': 2.8, - 'OTN': 0.57, - 'PAY': 3.1, - 'PIX': 96, - 'PLBT': 0.33, - 'PLR': 114, - 'PLU': 0.87, - 'POE': 784, - 'POLL': 3.5, - 'PPT': 2, - 'PRE': 32, - 'PRG': 39, - 'PRO': 41, - 'PRS': 60, - 'PTOY': 0.5, - 'QAU': 63, - 'QCN': 0.03, - 'QTUM': 0.04, - 'QVT': 64, - 'REP': 0.02, - 'RKC': 15, - 'RVT': 14, - 'SAN': 2.24, - 'SBD': 0.03, - 'SCL': 2.6, - 'SISA': 1640, - 'SKIN': 407, - 'SMART': 0.4, - 'SMS': 0.0375, - 'SNC': 36, - 'SNGLS': 4, - 'SNM': 48, - 'SNT': 233, - 'STEEM': 0.01, - 'STRAT': 0.01, - 'STU': 14, - 'STX': 11, - 'SUB': 17, - 'SUR': 3, - 'SWT': 0.51, - 'TAAS': 0.91, - 'TBT': 2.37, - 'TFL': 15, - 'TIME': 0.03, - 'TIX': 7.1, - 'TKN': 1, - 'TKR': 84, - 'TNT': 90, - 'TRST': 1.6, - 'TRX': 1395, - 'UET': 480, - 'UGT': 15, - 'VEN': 14, - 'VERI': 0.037, - 'VIB': 50, - 'VIBE': 145, - 'VOISE': 618, - 'WEALTH': 0.0168, - 'WINGS': 2.4, - 'WTC': 0.75, - 'XAUR': 3.23, - 'XDN': 0.01, - 'XEM': 15, - 'XUC': 0.9, - 'YOYOW': 140, - 'ZAP': 24, - 'ZRX': 23, - 'ZSC': 191, - }, - 'deposit': { - 'BTC': 0.0006, - 'ETH': 0.003, - 'BCH': 0, - 'USDT': 0, - 'BTG': 0, - 'LTC': 0, - 'ZEC': 0, - 'XMR': 0, - '1ST': 0, - 'ADX': 0, - 'AE': 0, - 'AEON': 0, - 'AIR': 0, - 'AMP': 0, - 'ANT': 0, - 'ARDR': 0, - 'ARN': 0, - 'ART': 0, - 'ATB': 0, - 'ATL': 0, - 'ATM': 0, - 'ATS': 0, - 'AVT': 0, - 'BAS': 0, - 'BCN': 0, - 'DAO.Casino': 0, // id = 'BET' - 'BKB': 0, - 'BMC': 0, - 'BMT': 0, - 'BNT': 0, - 'BQX': 0, - 'BTM': 0, - 'BTX': 0, - 'BUS': 0, - 'CCT': 0, - 'CDT': 0, - 'CDX': 0, - 'CFI': 0, - 'CLD': 0, - 'CND': 0, - 'CNX': 0, - 'COSS': 0, - 'CSNO': 0, - 'CTR': 0, - 'CTX': 0, - 'CVC': 0, - 'DBIX': 0, - 'DCN': 0, - 'DCT': 0, - 'DDF': 0, - 'DENT': 0, - 'DGB': 0, - 'DGD': 0, - 'DICE': 0, - 'DLT': 0, - 'DNT': 0, - 'DOGE': 0, - 'DOV': 0, - 'DRPU': 0, - 'DRT': 0, - 'DSH': 0, - 'EBET': 0, - 'EBTC': 0, - 'EBTCOLD': 0, - 'ECAT': 0, - 'EDG': 0, - 'EDO': 0, - 'ELE': 0, - 'ELM': 0, - 'EMC': 0, - 'EMGO': 0, - 'ENJ': 0, - 'EOS': 0, - 'ERO': 0, - 'ETBS': 0, - 'ETC': 0, - 'ETP': 0, - 'EVX': 0, - 'EXN': 0, - 'FRD': 0, - 'FUEL': 0, - 'FUN': 0, - 'FYN': 0, - 'FYP': 0, - 'GNO': 0, - 'GUP': 0, - 'GVT': 0, - 'HAC': 0, - 'HDG': 0, - 'HGT': 0, - 'HPC': 0, - 'HVN': 0, - 'ICN': 0, - 'ICO': 0, - 'ICOS': 0, - 'IND': 0, - 'INDI': 0, - 'ITS': 0, - 'IXT': 0, - 'KBR': 0, - 'KICK': 0, - 'LA': 0, - 'LAT': 0, - 'LIFE': 0, - 'LRC': 0, - 'LSK': 0, - 'LUN': 0, - 'MAID': 0, - 'MANA': 0, - 'MCAP': 0, - 'MIPS': 0, - 'MNE': 0, - 'MSP': 0, - 'MTH': 0, - 'MYB': 0, - 'NDC': 0, - 'NEBL': 0, - 'NET': 0, - 'NTO': 0, - 'NXC': 0, - 'NXT': 0, - 'OAX': 0, - 'ODN': 0, - 'OMG': 0, - 'OPT': 0, - 'ORME': 0, - 'OTN': 0, - 'PAY': 0, - 'PIX': 0, - 'PLBT': 0, - 'PLR': 0, - 'PLU': 0, - 'POE': 0, - 'POLL': 0, - 'PPT': 0, - 'PRE': 0, - 'PRG': 0, - 'PRO': 0, - 'PRS': 0, - 'PTOY': 0, - 'QAU': 0, - 'QCN': 0, - 'QTUM': 0, - 'QVT': 0, - 'REP': 0, - 'RKC': 0, - 'RVT': 0, - 'SAN': 0, - 'SBD': 0, - 'SCL': 0, - 'SISA': 0, - 'SKIN': 0, - 'SMART': 0, - 'SMS': 0, - 'SNC': 0, - 'SNGLS': 0, - 'SNM': 0, - 'SNT': 0, - 'STEEM': 0, - 'STRAT': 0, - 'STU': 0, - 'STX': 0, - 'SUB': 0, - 'SUR': 0, - 'SWT': 0, - 'TAAS': 0, - 'TBT': 0, - 'TFL': 0, - 'TIME': 0, - 'TIX': 0, - 'TKN': 0, - 'TKR': 0, - 'TNT': 0, - 'TRST': 0, - 'TRX': 0, - 'UET': 0, - 'UGT': 0, - 'VEN': 0, - 'VERI': 0, - 'VIB': 0, - 'VIBE': 0, - 'VOISE': 0, - 'WEALTH': 0, - 'WINGS': 0, - 'WTC': 0, - 'XAUR': 0, - 'XDN': 0, - 'XEM': 0, - 'XUC': 0, - 'YOYOW': 0, - 'ZAP': 0, - 'ZRX': 0, - 'ZSC': 0, - }, - }, - }, - 'commonCurrencies': { - 'BET': 'DAO.Casino', - 'CAT': 'BitClave', - 'CPT': 'Cryptaur', // conflict with CPT = Contents Protocol https://github.com/ccxt/ccxt/issues/4920 and https://github.com/ccxt/ccxt/issues/6081 - 'DRK': 'DASH', - 'EMGO': 'MGO', - 'GET': 'Themis', - 'HSR': 'HC', - 'LNC': 'LinkerCoin', - 'UNC': 'Unigame', - 'USD': 'USDT', - 'XBT': 'BTC', - }, - 'exceptions': { - 'exact': { - '2001': BadSymbol, // {"error":{"code":2001,"message":"Symbol not found","description":"Try get /api/2/public/symbol, to get list of all available symbols."}} - }, - 'broad': { - }, - }, - 'options': { - 'defaultTimeInForce': 'FOK', - }, - }); - } - - async fetchMarkets (params = {}) { - const response = await this.publicGetSymbols (params); - const markets = this.safeValue (response, 'symbols'); - const result = []; - for (let i = 0; i < markets.length; i++) { - const market = markets[i]; - const id = this.safeString (market, 'symbol'); - const baseId = this.safeString (market, 'commodity'); - const quoteId = this.safeString (market, 'currency'); - const lot = this.safeFloat (market, 'lot'); - const step = this.safeFloat (market, 'step'); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - const symbol = base + '/' + quote; - result.push ({ - 'info': market, - 'id': id, - 'symbol': symbol, - 'base': base, - 'quote': quote, - 'baseId': baseId, - 'quoteId': quoteId, - 'lot': lot, - 'step': step, - 'active': true, - 'maker': this.safeFloat (market, 'provideLiquidityRate'), - 'taker': this.safeFloat (market, 'takeLiquidityRate'), - 'precision': { - 'amount': this.precisionFromString (market['lot']), - 'price': this.precisionFromString (market['step']), - }, - 'limits': { - 'amount': { - 'min': lot, - 'max': undefined, - }, - 'price': { - 'min': step, - 'max': undefined, - }, - 'cost': { - 'min': undefined, - 'max': undefined, - }, - }, - }); - } - return result; - } - - async fetchBalance (params = {}) { - await this.loadMarkets (); - let method = this.safeString (params, 'type', 'trading'); - method += 'GetBalance'; - const query = this.omit (params, 'type'); - const response = await this[method] (query); - const balances = this.safeValue (response, 'balance', []); - const result = { 'info': response }; - for (let i = 0; i < balances.length; i++) { - const balance = balances[i]; - const currencyId = this.safeString (balance, 'currency_code'); - const code = this.safeCurrencyCode (currencyId); - const account = this.account (); - account['free'] = this.safeFloat2 (balance, 'cash', 'balance'); - account['used'] = this.safeFloat (balance, 'reserved'); - result[code] = account; - } - return this.parseBalance (result); - } - - async fetchOrderBook (symbol, limit = undefined, params = {}) { - await this.loadMarkets (); - const orderbook = await this.publicGetSymbolOrderbook (this.extend ({ - 'symbol': this.marketId (symbol), - }, params)); - return this.parseOrderBook (orderbook); - } - - parseTicker (ticker, market = undefined) { - const timestamp = this.safeInteger (ticker, 'timestamp'); - let symbol = undefined; - if (market) { - symbol = market['symbol']; - } - const last = this.safeFloat (ticker, 'last'); - return { - 'symbol': symbol, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'high': this.safeFloat (ticker, 'high'), - 'low': this.safeFloat (ticker, 'low'), - 'bid': this.safeFloat (ticker, 'bid'), - 'bidVolume': undefined, - 'ask': this.safeFloat (ticker, 'ask'), - 'askVolume': undefined, - 'vwap': undefined, - 'open': this.safeFloat (ticker, 'open'), - 'close': last, - 'last': last, - 'previousClose': undefined, - 'change': undefined, - 'percentage': undefined, - 'average': undefined, - 'baseVolume': this.safeFloat (ticker, 'volume'), - 'quoteVolume': this.safeFloat (ticker, 'volume_quote'), - 'info': ticker, - }; - } - - async fetchTickers (symbols = undefined, params = {}) { - await this.loadMarkets (); - const tickers = await this.publicGetTicker (params); - const ids = Object.keys (tickers); - const result = {}; - for (let i = 0; i < ids.length; i++) { - const id = ids[i]; - const market = this.markets_by_id[id]; - const symbol = market['symbol']; - const ticker = tickers[id]; - result[symbol] = this.parseTicker (ticker, market); - } - return result; - } - - async fetchTicker (symbol, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'symbol': market['id'], - }; - const response = await this.publicGetSymbolTicker (this.extend (request, params)); - if ('message' in response) { - throw new ExchangeError (this.id + ' ' + response['message']); - } - return this.parseTicker (response, market); - } - - parseTrade (trade, market = undefined) { - if (Array.isArray (trade)) { - return this.parsePublicTrade (trade, market); - } - return this.parseOrderTrade (trade, market); - } - - parsePublicTrade (trade, market = undefined) { - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; - } - let side = undefined; - const tradeLength = trade.length; - if (tradeLength > 4) { - side = trade[4]; - } - const price = parseFloat (trade[1]); - const amount = parseFloat (trade[2]); - const cost = price * amount; - return { - 'info': trade, - 'id': trade[0].toString (), - 'timestamp': trade[3], - 'datetime': this.iso8601 (trade[3]), - 'symbol': symbol, - 'type': undefined, - 'side': side, - 'order': undefined, - 'takerOrMaker': undefined, - 'price': price, - 'amount': amount, - 'cost': cost, - 'fee': undefined, - }; - } - - parseOrderTrade (trade, market = undefined) { - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; - } - let amount = this.safeFloat (trade, 'execQuantity'); - if (market) { - amount *= market['lot']; - } - const price = this.safeFloat (trade, 'execPrice'); - const cost = price * amount; - const fee = { - 'cost': this.safeFloat (trade, 'fee'), - 'currency': undefined, - 'rate': undefined, - }; - const timestamp = this.safeInteger (trade, 'timestamp'); - const id = this.safeString (trade, 'tradeId'); - // we use clientOrderId as the order id with HitBTC intentionally - // because most of their endpoints will require clientOrderId - // explained here: https://github.com/ccxt/ccxt/issues/5674 - const orderId = this.safeString (trade, 'clientOrderId'); - const side = this.safeString (trade, 'side'); - return { - 'info': trade, - 'id': id, - 'order': orderId, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': symbol, - 'type': undefined, - 'side': side, - 'price': price, - 'amount': amount, - 'cost': cost, - 'fee': fee, - }; - } - - async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'symbol': market['id'], - // 'from': 0, - // 'till': 100, - // 'by': 'ts', // or by trade_id - // 'sort': 'desc', // or asc - // 'start_index': 0, - // 'max_results': 1000, - // 'format_item': 'object', - // 'format_price': 'number', - // 'format_amount': 'number', - // 'format_tid': 'string', - // 'format_timestamp': 'millisecond', - // 'format_wrap': false, - // 'side': 'true', - }; - if (since !== undefined) { - request['by'] = 'ts'; - request['from'] = since; - } - if (limit !== undefined) { - request['max_results'] = limit; - } - const response = await this.publicGetSymbolTrades (this.extend (request, params)); - return this.parseTrades (response['trades'], market, since, limit); - } - - async createOrder (symbol, type, side, amount, price = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - // check if amount can be evenly divided into lots - // they want integer quantity in lot units - const quantity = parseFloat (amount) / market['lot']; - const wholeLots = Math.round (quantity); - const difference = quantity - wholeLots; - if (Math.abs (difference) > market['step']) { - throw new ExchangeError (this.id + ' order amount should be evenly divisible by lot unit size of ' + market['lot'].toString ()); - } - const clientOrderId = this.milliseconds (); - const request = { - 'clientOrderId': clientOrderId.toString (), - 'symbol': market['id'], - 'side': side, - 'quantity': wholeLots.toString (), // quantity in integer lot units - 'type': type, - }; - if (type === 'limit') { - request['price'] = this.priceToPrecision (symbol, price); - } else { - request['timeInForce'] = this.options['defaultTimeInForce']; - } - const response = await this.tradingPostNewOrder (this.extend (request, params)); - const order = this.parseOrder (response['ExecutionReport'], market); - if (order['status'] === 'rejected') { - throw new InvalidOrder (this.id + ' order was rejected by the exchange ' + this.json (order)); - } - return order; - } - - async cancelOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - // we use clientOrderId as the order id with HitBTC intentionally - // because most of their endpoints will require clientOrderId - // explained here: https://github.com/ccxt/ccxt/issues/5674 - const request = { - 'clientOrderId': id, - }; - return await this.tradingPostCancelOrder (this.extend (request, params)); - } - - parseOrderStatus (status) { - const statuses = { - 'new': 'open', - 'partiallyFilled': 'open', - 'filled': 'closed', - 'canceled': 'canceled', - 'rejected': 'rejected', - 'expired': 'expired', - }; - return this.safeString (statuses, status); - } - - parseOrder (order, market = undefined) { - let timestamp = this.safeInteger (order, 'lastTimestamp'); - if (timestamp === undefined) { - timestamp = this.safeInteger (order, 'timestamp'); - } - let symbol = undefined; - if (market === undefined) { - market = this.markets_by_id[order['symbol']]; - } - const status = this.parseOrderStatus (this.safeString (order, 'orderStatus')); - let price = this.safeFloat (order, 'orderPrice'); - price = this.safeFloat (order, 'price', price); - price = this.safeFloat (order, 'avgPrice', price); - let amount = this.safeFloat (order, 'orderQuantity'); - amount = this.safeFloat (order, 'quantity', amount); - let remaining = this.safeFloat (order, 'quantityLeaves'); - remaining = this.safeFloat (order, 'leavesQuantity', remaining); - let filled = undefined; - let cost = undefined; - const amountDefined = (amount !== undefined); - const remainingDefined = (remaining !== undefined); - if (market !== undefined) { - symbol = market['symbol']; - if (amountDefined) { - amount *= market['lot']; - } - if (remainingDefined) { - remaining *= market['lot']; - } - } else { - const marketId = this.safeString (order, 'symbol'); - if (marketId in this.markets_by_id) { - market = this.markets_by_id[marketId]; - } - } - if (amountDefined) { - if (remainingDefined) { - filled = amount - remaining; - if (price !== undefined) { - cost = price * filled; - } - } - } - const feeCost = this.safeFloat (order, 'fee'); - let feeCurrency = undefined; - if (market !== undefined) { - symbol = market['symbol']; - feeCurrency = market['quote']; - } - const fee = { - 'cost': feeCost, - 'currency': feeCurrency, - 'rate': undefined, - }; - // we use clientOrderId as the order id with HitBTC intentionally - // because most of their endpoints will require clientOrderId - // explained here: https://github.com/ccxt/ccxt/issues/5674 - const id = this.safeString (order, 'clientOrderId'); - const type = this.safeString (order, 'type'); - const side = this.safeString (order, 'side'); - return { - 'id': id, - 'info': order, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'lastTradeTimestamp': undefined, - 'status': status, - 'symbol': symbol, - 'type': type, - 'side': side, - 'price': price, - 'cost': cost, - 'amount': amount, - 'filled': filled, - 'remaining': remaining, - 'fee': fee, - }; - } - - async fetchOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - // we use clientOrderId as the order id with HitBTC intentionally - // because most of their endpoints will require clientOrderId - // explained here: https://github.com/ccxt/ccxt/issues/5674 - const request = { - 'clientOrderId': id, - }; - const response = await this.tradingGetOrder (this.extend (request, params)); - if (response['orders'][0]) { - return this.parseOrder (response['orders'][0]); - } - throw new OrderNotFound (this.id + ' fetchOrder() error: ' + this.response); - } - - async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const statuses = [ 'new', 'partiallyFiiled' ]; - let market = undefined; - const request = { - 'sort': 'desc', - 'statuses': statuses.join (','), - }; - if (symbol !== undefined) { - market = this.market (symbol); - request['symbols'] = market['id']; - } - const response = await this.tradingGetOrdersActive (this.extend (request, params)); - return this.parseOrders (response['orders'], market, since, limit); - } - - async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - let market = undefined; - const statuses = [ 'filled', 'canceled', 'rejected', 'expired' ]; - const request = { - 'sort': 'desc', - 'statuses': statuses.join (','), - 'max_results': 1000, - }; - if (symbol !== undefined) { - market = this.market (symbol); - request['symbols'] = market['id']; - } - const response = await this.tradingGetOrdersRecent (this.extend (request, params)); - return this.parseOrders (response['orders'], market, since, limit); - } - - async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - let market = undefined; - if (symbol !== undefined) { - market = this.market (symbol); - } - // we use clientOrderId as the order id with HitBTC intentionally - // because most of their endpoints will require clientOrderId - // explained here: https://github.com/ccxt/ccxt/issues/5674 - const request = { - 'clientOrderId': id, - }; - const response = await this.tradingGetTradesByOrder (this.extend (request, params)); - return this.parseTrades (response['trades'], market, since, limit); - } - - async withdraw (code, amount, address, tag = undefined, params = {}) { - this.checkAddress (address); - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'currency_code': currency['id'], - 'amount': amount, - 'address': address, - }; - if (tag !== undefined) { - request['extra_id'] = tag; - } - const response = await this.paymentPostPayout (this.extend (request, params)); - return { - 'info': response, - 'id': response['transaction'], - }; - } - - nonce () { - return this.milliseconds (); - } - - sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = '/' + 'api' + '/' + this.version + '/' + api + '/' + this.implodeParams (path, params); - let query = this.omit (params, this.extractParams (path)); - if (api === 'public') { - if (Object.keys (query).length) { - url += '?' + this.urlencode (query); - } - } else { - this.checkRequiredCredentials (); - const nonce = this.nonce (); - const payload = { 'nonce': nonce, 'apikey': this.apiKey }; - query = this.extend (payload, query); - if (method === 'GET') { - url += '?' + this.urlencode (query); - } else { - url += '?' + this.urlencode (payload); - } - let auth = url; - if (method === 'POST') { - if (Object.keys (query).length) { - body = this.urlencode (query); - auth += body; - } - } - headers = { - 'Content-Type': 'application/x-www-form-urlencoded', - 'X-Signature': this.hmac (this.encode (auth), this.encode (this.secret), 'sha512').toLowerCase (), - }; - } - url = this.urls['api'] + url; - return { 'url': url, 'method': method, 'body': body, 'headers': headers }; - } - - async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - const response = await this.fetch2 (path, api, method, params, headers, body); - if ('code' in response) { - if ('ExecutionReport' in response) { - if (response['ExecutionReport']['orderRejectReason'] === 'orderExceedsLimit') { - throw new InsufficientFunds (this.id + ' ' + this.json (response)); - } - } - throw new ExchangeError (this.id + ' ' + this.json (response)); - } - return response; - } - - handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) { - if (!response) { - return; // fallback to default error handler - } - const error = this.safeValue (response, 'error'); - if (error) { - const code = this.safeValue (error, 'code'); - const feedback = this.id + ' ' + body; - this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback); - this.throwBroadlyMatchedException (this.exceptions['broad'], error, feedback); - throw new ExchangeError (feedback); // unknown error - } - } -}; - -},{"./base/Exchange":7,"./base/errors":9}],92:[function(require,module,exports){ -'use strict'; - -// --------------------------------------------------------------------------- - -const hitbtc = require ('./hitbtc'); -const { BadSymbol, PermissionDenied, ExchangeError, ExchangeNotAvailable, OrderNotFound, InsufficientFunds, InvalidOrder, RequestTimeout, AuthenticationError } = require ('./base/errors'); -const { TRUNCATE, DECIMAL_PLACES } = require ('./base/functions/number'); -// --------------------------------------------------------------------------- - -module.exports = class hitbtc2 extends hitbtc { - describe () { - return this.deepExtend (super.describe (), { - 'id': 'hitbtc2', - 'name': 'HitBTC', - 'countries': [ 'HK' ], - 'rateLimit': 1500, 'version': '2', + 'pro': true, 'has': { 'createDepositAddress': true, 'fetchDepositAddress': true, - 'CORS': true, + 'CORS': false, 'editOrder': true, 'fetchCurrencies': true, 'fetchOHLCV': true, @@ -54723,7 +57622,10 @@ module.exports = class hitbtc2 extends hitbtc { }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/27766555-8eaec20e-5edc-11e7-9c5b-6dc69fc42f5e.jpg', - 'api': 'https://api.hitbtc.com', + 'api': { + 'public': 'https://api.hitbtc.com', + 'private': 'https://api.hitbtc.com', + }, 'www': 'https://hitbtc.com', 'referral': 'https://hitbtc.com/?ref_id=5a5d39a65d466', 'doc': [ @@ -55216,6 +58118,20 @@ module.exports = class hitbtc2 extends hitbtc { 'options': { 'defaultTimeInForce': 'FOK', }, + 'commonCurrencies': { + 'BET': 'DAO.Casino', + 'CAT': 'BitClave', + 'CPT': 'Cryptaur', // conflict with CPT = Contents Protocol https://github.com/ccxt/ccxt/issues/4920 and https://github.com/ccxt/ccxt/issues/6081 + 'DRK': 'DASH', + 'EMGO': 'MGO', + 'GET': 'Themis', + 'HSR': 'HC', + 'LNC': 'LinkerCoin', + 'PLA': 'PlayChip', + 'UNC': 'Unigame', + 'USD': 'USDT', + 'XBT': 'BTC', + }, 'exceptions': { '504': RequestTimeout, // {"error":{"code":504,"message":"Gateway Timeout"}} '1002': AuthenticationError, // {"error":{"code":1002,"message":"Authorization failed","description":""}} @@ -55848,6 +58764,7 @@ module.exports = class hitbtc2 extends hitbtc { // because most of their endpoints will require clientOrderId // explained here: https://github.com/ccxt/ccxt/issues/5674 const id = this.safeString (order, 'clientOrderId'); + const clientOrderId = id; let price = this.safeFloat (order, 'price'); if (price === undefined) { if (id in this.orders) { @@ -55903,6 +58820,7 @@ module.exports = class hitbtc2 extends hitbtc { } return { 'id': id, + 'clientOrderId': clientOrderId, // https://github.com/ccxt/ccxt/issues/5674 'timestamp': created, 'datetime': this.iso8601 (created), 'lastTradeTimestamp': updated, @@ -56116,6 +59034,10 @@ module.exports = class hitbtc2 extends hitbtc { }; } + nonce () { + return this.milliseconds (); + } + sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { let url = '/api/' + this.version + '/'; const query = this.omit (params, this.extractParams (path)); @@ -56141,7 +59063,7 @@ module.exports = class hitbtc2 extends hitbtc { 'Content-Type': 'application/json', }; } - url = this.urls['api'] + url; + url = this.urls['api'][api] + url; return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } @@ -56176,13 +59098,1264 @@ module.exports = class hitbtc2 extends hitbtc { } }; -},{"./base/errors":9,"./base/functions/number":15,"./hitbtc":91}],93:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],91:[function(require,module,exports){ +'use strict'; + +// --------------------------------------------------------------------------- + +const hitbtc = require ('./hitbtc'); + +// --------------------------------------------------------------------------- + +module.exports = class hitbtc2 extends hitbtc { + describe () { + // this is a temporary stub for backward compatibility + // https://github.com/ccxt/ccxt/issues/6678 + return this.deepExtend (super.describe (), { + 'id': 'hitbtc2', + }); + } +}; + +},{"./hitbtc":90}],92:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { AuthenticationError, ExchangeError, ExchangeNotAvailable, InvalidOrder, OrderNotFound, InsufficientFunds, ArgumentsRequired, BadSymbol, BadRequest, RequestTimeout } = require ('./base/errors'); +const { BadRequest, AuthenticationError, NetworkError, ArgumentsRequired, OrderNotFound, InsufficientFunds } = require ('./base/errors'); +const { TICK_SIZE } = require ('./base/functions/number'); + +// --------------------------------------------------------------------------- + +module.exports = class hollaex extends Exchange { + describe () { + return this.deepExtend (super.describe (), { + 'id': 'hollaex', + 'name': 'HollaEx', + 'countries': [ 'KR' ], + 'rateLimit': 333, + 'version': 'v1', + 'has': { + 'CORS': false, + 'fetchMarkets': true, + 'fetchCurrencies': true, + 'fetchTicker': true, + 'fetchTickers': true, + 'fetchOrderBook': true, + 'fetchOrderBooks': true, + 'fetchTrades': true, + 'fetchOHLCV': true, + 'fetchBalance': true, + 'createOrder': true, + 'createLimitBuyOrder': true, + 'createLimitSellOrder': true, + 'createMarketBuyOrder': true, + 'createMarketSellOrder': true, + 'cancelOrder': true, + 'cancelAllOrders': true, + 'fetchOpenOrders': true, + 'fetchClosedOrders': false, + 'fetchOpenOrder': true, + 'fetchOrder': false, + 'fetchDeposits': true, + 'fetchWithdrawals': true, + 'fetchTransactions': false, + 'fetchOrders': false, + 'fetchMyTrades': true, + 'withdraw': true, + 'fetchDepositAddress': true, + }, + 'timeframes': { + '1h': '1h', + '1d': '1d', + }, + 'urls': { + 'logo': 'https://user-images.githubusercontent.com/1294454/75841031-ca375180-5ddd-11ea-8417-b975674c23cb.jpg', + 'api': 'https://api.hollaex.com', + 'www': 'https://hollaex.com', + 'doc': 'https://apidocs.hollaex.com', + 'referral': 'https://pro.hollaex.com/signup?affiliation_code=QSWA6G', + }, + 'precisionMode': TICK_SIZE, + 'requiredCredentials': { + 'apiKey': true, + 'secret': true, + }, + 'api': { + 'public': { + 'get': [ + 'health', + 'constant', + 'ticker', + 'ticker/all', + 'orderbooks', + 'trades', + 'chart', + // TradingView data + 'udf/config', + 'udf/history', + 'udf/symbols', + ], + }, + 'private': { + 'get': [ + 'user', + 'user/balance', + 'user/trades', + 'user/orders', + 'user/orders/{order_id}', + 'user/deposits', + 'user/withdrawals', + 'user/withdraw/{currency}/fee', + ], + 'post': [ + 'user/request-withdrawal', + 'order', + ], + 'delete': [ + 'user/orders', + 'user/orders/{order_id}', + ], + }, + }, + 'fees': { + 'trading': { + 'tierBased': true, + 'percentage': true, + }, + }, + 'exceptions': { + 'broad': { + 'Invalid token': AuthenticationError, + 'Order not found': OrderNotFound, + 'Insufficient balance': InsufficientFunds, + }, + 'exact': { + '400': BadRequest, + '403': AuthenticationError, + '404': BadRequest, + '405': BadRequest, + '410': BadRequest, + '429': BadRequest, + '500': NetworkError, + '503': NetworkError, + }, + }, + 'options': { + // how many seconds before the authenticated request expires + 'api-expires': parseInt (this.timeout / 1000), + }, + }); + } + + async fetchMarkets (params = {}) { + const response = await this.publicGetConstant (params); + // + // { + // coins: { + // xmr: { + // id: 7, + // fullname: "Monero", + // symbol: "xmr", + // active: true, + // allow_deposit: true, + // allow_withdrawal: true, + // withdrawal_fee: 0.02, + // min: 0.001, + // max: 100000, + // increment_unit: 0.001, + // deposit_limits: { '1': 0, '2': 0, '3': 0, '4': 0, '5': 0, '6': 0 }, + // withdrawal_limits: { '1': 10, '2': 15, '3': 100, '4': 100, '5': 200, '6': 300, '7': 350, '8': 400, '9': 500, '10': -1 }, + // created_at: "2019-12-09T07:14:02.720Z", + // updated_at: "2020-01-16T12:12:53.162Z" + // }, + // // ... + // }, + // pairs: { + // 'btc-usdt': { + // id: 2, + // name: "btc-usdt", + // pair_base: "btc", + // pair_2: "usdt", + // taker_fees: { '1': 0.3, '2': 0.25, '3': 0.2, '4': 0.18, '5': 0.1, '6': 0.09, '7': 0.08, '8': 0.06, '9': 0.04, '10': 0 }, + // maker_fees: { '1': 0.1, '2': 0.08, '3': 0.05, '4': 0.03, '5': 0, '6': 0, '7': 0, '8': 0, '9': 0, '10': 0 }, + // min_size: 0.0001, + // max_size: 1000, + // min_price: 100, + // max_price: 100000, + // increment_size: 0.0001, + // increment_price: 0.05, + // active: true, + // created_at: "2019-12-09T07:15:54.537Z", + // updated_at: "2019-12-09T07:15:54.537Z" + // }, + // }, + // config: { tiers: 10 }, + // status: true + // } + // + const pairs = this.safeValue (response, 'pairs', {}); + const keys = Object.keys (pairs); + const result = []; + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const market = pairs[key]; + const id = this.safeString (market, 'name'); + const baseId = this.safeString (market, 'pair_base'); + const quoteId = this.safeString (market, 'pair_2'); + const base = this.commonCurrencyCode (baseId.toUpperCase ()); + const quote = this.commonCurrencyCode (quoteId.toUpperCase ()); + const symbol = base + '/' + quote; + const active = this.safeValue (market, 'active'); + result.push ({ + 'id': id, + 'symbol': symbol, + 'base': base, + 'quote': quote, + 'baseId': baseId, + 'quoteId': quoteId, + 'active': active, + 'precision': { + 'price': this.safeFloat (market, 'increment_price'), + 'amount': this.safeFloat (market, 'increment_size'), + }, + 'limits': { + 'amount': { + 'min': this.safeFloat (market, 'min_size'), + 'max': this.safeFloat (market, 'max_size'), + }, + 'price': { + 'min': this.safeFloat (market, 'min_price'), + 'max': this.safeFloat (market, 'max_price'), + }, + 'cost': { 'min': undefined, 'max': undefined }, + }, + 'info': market, + }); + } + return result; + } + + async fetchCurrencies (params = {}) { + const response = await this.publicGetConstant (params); + const coins = this.safeValue (response, 'coins', {}); + const keys = Object.keys (coins); + const result = {}; + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const currency = coins[key]; + const id = this.safeString (currency, 'symbol'); + const numericId = this.safeInteger (currency, 'id'); + const code = this.safeCurrencyCode (id); + const name = this.safeString (currency, 'fullname'); + const active = this.safeValue (currency, 'active'); + const fee = this.safeFloat (currency, 'withdrawal_fee'); + const precision = this.safeFloat (currency, 'increment_unit'); + const withdrawalLimits = this.safeValue (currency, 'withdrawal_limits', []); + result[code] = { + 'id': id, + 'numericId': numericId, + 'code': code, + 'info': currency, + 'name': name, + 'active': active, + 'fee': fee, + 'precision': precision, + 'limits': { + 'amount': { + 'min': this.safeFloat (currency, 'min'), + 'max': this.safeFloat (currency, 'max'), + }, + 'price': { + 'min': undefined, + 'max': undefined, + }, + 'cost': { + 'min': undefined, + 'max': undefined, + }, + 'withdraw': { + 'min': undefined, + 'max': this.safeValue (withdrawalLimits, 0), + }, + }, + }; + } + return result; + } + + async fetchOrderBooks (symbols = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const response = await this.publicGetOrderbooks (params); + const result = {}; + const marketIds = Object.keys (response); + for (let i = 0; i < marketIds.length; i++) { + const marketId = marketIds[i]; + const orderbook = response[marketId]; + let symbol = marketId; + if (marketId in this.markets_by_id) { + const market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + const [ baseId, quoteId ] = marketId.split ('-'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + const timestamp = this.parse8601 (this.safeString (orderbook, 'timestamp')); + result[symbol] = this.parseOrderBook (response[marketId], timestamp); + } + return result; + } + + async fetchOrderBook (symbol, limit = undefined, params = {}) { + await this.loadMarkets (); + const marketId = this.marketId (symbol); + const request = { + 'symbol': marketId, + }; + const response = await this.publicGetOrderbooks (this.extend (request, params)); + // + // { + // "btc-usdt": { + // "bids": [ + // [ 8836.4, 1.022 ], + // [ 8800, 0.0668 ], + // [ 8797.75, 0.2398 ], + // ], + // "asks": [ + // [ 8839.35, 1.5334 ], + // [ 8852.6, 0.0579 ], + // [ 8860.45, 0.1815 ], + // ], + // "timestamp": "2020-03-03T02:27:25.147Z" + // }, + // "eth-usdt": {}, + // // ... + // } + // + const orderbook = this.safeValue (response, marketId); + const timestamp = this.parse8601 (this.safeString (orderbook, 'timestamp')); + return this.parseOrderBook (orderbook, timestamp); + } + + async fetchTicker (symbol, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.publicGetTicker (this.extend (request, params)); + // + // { + // open: 8615.55, + // close: 8841.05, + // high: 8921.1, + // low: 8607, + // last: 8841.05, + // volume: 20.2802, + // timestamp: '2020-03-03T03:11:18.964Z' + // } + // + return this.parseTicker (response, market); + } + + async fetchTickers (symbols = undefined, params = {}) { + await this.loadMarkets (); + const response = await this.publicGetTickerAll (this.extend (params)); + // + // { + // "bch-usdt": { + // "time": "2020-03-02T04:29:45.011Z", + // "open": 341.65, + // "close":337.9, + // "high":341.65, + // "low":337.3, + // "last":337.9, + // "volume":0.054, + // "symbol":"bch-usdt" + // }, + // // ... + // } + // + return this.parseTickers (response, symbols); + } + + parseTickers (response, symbols = undefined) { + const result = {}; + const keys = Object.keys (response); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const ticker = response[key]; + let symbol = key; + let market = undefined; + const marketId = this.safeString (ticker, 'symbol', key); + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + const [ baseId, quoteId ] = marketId.split ('-'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + result[symbol] = this.parseTicker (ticker, market); + } + return this.filterByArray (result, 'symbol', symbols); + } + + parseTicker (ticker, market = undefined) { + // + // fetchTicker + // + // { + // open: 8615.55, + // close: 8841.05, + // high: 8921.1, + // low: 8607, + // last: 8841.05, + // volume: 20.2802, + // timestamp: '2020-03-03T03:11:18.964Z', + // } + // + // fetchTickers + // + // { + // "time": "2020-03-02T04:29:45.011Z", + // "open": 341.65, + // "close": 337.9, + // "high": 341.65, + // "low": 337.3, + // "last": 337.9, + // "volume": 0.054, + // "symbol": "bch-usdt" + // } + // + let symbol = undefined; + const marketId = this.safeString (ticker, 'symbol'); + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + const [ baseId, quoteId ] = marketId.split ('-'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const timestamp = this.parse8601 (this.safeString2 (ticker, 'time', 'timestamp')); + const close = this.safeFloat (ticker, 'close'); + const result = { + 'symbol': symbol, + 'info': ticker, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'high': this.safeFloat (ticker, 'high'), + 'low': this.safeFloat (ticker, 'low'), + 'bid': undefined, + 'bidVolume': undefined, + 'ask': undefined, + 'askVolume': undefined, + 'vwap': undefined, + 'open': this.safeFloat (ticker, 'open'), + 'close': close, + 'last': this.safeFloat (ticker, 'last', close), + 'previousClose': undefined, + 'change': undefined, + 'percentage': undefined, + 'average': undefined, + 'baseVolume': this.safeFloat (ticker, 'volume'), + 'quoteVolume': undefined, + }; + return result; + } + + async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.publicGetTrades (this.extend (request, params)); + // + // { + // "btc-usdt": [ + // { + // "size": 0.5, + // "price": 8830, + // "side": "buy", + // "timestamp": "2020-03-03T04:44:33.034Z" + // }, + // // ... + // ] + // } + // + const trades = await this.safeValue (response, market['id'], []); + return this.parseTrades (trades, market, since, limit); + } + + parseTrade (trade, market = undefined) { + // + // fetchTrades (public) + // + // { + // "size": 0.5, + // "price": 8830, + // "side": "buy", + // "timestamp": "2020-03-03T04:44:33.034Z" + // } + // + // fetchMyTrades (private) + // + // { + // "side": "buy", + // "symbol": "eth-usdt", + // "size": 0.086, + // "price": 226.19, + // "timestamp": "2020-03-03T08:03:55.459Z", + // "fee": 0.1 + // } + // + let symbol = undefined; + const marketId = this.safeString (trade, 'symbol'); + let quote = undefined; + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + const [ baseId, quoteId ] = marketId.split ('-'); + const base = this.safeCurrencyCode (baseId); + quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const datetime = this.safeString (trade, 'timestamp'); + const timestamp = this.parse8601 (datetime); + const side = this.safeString (trade, 'side'); + const price = this.safeFloat (trade, 'price'); + const amount = this.safeFloat (trade, 'size'); + let cost = undefined; + if (price !== undefined) { + if (amount !== undefined) { + cost = price * amount; + } + } + const feeCost = this.safeFloat (trade, 'fee'); + let fee = undefined; + if (feeCost !== undefined) { + const feeCurrencyCode = (market !== undefined) ? market['quote'] : quote; + fee = { + 'cost': feeCost, + 'currency': feeCurrencyCode, + }; + } + const result = { + 'info': trade, + 'id': undefined, + 'timestamp': timestamp, + 'datetime': datetime, + 'symbol': symbol, + 'order': undefined, + 'type': undefined, + 'side': side, + 'takerOrMaker': undefined, + 'price': price, + 'amount': amount, + 'cost': cost, + 'fee': fee, + }; + return result; + } + + async fetchOHLCV (symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + 'resolution': this.timeframes[timeframe], + }; + const duration = this.parseTimeframe (timeframe); + if (since === undefined) { + if (limit === undefined) { + throw new ArgumentsRequired (this.id + " fetchOHLCV requires a 'since' or a 'limit' argument"); + } else { + const end = this.seconds (); + const start = end - duration * limit; + request['to'] = end; + request['from'] = start; + } + } else { + if (limit === undefined) { + request['from'] = parseInt (since / 1000); + request['to'] = this.seconds (); + } else { + const start = parseInt (since / 1000); + request['from'] = start; + request['to'] = this.sum (start, duration * limit); + } + } + const response = await this.publicGetChart (this.extend (request, params)); + // + // [ + // { + // "time":"2020-03-02T20:00:00.000Z", + // "close":8872.1, + // "high":8872.1, + // "low":8858.6, + // "open":8858.6, + // "symbol":"btc-usdt", + // "volume":1.2922 + // }, + // ] + // + return this.parseOHLCVs (response, market, timeframe, since, limit); + } + + parseOHLCV (response, market = undefined, timeframe = '1h', since = undefined, limit = undefined) { + // + // { + // "time":"2020-03-02T20:00:00.000Z", + // "close":8872.1, + // "high":8872.1, + // "low":8858.6, + // "open":8858.6, + // "symbol":"btc-usdt", + // "volume":1.2922 + // } + // + return [ + this.parse8601 (this.safeString (response, 'time')), + this.safeFloat (response, 'open'), + this.safeFloat (response, 'high'), + this.safeFloat (response, 'low'), + this.safeFloat (response, 'close'), + this.safeFloat (response, 'volume'), + ]; + } + + async fetchBalance (params = {}) { + await this.loadMarkets (); + const response = await this.privateGetUserBalance (params); + // + // { + // "updated_at": "2020-03-02T22:27:38.428Z", + // "btc_balance": 0, + // "btc_pending": 0, + // "btc_available": 0, + // "eth_balance": 0, + // "eth_pending": 0, + // "eth_available": 0, + // // ... + // } + // + const result = { 'info': response }; + const currencyIds = Object.keys (this.currencies_by_id); + for (let i = 0; i < currencyIds.length; i++) { + const currencyId = currencyIds[i]; + const code = this.safeCurrencyCode (currencyId); + const account = this.account (); + account['free'] = this.safeFloat (response, currencyId + '_available'); + account['total'] = this.safeFloat (response, currencyId + '_balance'); + result[code] = account; + } + return this.parseBalance (result); + } + + async fetchOpenOrder (id, symbol = undefined, params = {}) { + await this.loadMarkets (); + const request = { + 'order_id': id, + }; + const response = await this.privateGetUserOrdersOrderId (this.extend (request, params)); + // + // { + // "created_at": "2018-03-23T04:14:08.663Z", + // "title": "string", + // "side": "sell", + // "type": "limit", + // "price": 0, + // "size": 0, + // "symbol": "xht-usdt", + // "id": "string", + // "created_by": 1, + // "filled": 0 + // } + // + return this.parseOrder (response); + } + + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let market = undefined; + const request = {}; + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + } + const response = await this.privateGetUserOrders (this.extend (request, params)); + // + // [ + // { + // "created_at":"2020-03-03T08:02:18.639Z", + // "title":"5419ff3f-9d25-4af7-bcc2-803926518d76", + // "side":"buy", + // "type":"limit", + // "price":226.19, + // "size":0.086, + // "symbol":"eth-usdt", + // "id":"5419ff3f-9d25-4af7-bcc2-803926518d76", + // "created_by":620, + // "filled":0 + // } + // ] + // + return this.parseOrders (response, market); + } + + parseOrder (order, market = undefined) { + // + // fetchOpenOrder, fetchOpenOrders + // + // { + // "created_at":"2020-03-03T08:02:18.639Z", + // "title":"5419ff3f-9d25-4af7-bcc2-803926518d76", + // "side":"buy", + // "type":"limit", + // "price":226.19, + // "size":0.086, + // "symbol":"eth-usdt", + // "id":"5419ff3f-9d25-4af7-bcc2-803926518d76", + // "created_by":620, + // "filled":0 + // } + // + let symbol = undefined; + const marketId = this.safeString (order, 'symbol'); + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + const [ baseId, quoteId ] = marketId.split ('-'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const id = this.safeString (order, 'id'); + const timestamp = this.parse8601 (this.safeString (order, 'created_at')); + const type = this.safeString (order, 'type'); + const side = this.safeString (order, 'side'); + const price = this.safeFloat (order, 'price'); + const amount = this.safeFloat (order, 'size'); + const filled = this.safeFloat (order, 'filled'); + let cost = undefined; + let remaining = undefined; + if (filled !== undefined) { + if (amount !== undefined) { + remaining = amount - filled; + } + if (price !== undefined) { + cost = filled * price; + } + } + const status = (type === 'market') ? 'closed' : 'open'; + const result = { + 'id': id, + 'clientOrderId': undefined, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': undefined, + 'status': status, + 'symbol': symbol, + 'type': type, + 'side': side, + 'price': price, + 'amount': amount, + 'filled': filled, + 'remaining': remaining, + 'cost': cost, + 'trades': undefined, + 'fee': undefined, + 'info': order, + 'average': undefined, + }; + return result; + } + + async createOrder (symbol, type, side, amount, price = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const order = { + 'symbol': market['id'], + 'side': side, + 'size': amount, + 'type': type, + }; + if (type !== 'market') { + order['price'] = price; + } + const response = await this.privatePostOrder (this.extend (order, params)); + // + // { + // "symbol": "xht-usdt", + // "side": "sell", + // "size": 1, + // "type": "limit", + // "price": 0.1, + // "id": "string", + // "created_by": 34, + // "filled": 0, + // "status": "pending" + // } + // + return this.parseOrder (response, market); + } + + async cancelOrder (id, symbol = undefined, params = {}) { + await this.loadMarkets (); + const request = { + 'order_id': id, + }; + const response = await this.privateDeleteUserOrdersOrderId (this.extend (request, params)); + // + // { + // "title": "string", + // "symbol": "xht-usdt", + // "side": "sell", + // "size": 1, + // "type": "limit", + // "price": 0.1, + // "id": "string", + // "created_by": 34, + // "filled": 0 + // } + // + return this.parseOrder (response); + } + + async cancelAllOrders (symbol = undefined, params = {}) { + await this.loadMarkets (); + const request = {}; + let market = undefined; + if (symbol !== undefined) { + market = this.markets (symbol); + request['symbol'] = market['id']; + } + const response = await this.privateDeleteUserOrders (this.extend (request, params)); + // + // [ + // { + // "title": "string", + // "symbol": "xht-usdt", + // "side": "sell", + // "size": 1, + // "type": "limit", + // "price": 0.1, + // "id": "string", + // "created_by": 34, + // "filled": 0 + // } + // ] + // + return this.parseOrders (response, market); + } + + async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'symbol': market['id'], + // 'limit': 50, // default 50, max 100 + // 'page': 1, // page of data to retrieve + // 'order_by': 'timestamp', // field to order data + // 'order': 'asc', // asc or desc + // 'start_date': 123, // starting date of queried data + // 'end_date': 321, // ending date of queried data + }; + let market = undefined; + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + } + if (limit !== undefined) { + request['limit'] = limit; // default 50, max 100 + } + if (since !== undefined) { + request['start_date'] = this.iso8601 (since); + } + const response = await this.privateGetUserTrades (this.extend (request, params)); + // + // { + // "count": 1, + // "data": [ + // { + // "side": "buy", + // "symbol": "eth-usdt", + // "size": 0.086, + // "price": 226.19, + // "timestamp": "2020-03-03T08:03:55.459Z", + // "fee": 0.1 + // } + // ] + // } + // + const data = this.safeValue (response, 'data', []); + return this.parseTrades (data, market, since, limit); + } + + async fetchDepositAddress (code, params = {}) { + await this.loadMarkets (); + const currency = this.currency (code); + const response = await this.privateGetUser (params); + // + // { + // "id": 620, + // "email": "email@gmail.com", + // "full_name": "", + // "name_verified": false, + // "gender": false, + // "nationality": "", + // "phone_number": "", + // "address": { "city": "", "address": "", "country": "", "postal_code": "" }, + // "id_data": { "note": "", "type": "", "number": "", "status": 0 }, + // "bank_account":[], + // "crypto_wallet":{ + // "xrp": "rJtoECs6rPkJoAfgtR8SDDshV6hRHe3X7y:391496555" + // "usdt":"0x1fb4248e167901dfa0d8cdda2243a2126d7ce48d" + // // ... + // }, + // "verification_level": 1, + // "otp_enabled": true, + // "activated": true, + // "note": "", + // "username": "user", + // "affiliation_code": "QSWA6G", + // "settings": { + // "chat": { "set_username": false }, + // "risk": { "order_portfolio_percentage": 20 }, + // "audio": { + // "public_trade": false, + // "order_completed": true, + // "order_partially_completed": true + // }, + // "language": "en", + // "interface": { "theme": "white","order_book_levels": 10 }, + // "notification": { + // "popup_order_completed": true, + // "popup_order_confirmation": true, + // "popup_order_partially_filled": true + // } + // }, + // "flagged": false, + // "is_hap": false, + // "pin": false, + // "discount": 0, + // "created_at": "2020-03-02T22:27:38.331Z", + // "updated_at": "2020-03-03T07:54:58.315Z", + // "balance": { + // "xht_balance": 0, + // "xht_pending": 0, + // "xht_available": 0, + // // ... + // "updated_at": "2020-03-03T10:21:05.430Z" + // }, + // "images": [], + // "fees": { + // "btc-usdt": { "maker_fee": 0.1, "taker_fee": 0.3 }, + // "eth-usdt": { "maker_fee": 0.1, "taker_fee": 0.3 }, + // // ... + // } + // } + // + const cryptoWallet = this.safeValue (response, 'crypto_wallet'); + let address = this.safeString (cryptoWallet, currency['id']); + let tag = undefined; + if (address !== undefined) { + const parts = address.split (':'); + address = this.safeString (parts, 0); + tag = this.safeString (parts, 1); + } + this.checkAddress (address); + return { + 'currency': code, + 'address': address, + 'tag': tag, + 'info': response, + }; + } + + async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'currency': currency['id'], + // 'limit': 50, // default 50, max 100 + // 'page': 1, // page of data to retrieve + // 'order_by': 'timestamp', // field to order data + // 'order': 'asc', // asc or desc + // 'start_date': 123, // starting date of queried data + // 'end_date': 321, // ending date of queried data + }; + let currency = undefined; + if (code !== undefined) { + currency = this.currency (code); + request['currency'] = currency['id']; + } + if (limit !== undefined) { + request['limit'] = limit; // default 50, max 100 + } + if (since !== undefined) { + request['start_date'] = this.iso8601 (since); + } + const response = await this.privateGetUserDeposits (this.extend (request, params)); + // + // { + // "count": 1, + // "data": [ + // { + // "id": 539, + // "amount": 20, + // "fee": 0, + // "address": "0x5c0cc98270d7089408fcbcc8e2131287f5be2306", + // "transaction_id": "0xd4006327a5ec2c41adbdcf566eaaba6597c3d45906abe78ea1a4a022647c2e28", + // "status": true, + // "dismissed": false, + // "rejected": false, + // "description": "", + // "type": "deposit", + // "currency": "usdt", + // "created_at": "2020-03-03T07:56:36.198Z", + // "updated_at": "2020-03-03T08:00:05.674Z", + // "user_id": 620 + // } + // ] + // } + // + const data = this.safeValue (response, 'data', []); + return this.parseTransactions (data, currency, since, limit); + } + + async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'currency': currency['id'], + // 'limit': 50, // default 50, max 100 + // 'page': 1, // page of data to retrieve + // 'order_by': 'timestamp', // field to order data + // 'order': 'asc', // asc or desc + // 'start_date': 123, // starting date of queried data + // 'end_date': 321, // ending date of queried data + }; + let currency = undefined; + if (code !== undefined) { + currency = this.currency (code); + request['currency'] = currency['id']; + } + if (limit !== undefined) { + request['limit'] = limit; // default 50, max 100 + } + if (since !== undefined) { + request['start_date'] = this.iso8601 (since); + } + const response = await this.privateGetUserWithdrawals (this.extend (request, params)); + // + // { + // "count": 1, + // "data": [ + // { + // "id": 539, + // "amount": 20, + // "fee": 0, + // "address": "0x5c0cc98270d7089408fcbcc8e2131287f5be2306", + // "transaction_id": "0xd4006327a5ec2c41adbdcf566eaaba6597c3d45906abe78ea1a4a022647c2e28", + // "status": true, + // "dismissed": false, + // "rejected": false, + // "description": "", + // "type": "withdrawal", + // "currency": "usdt", + // "created_at": "2020-03-03T07:56:36.198Z", + // "updated_at": "2020-03-03T08:00:05.674Z", + // "user_id": 620 + // } + // ] + // } + // + const data = this.safeValue (response, 'data', []); + return this.parseTransactions (data, currency, since, limit); + } + + parseTransaction (transaction, currency = undefined) { + // + // { + // "id": 539, + // "amount": 20, + // "fee": 0, + // "address": "0x5c0cc98270d7089408fcbcc8e2131287f5be2306", + // "transaction_id": "0xd4006327a5ec2c41adbdcf566eaaba6597c3d45906abe78ea1a4a022647c2e28", + // "status": true, + // "dismissed": false, + // "rejected": false, + // "description": "", + // "type": "withdrawal", + // "currency": "usdt", + // "created_at": "2020-03-03T07:56:36.198Z", + // "updated_at": "2020-03-03T08:00:05.674Z", + // "user_id": 620 + // } + // + const id = this.safeString (transaction, 'id'); + const txid = this.safeString (transaction, 'transaction_id'); + const timestamp = this.parse8601 (this.safeString (transaction, 'created_at')); + const updated = this.parse8601 (this.safeString (transaction, 'updated_at')); + const type = this.safeString (transaction, 'type'); + const amount = this.safeFloat (transaction, 'amount'); + let address = this.safeString (transaction, 'address'); + let addressTo = undefined; + const addressFrom = undefined; + let tag = undefined; + let tagTo = undefined; + const tagFrom = undefined; + if (address !== undefined) { + const parts = address.split (':'); + address = this.safeString (parts, 0); + tag = this.safeString (parts, 1); + addressTo = address; + tagTo = tag; + } + const currencyId = this.safeString (transaction, 'currency'); + const code = this.safeCurrencyCode (currencyId); + let status = this.safeValue (transaction, 'status'); + const dismissed = this.safeValue (transaction, 'dismissed'); + const rejected = this.safeValue (transaction, 'rejected'); + if (status) { + status = 'ok'; + } else if (dismissed) { + status = 'canceled'; + } else if (rejected) { + status = 'failed'; + } else { + status = 'pending'; + } + const fee = { + 'currency': code, + 'cost': this.safeFloat (transaction, 'fee'), + }; + return { + 'info': transaction, + 'id': id, + 'txid': txid, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'addressFrom': addressFrom, + 'address': address, + 'addressTo': addressTo, + 'tagFrom': tagFrom, + 'tag': tag, + 'tagTo': tagTo, + 'type': type, + 'amount': amount, + 'currency': code, + 'status': status, + 'updated': updated, + 'fee': fee, + }; + } + + async withdraw (code, amount, address, tag = undefined, params = {}) { + this.checkAddress (address); + await this.loadMarkets (); + const currency = this.currency (code); + if (tag !== undefined) { + address += ':' + tag; + } + const request = { + 'currency': currency['id'], + 'amount': amount, + 'address': address, + }; + // one time password + let otp = this.safeString (params, 'otp_code'); + if ((otp !== undefined) || (this.twofa !== undefined)) { + if (otp === undefined) { + otp = this.oath (); + } + request['otp_code'] = otp; + } + const response = await this.privatePostUserRequestWithdrawal (this.extend (request, params)); + return { + 'info': response, + 'id': undefined, + }; + } + + sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { + const query = this.omit (params, this.extractParams (path)); + path = '/' + this.version + '/' + this.implodeParams (path, params); + if (method === 'GET') { + if (Object.keys (query).length) { + path += '?' + this.urlencode (query); + } + } + const url = this.urls['api'] + path; + if (api === 'private') { + this.checkRequiredCredentials (); + const defaultExpires = this.safeInteger2 (this.options, 'api-expires', 'expires', parseInt (this.timeout / 1000)); + const expires = this.sum (this.seconds (), defaultExpires); + const expiresString = expires.toString (); + let auth = method + path + expiresString; + headers = { + 'api-key': this.encode (this.apiKey), + 'api-expires': expiresString, + }; + if (method === 'POST') { + headers['Content-type'] = 'application/json'; + if (Object.keys (query).length) { + body = this.json (query); + auth += body; + } + } + const signature = this.hmac (this.encode (auth), this.encode (this.secret)); + headers['api-signature'] = signature; + } + return { 'url': url, 'method': method, 'body': body, 'headers': headers }; + } + + handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (response === undefined) { + return; + } + if ((code >= 400) && (code <= 503)) { + // + // { "message": "Invalid token" } + // + const feedback = this.id + ' ' + body; + const message = this.safeString (response, 'message'); + this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback); + const status = code.toString (); + this.throwExactlyMatchedException (this.exceptions['exact'], status, feedback); + } + } +}; + +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],93:[function(require,module,exports){ +'use strict'; + +// --------------------------------------------------------------------------- + +const Exchange = require ('./base/Exchange'); +const { AuthenticationError, ExchangeError, PermissionDenied, ExchangeNotAvailable, InvalidOrder, OrderNotFound, InsufficientFunds, ArgumentsRequired, BadSymbol, BadRequest, RequestTimeout } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -56197,11 +60370,12 @@ module.exports = class huobipro extends Exchange { 'version': 'v1', 'accounts': undefined, 'accountsById': undefined, - 'hostname': 'api.huobi.pro', + 'hostname': 'api.huobi.pro', // api.testnet.huobi.pro + 'pro': true, 'has': { 'CORS': false, 'fetchTickers': true, - 'fetchDepositAddress': false, + 'fetchDepositAddress': true, 'fetchOHLCV': true, 'fetchOrder': true, 'fetchOrders': true, @@ -56227,12 +60401,18 @@ module.exports = class huobipro extends Exchange { '1y': '1year', }, 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/27766569-15aa7b9a-5edd-11e7-9e7f-44791f4ee49c.jpg', + 'test': { + 'market': 'https://api.testnet.huobi.pro', + 'public': 'https://api.testnet.huobi.pro', + 'private': 'https://api.testnet.huobi.pro', + }, + 'logo': 'https://user-images.githubusercontent.com/1294454/76137448-22748a80-604e-11ea-8069-6e389271911d.jpg', 'api': { 'market': 'https://{hostname}', 'public': 'https://{hostname}', 'private': 'https://{hostname}', - 'zendesk': 'https://huobiglobal.zendesk.com/hc/en-us/articles', + 'v2Public': 'https://{hostname}', + 'v2Private': 'https://{hostname}', }, 'www': 'https://www.huobi.pro', 'referral': 'https://www.huobi.co/en-us/topic/invited/?invite_code=rwrd3', @@ -56240,9 +60420,19 @@ module.exports = class huobipro extends Exchange { 'fees': 'https://www.huobi.pro/about/fee/', }, 'api': { - 'zendesk': { + 'v2Public': { 'get': [ - '360000400491-Trade-Limits', + 'reference/currencies', + ], + }, + 'v2Private': { + 'get': [ + 'account/withdraw/quota', + 'account/deposit/address', + 'reference/transact-fee-rate', + ], + 'post': [ + 'sub-user/management', ], }, 'market': { @@ -56266,10 +60456,6 @@ module.exports = class huobipro extends Exchange { ], }, 'private': { - // todo add v2 endpoints - // 'GET /v2/account/withdraw/quota - // 'GET /v2/reference/currencies - // 'GET /v2/account/deposit/address 'get': [ 'account/accounts', // 查询当前用户的所有账户(即account-id) 'account/accounts/{id}/balance', // 查询指定账户的余额 @@ -56294,8 +60480,6 @@ module.exports = class huobipro extends Exchange { 'stable-coin/exchange_rate', 'stable-coin/quote', ], - // todo add v2 endpoints - // POST /v2/sub-user/management 'post': [ 'futures/transfer', 'order/batch-orders', @@ -56331,6 +60515,7 @@ module.exports = class huobipro extends Exchange { 'exceptions': { 'exact': { // err-code + 'api-not-support-temp-addr': PermissionDenied, // {"status":"error","err-code":"api-not-support-temp-addr","err-msg":"API withdrawal does not support temporary addresses","data":null} 'timeout': RequestTimeout, // {"ts":1571653730865,"status":"error","err-code":"timeout","err-msg":"Request Timeout"} 'gateway-internal-error': ExchangeNotAvailable, // {"status":"error","err-code":"gateway-internal-error","err-msg":"Failed to load data. Try again later.","data":null} 'account-frozen-balance-insufficient-error': InsufficientFunds, // {"status":"error","err-code":"account-frozen-balance-insufficient-error","err-msg":"trade account balance is not enough, left: `0.0027`","data":null} @@ -56498,6 +60683,21 @@ module.exports = class huobipro extends Exchange { } parseTicker (ticker, market = undefined) { + // + // { + // "amount": 26228.672978342216, + // "open": 9078.95, + // "close": 9146.86, + // "high": 9155.41, + // "id": 209988544334, + // "count": 265846, + // "low": 8988.0, + // "version": 209988544334, + // "ask": [ 9146.87, 0.156134 ], + // "vol": 2.3822168242201668E8, + // "bid": [ 9146.86, 0.080758 ], + // } + // let symbol = undefined; if (market !== undefined) { symbol = market['symbol']; @@ -56569,13 +60769,35 @@ module.exports = class huobipro extends Exchange { 'type': 'step0', }; const response = await this.marketGetDepth (this.extend (request, params)); + // + // { + // "status": "ok", + // "ch": "market.btcusdt.depth.step0", + // "ts": 1583474832790, + // "tick": { + // "bids": [ + // [ 9100.290000000000000000, 0.200000000000000000 ], + // [ 9099.820000000000000000, 0.200000000000000000 ], + // [ 9099.610000000000000000, 0.205000000000000000 ], + // ], + // "asks": [ + // [ 9100.640000000000000000, 0.005904000000000000 ], + // [ 9101.010000000000000000, 0.287311000000000000 ], + // [ 9101.030000000000000000, 0.012121000000000000 ], + // ], + // "ts":1583474832008, + // "version":104999698780 + // } + // } + // if ('tick' in response) { if (!response['tick']) { throw new ExchangeError (this.id + ' fetchOrderBook() returned empty response: ' + this.json (response)); } - const orderbook = this.safeValue (response, 'tick'); - const result = this.parseOrderBook (orderbook, orderbook['ts']); - result['nonce'] = orderbook['version']; + const tick = this.safeValue (response, 'tick'); + const timestamp = this.safeInteger (tick, 'ts', this.safeInteger (response, 'ts')); + const result = this.parseOrderBook (tick, timestamp); + result['nonce'] = this.safeInteger (tick, 'version'); return result; } throw new ExchangeError (this.id + ' fetchOrderBook() returned unrecognized response: ' + this.json (response)); @@ -56588,7 +60810,31 @@ module.exports = class huobipro extends Exchange { 'symbol': market['id'], }; const response = await this.marketGetDetailMerged (this.extend (request, params)); - return this.parseTicker (response['tick'], market); + // + // { + // "status": "ok", + // "ch": "market.btcusdt.detail.merged", + // "ts": 1583494336669, + // "tick": { + // "amount": 26228.672978342216, + // "open": 9078.95, + // "close": 9146.86, + // "high": 9155.41, + // "id": 209988544334, + // "count": 265846, + // "low": 8988.0, + // "version": 209988544334, + // "ask": [ 9146.87, 0.156134 ], + // "vol": 2.3822168242201668E8, + // "bid": [ 9146.86, 0.080758 ], + // } + // } + // + const ticker = this.parseTicker (response['tick'], market); + const timestamp = this.safeValue (response, 'ts'); + ticker['timestamp'] = timestamp; + ticker['datetime'] = this.iso8601 (timestamp); + return ticker; } async fetchTickers (symbols = undefined, params = {}) { @@ -56609,10 +60855,24 @@ module.exports = class huobipro extends Exchange { result[symbol] = ticker; } } - return result; + return this.filterByArray (result, 'symbol', symbols); } parseTrade (trade, market = undefined) { + // + // fetchTrades (public) + // + // { + // "amount": 0.010411000000000000, + // "trade-id": 102090736910, + // "ts": 1583497692182, + // "id": 10500517034273194594947, + // "price": 9096.050000000000000000, + // "direction": "sell" + // } + // + // fetchMyTrades (private) + // let symbol = undefined; if (market === undefined) { const marketId = this.safeString (trade, 'symbol'); @@ -56660,7 +60920,8 @@ module.exports = class huobipro extends Exchange { 'currency': feeCurrency, }; } - const id = this.safeString (trade, 'id'); + const tradeId = this.safeString2 (trade, 'trade-id', 'tradeId'); + const id = this.safeString (trade, 'id', tradeId); return { 'id': id, 'info': trade, @@ -56707,6 +60968,30 @@ module.exports = class huobipro extends Exchange { request['size'] = limit; } const response = await this.marketGetHistoryTrade (this.extend (request, params)); + // + // { + // "status": "ok", + // "ch": "market.btcusdt.trade.detail", + // "ts": 1583497692365, + // "data": [ + // { + // "id": 105005170342, + // "ts": 1583497692182, + // "data": [ + // { + // "amount": 0.010411000000000000, + // "trade-id": 102090736910, + // "ts": 1583497692182, + // "id": 10500517034273194594947, + // "price": 9096.050000000000000000, + // "direction": "sell" + // } + // ] + // }, + // // ... + // ] + // } + // const data = this.safeValue (response, 'data'); let result = []; for (let i = 0; i < data.length; i++) { @@ -56908,6 +61193,9 @@ module.exports = class huobipro extends Exchange { } async fetchOpenOrdersV1 (symbol = undefined, since = undefined, limit = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOpenOrdersV1 requires a symbol argument'); + } return await this.fetchOrdersByStates ('pre-submitted,submitted,partial-filled', symbol, since, limit, params); } @@ -57071,6 +61359,7 @@ module.exports = class huobipro extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -57085,6 +61374,7 @@ module.exports = class huobipro extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; } @@ -57139,6 +61429,8 @@ module.exports = class huobipro extends Exchange { 'cost': undefined, 'trades': undefined, 'fee': undefined, + 'clientOrderId': undefined, + 'average': undefined, }; } @@ -57178,94 +61470,50 @@ module.exports = class huobipro extends Exchange { }; } - async withdraw (code, amount, address, tag = undefined, params = {}) { - await this.loadMarkets (); + parseDepositAddress (depositAddress, currency = undefined) { + // + // { + // currency: "eth", + // address: "0xf7292eb9ba7bc50358e27f0e025a4d225a64127b", + // addressTag: "", + // chain: "eth" + // } + // + const address = this.safeString (depositAddress, 'address'); + const tag = this.safeString (depositAddress, 'addressTag'); + const currencyId = this.safeString (depositAddress, 'currency'); + const code = this.safeCurrencyCode (currencyId); this.checkAddress (address); + return { + 'currency': code, + 'address': address, + 'tag': tag, + 'info': depositAddress, + }; + } + + async fetchDepositAddress (code, params = {}) { + await this.loadMarkets (); const currency = this.currency (code); const request = { - 'address': address, // only supports existing addresses in your withdraw address list - 'amount': amount, - 'currency': currency['id'].toLowerCase (), + 'currency': currency['id'], }; - if (tag !== undefined) { - request['addr-tag'] = tag; // only for XRP? - } - const response = await this.privatePostDwWithdrawApiCreate (this.extend (request, params)); - const id = this.safeString (response, 'data'); - return { - 'info': response, - 'id': id, - }; - } - - sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = '/'; - if (api === 'market') { - url += api; - } else if ((api === 'public') || (api === 'private')) { - url += this.version; - } - url += '/' + this.implodeParams (path, params); - const query = this.omit (params, this.extractParams (path)); - if (api === 'private') { - this.checkRequiredCredentials (); - const timestamp = this.ymdhms (this.milliseconds (), 'T'); - let request = { - 'SignatureMethod': 'HmacSHA256', - 'SignatureVersion': '2', - 'AccessKeyId': this.apiKey, - 'Timestamp': timestamp, - }; - if (method !== 'POST') { - request = this.extend (request, query); - } - request = this.keysort (request); - let auth = this.urlencode (request); - // unfortunately, PHP demands double quotes for the escaped newline symbol - // eslint-disable-next-line quotes - const payload = [ method, this.hostname, url, auth ].join ("\n"); - const signature = this.hmac (this.encode (payload), this.encode (this.secret), 'sha256', 'base64'); - auth += '&' + this.urlencode ({ 'Signature': signature }); - url += '?' + auth; - if (method === 'POST') { - body = this.json (query); - headers = { - 'Content-Type': 'application/json', - }; - } else { - headers = { - 'Content-Type': 'application/x-www-form-urlencoded', - }; - } - } else { - if (Object.keys (params).length) { - url += '?' + this.urlencode (params); - } - } - url = this.implodeParams (this.urls['api'][api], { - 'hostname': this.hostname, - }) + url; - return { 'url': url, 'method': method, 'body': body, 'headers': headers }; - } - - handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) { - if (response === undefined) { - return; // fallback to default error handler - } - if ('status' in response) { - // - // {"status":"error","err-code":"order-limitorder-amount-min-error","err-msg":"limit order amount error, min: `0.001`","data":null} - // - const status = this.safeString (response, 'status'); - if (status === 'error') { - const code = this.safeString (response, 'err-code'); - const feedback = this.id + ' ' + body; - this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback); - const message = this.safeString (response, 'err-msg'); - this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback); - throw new ExchangeError (feedback); - } - } + const response = await this.v2PrivateGetAccountDepositAddress (this.extend (request, params)); + // + // { + // code: 200, + // data: [ + // { + // currency: "eth", + // address: "0xf7292eb9ba7bc50358e27f0e025a4d225a64127b", + // addressTag: "", + // chain: "eth" + // } + // ] + // } + // + const data = this.safeValue (response, 'data', []); + return this.parseDepositAddress (this.safeValue (data, 0, {}), currency); } async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { @@ -57409,9 +61657,101 @@ module.exports = class huobipro extends Exchange { }; return this.safeString (statuses, status, status); } + + async withdraw (code, amount, address, tag = undefined, params = {}) { + await this.loadMarkets (); + this.checkAddress (address); + const currency = this.currency (code); + const request = { + 'address': address, // only supports existing addresses in your withdraw address list + 'amount': amount, + 'currency': currency['id'].toLowerCase (), + }; + if (tag !== undefined) { + request['addr-tag'] = tag; // only for XRP? + } + const response = await this.privatePostDwWithdrawApiCreate (this.extend (request, params)); + const id = this.safeString (response, 'data'); + return { + 'info': response, + 'id': id, + }; + } + + sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { + let url = '/'; + if (api === 'market') { + url += api; + } else if ((api === 'public') || (api === 'private')) { + url += this.version; + } else if ((api === 'v2Public') || (api === 'v2Private')) { + url += 'v2'; + } + url += '/' + this.implodeParams (path, params); + const query = this.omit (params, this.extractParams (path)); + if (api === 'private' || api === 'v2Private') { + this.checkRequiredCredentials (); + const timestamp = this.ymdhms (this.milliseconds (), 'T'); + let request = { + 'SignatureMethod': 'HmacSHA256', + 'SignatureVersion': '2', + 'AccessKeyId': this.apiKey, + 'Timestamp': timestamp, + }; + if (method !== 'POST') { + request = this.extend (request, query); + } + request = this.keysort (request); + let auth = this.urlencode (request); + // unfortunately, PHP demands double quotes for the escaped newline symbol + // eslint-disable-next-line quotes + const payload = [ method, this.hostname, url, auth ].join ("\n"); + const signature = this.hmac (this.encode (payload), this.encode (this.secret), 'sha256', 'base64'); + auth += '&' + this.urlencode ({ 'Signature': signature }); + url += '?' + auth; + if (method === 'POST') { + body = this.json (query); + headers = { + 'Content-Type': 'application/json', + }; + } else { + headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + }; + } + } else { + if (Object.keys (params).length) { + url += '?' + this.urlencode (params); + } + } + url = this.implodeParams (this.urls['api'][api], { + 'hostname': this.hostname, + }) + url; + return { 'url': url, 'method': method, 'body': body, 'headers': headers }; + } + + handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (response === undefined) { + return; // fallback to default error handler + } + if ('status' in response) { + // + // {"status":"error","err-code":"order-limitorder-amount-min-error","err-msg":"limit order amount error, min: `0.001`","data":null} + // + const status = this.safeString (response, 'status'); + if (status === 'error') { + const code = this.safeString (response, 'err-code'); + const feedback = this.id + ' ' + body; + this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback); + const message = this.safeString (response, 'err-msg'); + this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback); + throw new ExchangeError (feedback); + } + } + } }; -},{"./base/Exchange":7,"./base/errors":9}],94:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],94:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -57427,12 +61767,13 @@ module.exports = class huobiru extends huobipro { 'name': 'Huobi Russia', 'countries': [ 'RU' ], 'hostname': 'www.huobi.com.ru', + 'pro': true, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/52978816-e8552e00-33e3-11e9-98ed-845acfece834.jpg', 'api': { - 'market': 'https://www.huobi.com.ru/api', - 'public': 'https://www.huobi.com.ru/api', - 'private': 'https://www.huobi.com.ru/api', + 'market': 'https://{hostname}/api', + 'public': 'https://{hostname}/api', + 'private': 'https://{hostname}/api', 'zendesk': 'https://huobiglobal.zendesk.com/hc/en-us/articles', }, 'www': 'https://www.huobi.com.ru/ru-ru', @@ -57563,6 +61904,7 @@ module.exports = class ice3x extends Exchange { }, }, 'info': currency, + 'fee': undefined, }; } return result; @@ -57595,6 +61937,8 @@ module.exports = class ice3x extends Exchange { 'quoteId': quoteId, 'active': undefined, 'info': market, + 'precision': this.precision, + 'limits': this.limits, }); } return result; @@ -57777,6 +62121,7 @@ module.exports = class ice3x extends Exchange { } return { 'id': this.safeString (order, 'order_id'), + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -57792,6 +62137,7 @@ module.exports = class ice3x extends Exchange { 'trades': undefined, 'fee': fee, 'info': order, + 'average': undefined, }; } @@ -57923,7 +62269,7 @@ module.exports = class ice3x extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],96:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],96:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -58023,8 +62369,11 @@ module.exports = class idex extends Exchange { 'secret': false, }, 'commonCurrencies': { - 'ONE': 'Menlo One', 'FT': 'Fabric Token', + 'MT': 'Monarch', + 'ONE': 'Menlo One', + 'PLA': 'PlayChip', + 'WAX': 'WAXP', }, }); } @@ -58308,13 +62657,13 @@ module.exports = class idex extends Exchange { if (side === 'buy') { tokenBuy = market['baseId']; tokenSell = market['quoteId']; - amountBuy = this.toWei (amount, 'ether', market['precision']['amount']); - amountSell = this.toWei (quoteAmount, 'ether', 18); + amountBuy = this.toWei (amount, market['precision']['amount']); + amountSell = this.toWei (quoteAmount, 18); } else { tokenBuy = market['quoteId']; tokenSell = market['baseId']; - amountBuy = this.toWei (quoteAmount, 'ether', 18); - amountSell = this.toWei (amount, 'ether', market['precision']['amount']); + amountBuy = this.toWei (quoteAmount, 18); + amountSell = this.toWei (amount, market['precision']['amount']); } const nonce = await this.getNonce (); const orderToHash = { @@ -58659,8 +63008,11 @@ module.exports = class idex extends Exchange { amount = this.safeFloat (order, 'amount'); } const filled = this.safeFloat (order, 'filled'); - const cost = this.safeFloat (order, 'total'); const price = this.safeFloat (order, 'price'); + let cost = this.safeFloat (order, 'total'); + if ((cost !== undefined) && (filled !== undefined) && !cost) { + cost = filled * price; + } if ('market' in order) { const marketId = order['market']; symbol = this.markets_by_id[marketId]['symbol']; @@ -58680,6 +63032,7 @@ module.exports = class idex extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -58691,6 +63044,10 @@ module.exports = class idex extends Exchange { 'remaining': remaining, 'cost': cost, 'status': status, + 'lastTradeTimestamp': undefined, + 'average': undefined, + 'trades': undefined, + 'fee': undefined, }; } @@ -58914,7 +63271,7 @@ module.exports = class idex extends Exchange { const currency = this.currency (code); const tokenAddress = currency['id']; const nonce = await this.getNonce (); - amount = this.toWei (amount, 'ether', currency['precision']); + amount = this.toWei (amount, currency['precision']); const requestToHash = { 'contractAddress': await this.getContractAddress (), 'token': tokenAddress, @@ -59004,7 +63361,7 @@ module.exports = class idex extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],97:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],97:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -59078,6 +63435,9 @@ module.exports = class independentreserve extends Exchange { 'tierBased': false, }, }, + 'commonCurrencies': { + 'PLA': 'PlayChip', + }, }); } @@ -59101,6 +63461,9 @@ module.exports = class independentreserve extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'info': id, + 'active': undefined, + 'precision': this.precision, + 'limits': this.limits, }); } } @@ -59178,6 +63541,21 @@ module.exports = class independentreserve extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "OrderGuid": "c7347e4c-b865-4c94-8f74-d934d4b0b177", + // "CreatedTimestampUtc": "2014-09-23T12:39:34.3817763Z", + // "Type": "MarketBid", + // "VolumeOrdered": 5.0, + // "VolumeFilled": 5.0, + // "Price": null, + // "AvgPrice": 100.0, + // "ReservedAmount": 0.0, + // "Status": "Filled", + // "PrimaryCurrencyCode": "Xbt", + // "SecondaryCurrencyCode": "Usd" + // } + // let symbol = undefined; const baseId = this.safeString (order, 'PrimaryCurrencyCode'); const quoteId = this.safeString (order, 'PrimaryCurrencyCode'); @@ -59234,6 +63612,7 @@ module.exports = class independentreserve extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -59248,6 +63627,7 @@ module.exports = class independentreserve extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; } @@ -59415,7 +63795,7 @@ module.exports = class independentreserve extends Exchange { } }; -},{"./base/Exchange":7}],98:[function(require,module,exports){ +},{"./base/Exchange":8}],98:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -59698,6 +64078,16 @@ module.exports = class indodax extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "order_id": "12345", + // "submit_time": "1392228122", + // "price": "8000000", + // "type": "sell", + // "order_ltc": "100000000", + // "remain_ltc": "100000000" + // } + // let side = undefined; if ('type' in order) { side = order['type']; @@ -59749,6 +64139,7 @@ module.exports = class indodax extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -59763,6 +64154,7 @@ module.exports = class indodax extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; } @@ -59970,7 +64362,7 @@ module.exports = class indodax extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],99:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],99:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -60034,12 +64426,12 @@ module.exports = class itbit extends Exchange { }, }, 'markets': { - 'BTC/USD': { 'id': 'XBTUSD', 'symbol': 'BTC/USD', 'base': 'BTC', 'quote': 'USD' }, - 'BTC/SGD': { 'id': 'XBTSGD', 'symbol': 'BTC/SGD', 'base': 'BTC', 'quote': 'SGD' }, - 'BTC/EUR': { 'id': 'XBTEUR', 'symbol': 'BTC/EUR', 'base': 'BTC', 'quote': 'EUR' }, - 'ETH/USD': { 'id': 'ETHUSD', 'symbol': 'ETH/USD', 'base': 'ETH', 'quote': 'USD' }, - 'ETH/EUR': { 'id': 'ETHEUR', 'symbol': 'ETH/EUR', 'base': 'ETH', 'quote': 'EUR' }, - 'ETH/SGD': { 'id': 'ETHSGD', 'symbol': 'ETH/SGD', 'base': 'ETH', 'quote': 'SGD' }, + 'BTC/USD': { 'id': 'XBTUSD', 'symbol': 'BTC/USD', 'base': 'BTC', 'quote': 'USD', 'baseId': 'XBT', 'quoteId': 'USD' }, + 'BTC/SGD': { 'id': 'XBTSGD', 'symbol': 'BTC/SGD', 'base': 'BTC', 'quote': 'SGD', 'baseId': 'XBT', 'quoteId': 'SGD' }, + 'BTC/EUR': { 'id': 'XBTEUR', 'symbol': 'BTC/EUR', 'base': 'BTC', 'quote': 'EUR', 'baseId': 'XBT', 'quoteId': 'EUR' }, + 'ETH/USD': { 'id': 'ETHUSD', 'symbol': 'ETH/USD', 'base': 'ETH', 'quote': 'USD', 'baseId': 'ETH', 'quoteId': 'USD' }, + 'ETH/EUR': { 'id': 'ETHEUR', 'symbol': 'ETH/EUR', 'base': 'ETH', 'quote': 'EUR', 'baseId': 'ETH', 'quoteId': 'EUR' }, + 'ETH/SGD': { 'id': 'ETHSGD', 'symbol': 'ETH/SGD', 'base': 'ETH', 'quote': 'SGD', 'baseId': 'ETH', 'quoteId': 'SGD' }, }, 'fees': { 'trading': { @@ -60186,6 +64578,7 @@ module.exports = class itbit extends Exchange { 'price': price, 'amount': amount, 'cost': cost, + 'fee': undefined, }; if (feeCost !== undefined) { if (rebatesApplied !== undefined) { @@ -60445,19 +64838,51 @@ module.exports = class itbit extends Exchange { } parseOrder (order, market = undefined) { - const side = order['side']; - const type = order['type']; + // + // { + // "id": "13d6af57-8b0b-41e5-af30-becf0bcc574d", + // "walletId": "7e037345-1288-4c39-12fe-d0f99a475a98", + // "side": "buy", + // "instrument": "XBTUSD", + // "type": "limit", + // "currency": "XBT", + // "amount": "2.50000000", + // "displayAmount": "2.50000000", + // "price": "650.00000000", + // "volumeWeightedAveragePrice": "0.00000000", + // "amountFilled": "0.00000000", + // "createdTime": "2014-02-11T17:05:15Z", + // "status": "submitted", + // "funds": null, + // "metadata": {}, + // "clientOrderIdentifier": null, + // "postOnly": "False" + // } + // + const side = this.safeString (order, 'side'); + const type = this.safeString (order, 'type'); const symbol = this.markets_by_id[order['instrument']]['symbol']; const timestamp = this.parse8601 (order['createdTime']); const amount = this.safeFloat (order, 'amount'); const filled = this.safeFloat (order, 'amountFilled'); - const remaining = amount - filled; + let remaining = undefined; + let cost = undefined; const fee = undefined; const price = this.safeFloat (order, 'price'); const average = this.safeFloat (order, 'volumeWeightedAveragePrice'); - const cost = filled * average; + if (filled !== undefined) { + if (amount !== undefined) { + remaining = amount - filled; + } + if (average !== undefined) { + cost = filled * average; + } + } + const clientOrderId = this.safeString (order, 'clientOrderIdentifier'); + const id = this.safeString (order, 'id'); return { - 'id': order['id'], + 'id': id, + 'clientOrderId': clientOrderId, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -60474,6 +64899,7 @@ module.exports = class itbit extends Exchange { 'remaining': remaining, 'fee': fee, // 'trades': this.parseTrades (order['trades'], market), + 'trades': undefined, }; } @@ -60572,7 +64998,7 @@ module.exports = class itbit extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],100:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],100:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -60974,6 +65400,20 @@ module.exports = class kkex extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "status": 2, + // "source": "NORMAL", + // "amount": "10.852019", + // "create_date": 1523938461036, + // "avg_price": "0.00096104", + // "order_id": "100", + // "price": "0.00096105", + // "type": "buy", + // "symbol": "READBTC", + // "deal_amount": "10.852019" + // } + // let symbol = undefined; if (market !== undefined) { symbol = market['symbol']; @@ -61002,6 +65442,7 @@ module.exports = class kkex extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -61017,6 +65458,7 @@ module.exports = class kkex extends Exchange { 'remaining': remaining, 'fee': undefined, 'info': order, + 'trades': undefined, }; } @@ -61065,6 +65507,8 @@ module.exports = class kkex extends Exchange { 'remaining': undefined, 'trades': undefined, 'fee': undefined, + 'clientOrderId': undefined, + 'average': undefined, }; } @@ -61140,7 +65584,7 @@ module.exports = class kkex extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],101:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],101:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -61160,6 +65604,7 @@ module.exports = class kraken extends Exchange { 'version': '0', 'rateLimit': 3000, 'certified': true, + 'pro': true, 'has': { 'createDepositAddress': true, 'fetchDepositAddress': true, @@ -61192,7 +65637,7 @@ module.exports = class kraken extends Exchange { '2w': 21600, }, 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/27766599-22709304-5ede-11e7-9de1-9f33732e1509.jpg', + 'logo': 'https://user-images.githubusercontent.com/51840849/76173629-fc67fb00-61b1-11ea-84fe-f2de582f58a3.jpg', 'api': { 'public': 'https://api.kraken.com', 'private': 'https://api.kraken.com', @@ -61348,6 +65793,7 @@ module.exports = class kraken extends Exchange { 'delistedMarketsById': {}, // cannot withdraw/deposit these 'inactiveCurrencies': [ 'CAD', 'USD', 'JPY', 'GBP' ], + 'fetchMinOrderAmounts': true, }, 'exceptions': { 'EQuery:Invalid asset pair': BadSymbol, // {"error":["EQuery:Invalid asset pair"]} @@ -61403,7 +65849,11 @@ module.exports = class kraken extends Exchange { async fetchMarkets (params = {}) { const response = await this.publicGetAssetPairs (params); - const limits = await this.fetchMinOrderAmounts (); + const fetchMinOrderAmounts = this.safeValue (this.options, 'fetchMinOrderAmounts', false); + let limits = {}; + if (fetchMinOrderAmounts) { + limits = await this.fetchMinOrderAmounts (); + } const keys = Object.keys (response['result']); let result = []; for (let i = 0; i < keys.length; i++) { @@ -61866,14 +66316,14 @@ module.exports = class kraken extends Exchange { symbol = market['symbol']; } if (Array.isArray (trade)) { - timestamp = parseInt (trade[2] * 1000); + timestamp = this.safeTimestamp (trade, 2); side = (trade[3] === 's') ? 'sell' : 'buy'; type = (trade[4] === 'l') ? 'limit' : 'market'; - price = parseFloat (trade[0]); - amount = parseFloat (trade[1]); + price = this.safeFloat (trade, 0); + amount = this.safeFloat (trade, 1); const tradeLength = trade.length; if (tradeLength > 6) { - id = trade[6]; // artificially added as per #1794 + id = this.safeString (trade, 6); // artificially added as per #1794 } } else if ('ordertxid' in trade) { order = trade['ordertxid']; @@ -61997,8 +66447,10 @@ module.exports = class kraken extends Exchange { id = (length > 1) ? id : id[0]; } } + const clientOrderId = this.safeString (params, 'userref'); return { 'id': id, + 'clientOrderId': clientOrderId, 'info': response, 'timestamp': undefined, 'datetime': undefined, @@ -62120,8 +66572,10 @@ module.exports = class kraken extends Exchange { } const status = this.parseOrderStatus (this.safeString (order, 'status')); const id = this.safeString (order, 'id'); + const clientOrderId = this.safeString (order, 'userref'); return { 'id': id, + 'clientOrderId': clientOrderId, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -62138,6 +66592,7 @@ module.exports = class kraken extends Exchange { 'remaining': remaining, 'fee': fee, // 'trades': this.parseTrades (order['trades'], market), + 'trades': undefined, }; } @@ -62573,7 +67028,7 @@ module.exports = class kraken extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],102:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],102:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -62592,8 +67047,10 @@ module.exports = class kucoin extends Exchange { 'rateLimit': 334, 'version': 'v2', 'certified': false, + 'pro': true, 'comment': 'Platform 2.0', 'has': { + 'CORS': false, 'fetchTime': true, 'fetchMarkets': true, 'fetchCurrencies': true, @@ -62646,6 +67103,10 @@ module.exports = class kucoin extends Exchange { 'symbols', 'market/allTickers', 'market/orderbook/level{level}', + 'market/orderbook/level2', + 'market/orderbook/level2_20', + 'market/orderbook/level2_100', + 'market/orderbook/level3', 'market/histories', 'market/candles', 'market/stats', @@ -62677,6 +67138,7 @@ module.exports = class kucoin extends Exchange { 'post': [ 'accounts', 'accounts/inner-transfer', + 'accounts/sub-transfer', 'deposit-addresses', 'withdrawals', 'orders', @@ -62758,6 +67220,8 @@ module.exports = class kucoin extends Exchange { 'commonCurrencies': { 'HOT': 'HOTNOW', 'EDGE': 'DADI', // https://github.com/ccxt/ccxt/issues/5756 + 'WAX': 'WAXP', + 'TRY': 'Trias', }, 'options': { 'version': 'v1', @@ -62766,6 +67230,23 @@ module.exports = class kucoin extends Exchange { 'fetchBalance': { 'type': 'trade', // or 'main' }, + // endpoint versions + 'versions': { + 'public': { + 'GET': { + 'market/orderbook/level{level}': 'v1', + 'market/orderbook/level2': 'v2', + 'market/orderbook/level2_20': 'v1', + 'market/orderbook/level2_100': 'v1', + }, + }, + 'private': { + 'POST': { + 'accounts/inner-transfer': 'v2', + 'accounts/sub-transfer': 'v2', + }, + }, + }, }, }); } @@ -62815,8 +67296,7 @@ module.exports = class kucoin extends Exchange { for (let i = 0; i < data.length; i++) { const market = data[i]; const id = this.safeString (market, 'symbol'); - const baseId = this.safeString (market, 'baseCurrency'); - const quoteId = this.safeString (market, 'quoteCurrency'); + const [ baseId, quoteId ] = id.split ('-'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const symbol = base + '/' + quote; @@ -62884,6 +67364,9 @@ module.exports = class kucoin extends Exchange { 'code': code, 'precision': precision, 'info': entry, + 'active': undefined, + 'fee': undefined, + 'limits': this.limits, }; } return result; @@ -63449,8 +67932,10 @@ module.exports = class kucoin extends Exchange { } } } + const clientOrderId = this.safeString (order, 'clientOid'); return { 'id': orderId, + 'clientOrderId': clientOrderId, 'symbol': symbol, 'type': type, 'side': side, @@ -63464,6 +67949,9 @@ module.exports = class kucoin extends Exchange { 'fee': fee, 'status': status, 'info': order, + 'lastTradeTimestamp': undefined, + 'average': undefined, + 'trades': undefined, }; } @@ -64188,7 +68676,11 @@ module.exports = class kucoin extends Exchange { // the v2 URL is https://openapi-v2.kucoin.com/api/v1/endpoint // † ↑ // - const version = this.safeString (params, 'version', this.options['version']); + const versions = this.safeValue (this.options, 'versions', {}); + const apiVersions = this.safeValue (versions, api); + const methodVersions = this.safeValue (apiVersions, method, {}); + const defaultVersion = this.safeString (methodVersions, path, this.options['version']); + const version = this.safeString (params, 'version', defaultVersion); params = this.omit (params, 'version'); let endpoint = '/api/' + version + '/' + this.implodeParams (path, params); const query = this.omit (params, this.extractParams (path)); @@ -64237,7 +68729,7 @@ module.exports = class kucoin extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],103:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],103:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -64343,6 +68835,8 @@ module.exports = class kuna extends acx { 'max': undefined, }, }, + 'active': undefined, + 'info': undefined, }); break; } @@ -64431,7 +68925,7 @@ module.exports = class kuna extends acx { } }; -},{"./acx.js":4,"./base/errors":9}],104:[function(require,module,exports){ +},{"./acx.js":4,"./base/errors":10}],104:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -64512,6 +69006,9 @@ module.exports = class lakebtc extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'info': market, + 'active': undefined, + 'precision': this.precision, + 'limits': this.limits, }); } return result; @@ -64717,7 +69214,7 @@ module.exports = class lakebtc extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],105:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],105:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -64812,6 +69309,7 @@ module.exports = class latoken extends Exchange { }, }, 'commonCurrencies': { + 'MT': 'Monarch', 'TSL': 'Treasure SL', }, 'options': { @@ -65367,8 +69865,10 @@ module.exports = class latoken extends Exchange { if ((timeFilled !== undefined) && (timeFilled > 0)) { lastTradeTimestamp = timeFilled; } + const clientOrderId = this.safeString (order, 'cliOrdId'); return { 'id': id, + 'clientOrderId': clientOrderId, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -65384,6 +69884,7 @@ module.exports = class latoken extends Exchange { 'average': undefined, 'remaining': remaining, 'fee': undefined, + 'trades': undefined, }; } @@ -65614,7 +70115,7 @@ module.exports = class latoken extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],106:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],106:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -66026,6 +70527,19 @@ module.exports = class lbank extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "symbol":"eth_btc", + // "amount":10.000000, + // "create_time":1484289832081, + // "price":5000.000000, + // "avg_price":5277.301200, + // "type":"sell", + // "order_id":"ab704110-af0d-48fd-a083-c218f19a4a55", + // "deal_amount":10.000000, + // "status":2 + // } + // let symbol = undefined; const responseMarket = this.safeValue (this.marketsById, order['symbol']); if (responseMarket !== undefined) { @@ -66056,6 +70570,7 @@ module.exports = class lbank extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -66071,6 +70586,7 @@ module.exports = class lbank extends Exchange { 'trades': undefined, 'fee': undefined, 'info': this.safeValue (order, 'info', order), + 'average': undefined, }; } @@ -66272,7 +70788,7 @@ module.exports = class lbank extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],107:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],107:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -66933,6 +71449,7 @@ module.exports = class liquid extends Exchange { const side = this.safeString (order, 'side'); return { 'id': orderId, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -67203,7 +71720,7 @@ module.exports = class liquid extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],108:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],108:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -67310,6 +71827,7 @@ module.exports = class livecoin extends Exchange { 'RUR': 'RUB', 'SCT': 'SpaceCoin', 'TPI': 'ThaneCoin', + 'WAX': 'WAXP', 'wETT': 'WETT', 'XBT': 'Bricktox', }, @@ -67460,6 +71978,9 @@ module.exports = class livecoin extends Exchange { 'max': Math.pow (10, precision), }, }, + 'id': undefined, + 'code': undefined, + 'name': undefined, }; const currencies = [ { 'id': 'USD', 'code': 'USD', 'name': 'US Dollar' }, @@ -67808,6 +72329,7 @@ module.exports = class livecoin extends Exchange { return { 'info': order, 'id': order['id'], + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -67826,6 +72348,7 @@ module.exports = class livecoin extends Exchange { 'currency': feeCurrency, 'rate': feeRate, }, + 'average': undefined, }; } @@ -68115,7 +72638,7 @@ module.exports = class livecoin extends Exchange { }; -},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],109:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],109:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -68221,6 +72744,9 @@ module.exports = class luno extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'info': market, + 'active': undefined, + 'precision': this.precision, + 'limits': this.limits, }); } return result; @@ -68263,6 +72789,23 @@ module.exports = class luno extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "base": "string", + // "completed_timestamp": "string", + // "counter": "string", + // "creation_timestamp": "string", + // "expiration_timestamp": "string", + // "fee_base": "string", + // "fee_counter": "string", + // "limit_price": "string", + // "limit_volume": "string", + // "order_id": "string", + // "pair": "string", + // "state": "PENDING", + // "type": "BID" + // } + // const timestamp = this.safeInteger (order, 'creation_timestamp'); const status = (order['state'] === 'PENDING') ? 'open' : 'closed'; const side = (order['type'] === 'ASK') ? 'sell' : 'buy'; @@ -68301,6 +72844,7 @@ module.exports = class luno extends Exchange { const id = this.safeString (order, 'order_id'); return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -68316,6 +72860,7 @@ module.exports = class luno extends Exchange { 'trades': undefined, 'fee': fee, 'info': order, + 'average': undefined, }; } @@ -68572,7 +73117,7 @@ module.exports = class luno extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],110:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],110:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -68830,6 +73375,8 @@ module.exports = class lykke extends Exchange { 'max': undefined, }, }, + 'baseId': undefined, + 'quoteId': undefined, }); } return result; @@ -68891,6 +73438,23 @@ module.exports = class lykke extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "Id": "string", + // "Status": "Unknown", + // "AssetPairId": "string", + // "Volume": 0, + // "Price": 0, + // "RemainingVolume": 0, + // "LastMatchTime": "2020-03-26T20:58:50.710Z", + // "CreatedAt": "2020-03-26T20:58:50.710Z", + // "Type": "Unknown", + // "LowerLimitPrice": 0, + // "LowerPrice": 0, + // "UpperLimitPrice": 0, + // "UpperPrice": 0 + // } + // const status = this.parseOrderStatus (this.safeString (order, 'Status')); let symbol = undefined; if (market === undefined) { @@ -68916,6 +73480,7 @@ module.exports = class lykke extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -68930,6 +73495,7 @@ module.exports = class lykke extends Exchange { 'remaining': remaining, 'status': status, 'fee': undefined, + 'trades': undefined, }; } @@ -69032,7 +73598,7 @@ module.exports = class lykke extends Exchange { } }; -},{"./base/Exchange":7}],111:[function(require,module,exports){ +},{"./base/Exchange":8}],111:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -69387,6 +73953,7 @@ module.exports = class mercado extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -69540,7 +74107,7 @@ module.exports = class mercado extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],112:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],112:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -69765,7 +74332,7 @@ module.exports = class mixcoins extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],113:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],113:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -69862,6 +74429,9 @@ module.exports = class oceanex extends Exchange { 'taker': 0.1 / 100, }, }, + 'commonCurrencies': { + 'PLA': 'Plair', + }, 'exceptions': { 'codes': { '-1': BadRequest, @@ -70321,6 +74891,23 @@ module.exports = class oceanex extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "created_at": "2019-01-18T00:38:18Z", + // "trades_count": 0, + // "remaining_volume": "0.2", + // "price": "1001.0", + // "created_on": "1547771898", + // "side": "buy", + // "volume": "0.2", + // "state": "wait", + // "ord_type": "limit", + // "avg_price": "0.0", + // "executed_volume": "0.0", + // "id": 473797, + // "market": "veteth" + // } + // const status = this.parseOrderStatus (this.safeValue (order, 'state')); const marketId = this.safeValue2 (order, 'market', 'market_id'); let symbol = undefined; @@ -70344,6 +74931,7 @@ module.exports = class oceanex extends Exchange { return { 'info': order, 'id': this.safeString (order, 'id'), + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -70457,1249 +75045,63 @@ module.exports = class oceanex extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],114:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],114:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- -const okcoinusd = require ('./okcoinusd.js'); +const okex = require ('./okex.js'); // --------------------------------------------------------------------------- -module.exports = class okcoincny extends okcoinusd { +module.exports = class okcoin extends okex { describe () { return this.deepExtend (super.describe (), { - 'id': 'okcoincny', - 'name': 'OKCoin CNY', - 'countries': [ 'CN' ], - 'has': { - 'CORS': false, - }, - 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/27766792-8be9157a-5ee5-11e7-926c-6d69b8d3378d.jpg', - 'api': { - 'web': 'https://www.okcoin.cn', - 'public': 'https://www.okcoin.cn/api', - 'private': 'https://www.okcoin.cn/api', - }, - 'www': 'https://www.okcoin.cn', - 'doc': 'https://www.okcoin.cn/rest_getStarted.html', - 'referral': 'https://www.okcoin.cn', - }, - 'markets': { - 'BTC/CNY': { 'id': 'btc_cny', 'symbol': 'BTC/CNY', 'base': 'BTC', 'quote': 'CNY', 'type': 'spot', 'spot': true, 'future': false }, - 'LTC/CNY': { 'id': 'ltc_cny', 'symbol': 'LTC/CNY', 'base': 'LTC', 'quote': 'CNY', 'type': 'spot', 'spot': true, 'future': false }, - 'ETH/CNY': { 'id': 'eth_cny', 'symbol': 'ETH/CNY', 'base': 'ETH', 'quote': 'CNY', 'type': 'spot', 'spot': true, 'future': false }, - 'ETC/CNY': { 'id': 'etc_cny', 'symbol': 'ETC/CNY', 'base': 'ETC', 'quote': 'CNY', 'type': 'spot', 'spot': true, 'future': false }, - 'BCH/CNY': { 'id': 'bcc_cny', 'symbol': 'BCH/CNY', 'base': 'BCH', 'quote': 'CNY', 'type': 'spot', 'spot': true, 'future': false }, - }, - }); - } -}; - -},{"./okcoinusd.js":115}],115:[function(require,module,exports){ -'use strict'; - -// --------------------------------------------------------------------------- - -const Exchange = require ('./base/Exchange'); -const { BadSymbol, ExchangeError, ArgumentsRequired, DDoSProtection, InsufficientFunds, InvalidOrder, OrderNotFound, AuthenticationError, BadRequest } = require ('./base/errors'); - -// --------------------------------------------------------------------------- - -module.exports = class okcoinusd extends Exchange { - describe () { - return this.deepExtend (super.describe (), { - 'id': 'okcoinusd', - 'name': 'OKCoin USD', + 'id': 'okcoin', + 'name': 'OKCoin', 'countries': [ 'CN', 'US' ], - 'version': 'v1', - 'rateLimit': 1000, // up to 3000 requests per 5 minutes ≈ 600 requests per minute ≈ 10 requests per second ≈ 100 ms - 'has': { - 'CORS': false, - 'fetchOHLCV': true, - 'fetchOrder': true, - 'fetchOrders': false, - 'fetchOpenOrders': true, - 'fetchClosedOrders': true, - 'fetchTickers': true, - 'withdraw': true, - 'futures': false, - }, - 'extension': '.do', // appended to endpoint URL - 'timeframes': { - '1m': '1min', - '3m': '3min', - '5m': '5min', - '15m': '15min', - '30m': '30min', - '1h': '1hour', - '2h': '2hour', - '4h': '4hour', - '6h': '6hour', - '12h': '12hour', - '1d': '1day', - '3d': '3day', - '1w': '1week', - }, - 'api': { - 'v3': { - 'get': [ - 'futures/pc/market/futuresCoin', - ], - }, - 'web': { - 'get': [ - 'futures/pc/market/marketOverview', - 'spot/markets/index-tickers', - 'spot/markets/currencies', - 'spot/markets/products', - 'spot/markets/tickers', - 'spot/user-level', - ], - 'post': [ - 'futures/pc/market/futuresCoin', - ], - }, - 'public': { - 'get': [ - 'depth', - 'exchange_rate', - 'future_depth', - 'future_estimated_price', - 'future_hold_amount', - 'future_index', - 'future_kline', - 'future_price_limit', - 'future_ticker', - 'future_trades', - 'kline', - 'otcs', - 'ticker', - 'tickers', - 'trades', - ], - }, - 'private': { - 'post': [ - 'account_records', - 'batch_trade', - 'borrow_money', - 'borrow_order_info', - 'borrows_info', - 'cancel_borrow', - 'cancel_order', - 'cancel_otc_order', - 'cancel_withdraw', - 'funds_transfer', - 'future_batch_trade', - 'future_cancel', - 'future_devolve', - 'future_explosive', - 'future_order_info', - 'future_orders_info', - 'future_position', - 'future_position_4fix', - 'future_trade', - 'future_trades_history', - 'future_userinfo', - 'future_userinfo_4fix', - 'lend_depth', - 'order_fee', - 'order_history', - 'order_info', - 'orders_info', - 'otc_order_history', - 'otc_order_info', - 'repayment', - 'submit_otc_order', - 'trade', - 'trade_history', - 'trade_otc_order', - 'wallet_info', - 'withdraw', - 'withdraw_info', - 'unrepayments_info', - 'userinfo', - ], - }, - }, + 'hostname': 'okcoin.com', + 'pro': true, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/27766791-89ffb502-5ee5-11e7-8a5b-c5950b68ac65.jpg', - 'api': { - 'v3': 'https://www.okcoin.com/v3', - 'web': 'https://www.okcoin.com/v2', - 'public': 'https://www.okcoin.com/api', - 'private': 'https://www.okcoin.com', - }, 'www': 'https://www.okcoin.com', - 'doc': [ - 'https://www.okcoin.com/docs/en/', - 'https://www.npmjs.com/package/okcoin.com', - ], + 'doc': 'https://www.okcoin.com/docs/en/', + 'fees': 'https://www.okcoin.com/coin-fees', 'referral': 'https://www.okcoin.com/account/register?flag=activity&channelId=600001513', - 'fees': 'https://support.okcoin.com/hc/en-us/articles/360015261532-OKCoin-Fee-Rates', }, - // these are okcoin.com fees, okex fees are in okex.js 'fees': { 'trading': { 'taker': 0.002, 'maker': 0.001, }, }, - 'exceptions': { - // see https://github.com/okcoin-okex/API-docs-OKEx.com/blob/master/API-For-Spot-EN/Error%20Code%20For%20Spot.md - '10000': ExchangeError, // "Required field, can not be null" - '10001': DDoSProtection, // "Request frequency too high to exceed the limit allowed" - '10005': AuthenticationError, // "'SecretKey' does not exist" - '10006': AuthenticationError, // "'Api_key' does not exist" - '10007': AuthenticationError, // "Signature does not match" - '1002': InsufficientFunds, // "The transaction amount exceed the balance" - '1003': InvalidOrder, // "The transaction amount is less than the minimum requirement" - '1004': InvalidOrder, // "The transaction amount is less than 0" - '1013': InvalidOrder, // no contract type (PR-1101) - '1027': InvalidOrder, // createLimitBuyOrder(symbol, 0, 0): Incorrect parameter may exceeded limits - '1050': InvalidOrder, // returned when trying to cancel an order that was filled or canceled previously - '1217': InvalidOrder, // "Order was sent at ±5% of the current market price. Please resend" - '10014': InvalidOrder, // "Order price must be between 0 and 1,000,000" - '1009': OrderNotFound, // for spot markets, cancelling closed order - '1019': OrderNotFound, // order closed? ("Undo order failed") - '1051': OrderNotFound, // for spot markets, cancelling "just closed" order - '10009': OrderNotFound, // for spot markets, "Order does not exist" - '20015': OrderNotFound, // for future markets - '10008': BadRequest, // Illegal URL parameter - '1007': BadSymbol, // No trading market information - // todo: sort out below - // 10000 Required parameter is empty - // 10001 Request frequency too high to exceed the limit allowed - // 10002 Authentication failure - // 10002 System error - // 10003 This connection has requested other user data - // 10004 Request failed - // 10005 api_key or sign is invalid, 'SecretKey' does not exist - // 10006 'Api_key' does not exist - // 10007 Signature does not match - // 10008 Illegal parameter, Parameter erorr - // 10009 Order does not exist - // 10010 Insufficient funds - // 10011 Amount too low - // 10012 Only btc_usd ltc_usd supported - // 10013 Only support https request - // 10014 Order price must be between 0 and 1,000,000 - // 10015 Order price differs from current market price too much / Channel subscription temporally not available - // 10016 Insufficient coins balance - // 10017 API authorization error / WebSocket authorization error - // 10018 borrow amount less than lower limit [usd:100,btc:0.1,ltc:1] - // 10019 loan agreement not checked - // 1002 The transaction amount exceed the balance - // 10020 rate cannot exceed 1% - // 10021 rate cannot less than 0.01% - // 10023 fail to get latest ticker - // 10024 balance not sufficient - // 10025 quota is full, cannot borrow temporarily - // 10026 Loan (including reserved loan) and margin cannot be withdrawn - // 10027 Cannot withdraw within 24 hrs of authentication information modification - // 10028 Withdrawal amount exceeds daily limit - // 10029 Account has unpaid loan, please cancel/pay off the loan before withdraw - // 1003 The transaction amount is less than the minimum requirement - // 10031 Deposits can only be withdrawn after 6 confirmations - // 10032 Please enabled phone/google authenticator - // 10033 Fee higher than maximum network transaction fee - // 10034 Fee lower than minimum network transaction fee - // 10035 Insufficient BTC/LTC - // 10036 Withdrawal amount too low - // 10037 Trade password not set - // 1004 The transaction amount is less than 0 - // 10040 Withdrawal cancellation fails - // 10041 Withdrawal address not exsit or approved - // 10042 Admin password error - // 10043 Account equity error, withdrawal failure - // 10044 fail to cancel borrowing order - // 10047 this function is disabled for sub-account - // 10048 withdrawal information does not exist - // 10049 User can not have more than 50 unfilled small orders (amount<0.15BTC) - // 10050 can't cancel more than once - // 10051 order completed transaction - // 10052 not allowed to withdraw - // 10064 after a USD deposit, that portion of assets will not be withdrawable for the next 48 hours - // 1008 No latest market information - // 1009 No order - // 1010 Different user of the cancelled order and the original order - // 10100 User account frozen - // 10101 order type is wrong - // 10102 incorrect ID - // 10103 the private otc order's key incorrect - // 10106 API key domain not matched - // 1011 No documented user - // 1013 No order type - // 1014 No login - // 1015 No market depth information - // 1017 Date error - // 1018 Order failed - // 1019 Undo order failed - // 10216 Non-available API / non-public API - // 1024 Currency does not exist - // 1025 No chart type - // 1026 No base currency quantity - // 1027 Incorrect parameter may exceeded limits - // 1028 Reserved decimal failed - // 1029 Preparing - // 1030 Account has margin and futures, transactions can not be processed - // 1031 Insufficient Transferring Balance - // 1032 Transferring Not Allowed - // 1035 Password incorrect - // 1036 Google Verification code Invalid - // 1037 Google Verification code incorrect - // 1038 Google Verification replicated - // 1039 Message Verification Input exceed the limit - // 1040 Message Verification invalid - // 1041 Message Verification incorrect - // 1042 Wrong Google Verification Input exceed the limit - // 1043 Login password cannot be same as the trading password - // 1044 Old password incorrect - // 1045 2nd Verification Needed - // 1046 Please input old password - // 1048 Account Blocked - // 1050 Orders have been withdrawn or withdrawn - // 1051 Order completed - // 1201 Account Deleted at 00: 00 - // 1202 Account Not Exist - // 1203 Insufficient Balance - // 1204 Invalid currency - // 1205 Invalid Account - // 1206 Cash Withdrawal Blocked - // 1207 Transfer Not Support - // 1208 No designated account - // 1209 Invalid api - // 1216 Market order temporarily suspended. Please send limit order - // 1217 Order was sent at ±5% of the current market price. Please resend - // 1218 Place order failed. Please try again later - // 20001 User does not exist - // 20002 Account frozen - // 20003 Account frozen due to forced liquidation - // 20004 Contract account frozen - // 20005 User contract account does not exist - // 20006 Required field missing - // 20007 Illegal parameter - // 20008 Contract account balance is too low - // 20009 Contract status error - // 20010 Risk rate ratio does not exist - // 20011 Risk rate lower than 90%/80% before opening BTC position with 10x/20x leverage. or risk rate lower than 80%/60% before opening LTC position with 10x/20x leverage - // 20012 Risk rate lower than 90%/80% after opening BTC position with 10x/20x leverage. or risk rate lower than 80%/60% after opening LTC position with 10x/20x leverage - // 20013 Temporally no counter party price - // 20014 System error - // 20015 Order does not exist - // 20016 Close amount bigger than your open positions, liquidation quantity bigger than holding - // 20017 Not authorized/illegal operation/illegal order ID - // 20018 Order price cannot be more than 103-105% or less than 95-97% of the previous minute price - // 20019 IP restricted from accessing the resource - // 20020 Secret key does not exist - // 20021 Index information does not exist - // 20022 Wrong API interface (Cross margin mode shall call cross margin API, fixed margin mode shall call fixed margin API) - // 20023 Account in fixed-margin mode - // 20024 Signature does not match - // 20025 Leverage rate error - // 20026 API Permission Error - // 20027 no transaction record - // 20028 no such contract - // 20029 Amount is large than available funds - // 20030 Account still has debts - // 20038 Due to regulation, this function is not availavle in the country/region your currently reside in. - // 20049 Request frequency too high - // 20100 request time out - // 20101 the format of data is error - // 20102 invalid login - // 20103 event type error - // 20104 subscription type error - // 20107 JSON format error - // 20115 The quote is not match - // 20116 Param not match - // 21020 Contracts are being delivered, orders cannot be placed - // 21021 Contracts are being settled, contracts cannot be placed - }, 'options': { - 'marketBuyPrice': false, - 'fetchOHLCVWarning': true, - 'contractTypes': { - '1': 'this_week', - '2': 'next_week', - '4': 'quarter', - }, - 'fetchTickersMethod': 'fetch_tickers_from_api', - }, - }); - } - - async fetchMarkets (params = {}) { - // TODO: they have a new fee schedule as of Feb 7 - // the new fees are progressive and depend on 30-day traded volume - // the following is the worst case - const result = []; - const spotResponse = await this.webGetSpotMarketsProducts (); - // - // { - // "code": 0, - // "data": [ - // { - // "baseCurrency":0, - // "brokerId":0, - // "callAuctionOrCallNoCancelAuction":false, - // "callNoCancelSwitchTime":{}, - // "collect":"0", - // "continuousSwitchTime":{}, - // "groupId":1, - // "isMarginOpen":true, - // "listDisplay":0, - // "marginRiskPreRatio":1.2, - // "marginRiskRatio":1.1, - // "marketFrom":118, - // "maxMarginLeverage":5, - // "maxPriceDigit":1, - // "maxSizeDigit":8, - // "mergeTypes":"0.1,1,10", - // "minTradeSize":0.00100000, - // "online":1, - // "productId":20, - // "quoteCurrency":7, - // "quoteIncrement":"0.1", - // "quotePrecision":2, - // "sort":30038, - // "symbol":"btc_usdt", - // "tradingMode":3 - // }, - // ] - // } - // - const spotMarkets = this.safeValue (spotResponse, 'data', []); - let markets = spotMarkets; - if (this.has['futures']) { - const futuresResponse = await this.v3GetFuturesPcMarketFuturesCoin ({ - 'currencyCode': 0, - }); - // - // { - // "msg":"success", - // "code":0, - // "detailMsg":"", - // "data": [ - // { - // "symbolId":0, - // "symbol":"f_usd_btc", - // "iceSingleAvgMinAmount":2, - // "minTradeSize":1, - // "iceSingleAvgMaxAmount":500, - // "contractDepthLevel":["0.01","0.2"], - // "dealAllMaxAmount":999, - // "maxSizeDigit":4, - // "contracts":[ - // { "marketFrom":34, "id":201905240000034, "type":1, "desc":"BTC0524" }, - // { "marketFrom":13, "id":201905310000013, "type":2, "desc":"BTC0531" }, - // { "marketFrom":12, "id":201906280000012, "type":4, "desc":"BTC0628" }, - // ], - // "maxPriceDigit":2, - // "nativeRate":1, - // "quote":"usd", - // "nativeCurrency":"usd", - // "nativeCurrencyMark":"$", - // "contractSymbol":0, - // "unitAmount":100.00, - // "symbolMark":"฿", - // "symbolDesc":"BTC" - // }, - // ] - // } - // - const data = this.safeValue (futuresResponse, 'data', {}); - const futuresMarkets = this.safeValue (data, 'usd', []); - markets = this.arrayConcat (spotMarkets, futuresMarkets); - } - for (let i = 0; i < markets.length; i++) { - const market = markets[i]; - const id = this.safeString (market, 'symbol'); - let symbol = undefined; - let base = undefined; - let quote = undefined; - let baseId = undefined; - let quoteId = undefined; - let baseNumericId = undefined; - let quoteNumericId = undefined; - let lowercaseId = undefined; - let uppercaseBaseId = undefined; - const precision = { - 'amount': this.safeInteger (market, 'maxSizeDigit'), - 'price': this.safeInteger (market, 'maxPriceDigit'), - }; - const minAmount = this.safeFloat (market, 'minTradeSize'); - const minPrice = Math.pow (10, -precision['price']); - let contracts = this.safeValue (market, 'contracts'); - if (contracts === undefined) { - // spot markets - lowercaseId = id; - const parts = id.split ('_'); - baseId = parts[0]; - quoteId = parts[1]; - baseNumericId = this.safeInteger (market, 'baseCurrency'); - quoteNumericId = this.safeInteger (market, 'quoteCurrency'); - base = this.safeCurrencyCode (baseId); - quote = this.safeCurrencyCode (quoteId); - contracts = [{}]; - } else { - // futures markets - quoteId = this.safeStringLower2 (market, 'quote', 'denomination'); - uppercaseBaseId = this.safeStringLower (market, 'symbolDesc'); - baseId = uppercaseBaseId.toLowerCase (); - lowercaseId = baseId + '_' + quoteId; - base = this.safeCurrencyCode (uppercaseBaseId); - quote = this.safeCurrencyCode (quoteId); - } - for (let k = 0; k < contracts.length; k++) { - const contract = contracts[k]; - let type = this.safeString (contract, 'type', 'spot'); - let contractType = undefined; - let spot = true; - let future = false; - let active = true; - if (type === 'spot') { - symbol = base + '/' + quote; - active = market['online'] !== 0; - } else { - const contractId = this.safeString (contract, 'id'); - symbol = base + '-' + quote + '-' + contractId.slice (2, 8); - contractType = this.safeString (this.options['contractTypes'], type); - type = 'future'; - spot = false; - future = true; - } - const fees = this.safeValue2 (this.fees, type, 'trading', {}); - result.push (this.extend (fees, { - 'id': id, - 'lowercaseId': lowercaseId, - 'contractType': contractType, - 'symbol': symbol, - 'base': base, - 'quote': quote, - 'baseId': baseId, - 'quoteId': quoteId, - 'baseNumericId': baseNumericId, - 'quoteNumericId': quoteNumericId, - 'info': market, - 'type': type, - 'spot': spot, - 'future': future, - 'active': active, - 'precision': precision, - 'limits': { - 'amount': { - 'min': minAmount, - 'max': undefined, - }, - 'price': { - 'min': minPrice, - 'max': undefined, - }, - 'cost': { - 'min': minAmount * minPrice, - 'max': undefined, - }, - }, - })); - } - } - return result; - } - - calculateFee (symbol, type, side, amount, price, takerOrMaker = 'taker', params = {}) { - const market = this.markets[symbol]; - let key = 'quote'; - const rate = market[takerOrMaker]; - let cost = parseFloat (this.costToPrecision (symbol, amount * rate)); - if (side === 'sell') { - cost *= price; - } else { - key = 'base'; - } - return { - 'type': takerOrMaker, - 'currency': market[key], - 'rate': rate, - 'cost': parseFloat (this.feeToPrecision (symbol, cost)), - }; - } - - async fetchTickersFromApi (symbols = undefined, params = {}) { - await this.loadMarkets (); - const request = {}; - const response = await this.publicGetTickers (this.extend (request, params)); - const tickers = response['tickers']; - const timestamp = this.safeTimestamp (response, 'date'); - const result = {}; - for (let i = 0; i < tickers.length; i++) { - let ticker = tickers[i]; - ticker = this.parseTicker (this.extend (tickers[i], { 'timestamp': timestamp })); - const symbol = ticker['symbol']; - result[symbol] = ticker; - } - return result; - } - - async fetchTickersFromWeb (symbols = undefined, params = {}) { - await this.loadMarkets (); - const request = {}; - const response = await this.webGetSpotMarketsTickers (this.extend (request, params)); - const tickers = this.safeValue (response, 'data'); - const result = {}; - for (let i = 0; i < tickers.length; i++) { - const ticker = this.parseTicker (tickers[i]); - const symbol = ticker['symbol']; - result[symbol] = ticker; - } - return result; - } - - async fetchTickers (symbols = undefined, params = {}) { - const method = this.options['fetchTickersMethod']; - return await this[method] (symbols, params); - } - - async fetchOrderBook (symbol = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['future'] ? 'publicGetFutureDepth' : 'publicGetDepth'; - const request = this.createRequest (market, params); - if (limit !== undefined) { - request['size'] = limit; - } - const response = await this[method] (request); - return this.parseOrderBook (response); - } - - parseTicker (ticker, market = undefined) { - // - // { buy: "48.777300", - // change: "-1.244500", - // changePercentage: "-2.47%", - // close: "49.064000", - // createdDate: 1531704852254, - // currencyId: 527, - // dayHigh: "51.012500", - // dayLow: "48.124200", - // high: "51.012500", - // inflows: "0", - // last: "49.064000", - // low: "48.124200", - // marketFrom: 627, - // name: { }, - // open: "50.308500", - // outflows: "0", - // productId: 527, - // sell: "49.064000", - // symbol: "zec_okb", - // volume: "1049.092535" } - // - const timestamp = this.safeInteger2 (ticker, 'timestamp', 'createdDate'); - let symbol = undefined; - if (market === undefined) { - if ('symbol' in ticker) { - const marketId = ticker['symbol']; - if (marketId in this.markets_by_id) { - market = this.markets_by_id[marketId]; - } else { - const [ baseId, quoteId ] = ticker['symbol'].split ('_'); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - symbol = base + '/' + quote; - } - } - } - if (market !== undefined) { - symbol = market['symbol']; - } - const last = this.safeFloat (ticker, 'last'); - const open = this.safeFloat (ticker, 'open'); - const change = this.safeFloat (ticker, 'change'); - const percentage = this.safeFloat (ticker, 'changePercentage'); - return { - 'symbol': symbol, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'high': this.safeFloat (ticker, 'high'), - 'low': this.safeFloat (ticker, 'low'), - 'bid': this.safeFloat (ticker, 'buy'), - 'bidVolume': undefined, - 'ask': this.safeFloat (ticker, 'sell'), - 'askVolume': undefined, - 'vwap': undefined, - 'open': open, - 'close': last, - 'last': last, - 'previousClose': undefined, - 'change': change, - 'percentage': percentage, - 'average': undefined, - 'baseVolume': this.safeFloat2 (ticker, 'vol', 'volume'), - 'quoteVolume': undefined, - 'info': ticker, - }; - } - - async fetchTicker (symbol = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['future'] ? 'publicGetFutureTicker' : 'publicGetTicker'; - const request = this.createRequest (market, params); - const response = await this[method] (request); - let ticker = this.safeValue (response, 'ticker'); - if (ticker === undefined) { - throw new ExchangeError (this.id + ' fetchTicker returned an empty response: ' + this.json (response)); - } - const timestamp = this.safeTimestamp (response, 'date'); - if (timestamp !== undefined) { - ticker = this.extend (ticker, { 'timestamp': timestamp }); - } - return this.parseTicker (ticker, market); - } - - parseTrade (trade, market = undefined) { - let symbol = undefined; - if (market) { - symbol = market['symbol']; - } - const timestamp = this.safeInteger (trade, 'date_ms'); - const id = this.safeString (trade, 'tid'); - const type = undefined; - const side = this.safeString (trade, 'type'); - const price = this.safeFloat (trade, 'price'); - const amount = this.safeFloat (trade, 'amount'); - let cost = undefined; - if (price !== undefined) { - if (amount !== undefined) { - cost = price * amount; - } - } - return { - 'id': id, - 'info': trade, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': symbol, - 'order': undefined, - 'type': type, - 'side': side, - 'takerOrMaker': undefined, - 'price': price, - 'amount': amount, - 'cost': cost, - 'fee': undefined, - }; - } - - async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['future'] ? 'publicGetFutureTrades' : 'publicGetTrades'; - const request = this.createRequest (market, params); - const response = await this[method] (request); - return this.parseTrades (response, market, since, limit); - } - - parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) { - const numElements = ohlcv.length; - const volumeIndex = (numElements > 6) ? 6 : 5; - return [ - ohlcv[0], // timestamp - parseFloat (ohlcv[1]), // Open - parseFloat (ohlcv[2]), // High - parseFloat (ohlcv[3]), // Low - parseFloat (ohlcv[4]), // Close - // parseFloat (ohlcv[5]), // quote volume - // parseFloat (ohlcv[6]), // base volume - parseFloat (ohlcv[volumeIndex]), // okex will return base volume in the 7th element for future markets - ]; - } - - async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['future'] ? 'publicGetFutureKline' : 'publicGetKline'; - const request = this.createRequest (market, { - 'type': this.timeframes[timeframe], - }); - if (since !== undefined) { - request['since'] = parseInt ((this.milliseconds () - 86400000) / 1000); // default last 24h - } - if (limit !== undefined) { - if (this.options['fetchOHLCVWarning']) { - throw new ExchangeError (this.id + ' fetchOHLCV counts "limit" candles backwards in chronological ascending order, therefore the "limit" argument for ' + this.id + ' is disabled. Set ' + this.id + '.options["fetchOHLCVWarning"] = false to suppress this warning message.'); - } - request['size'] = parseInt (limit); // max is 1440 candles - } - const response = await this[method] (this.extend (request, params)); - return this.parseOHLCVs (response, market, timeframe, since, limit); - } - - async fetchBalance (params = {}) { - await this.loadMarkets (); - const response = await this.privatePostUserinfo (params); - const info = this.safeValue (response, 'info', {}); - const balances = this.safeValue (info, 'funds', {}); - const result = { 'info': response }; - let ids = Object.keys (balances['free']); - let usedField = 'freezed'; - // wtf, okex? - // https://github.com/okcoin-okex/API-docs-OKEx.com/commit/01cf9dd57b1f984a8737ef76a037d4d3795d2ac7 - if (!(usedField in balances)) { - usedField = 'holds'; - } - const usedKeys = Object.keys (balances[usedField]); - ids = this.arrayConcat (ids, usedKeys); - for (let i = 0; i < ids.length; i++) { - const id = ids[i]; - const code = this.safeCurrencyCode (id); - const account = this.account (); - account['free'] = this.safeFloat (balances['free'], id); - account['used'] = this.safeFloat (balances[usedField], id); - result[code] = account; - } - return this.parseBalance (result); - } - - async createOrder (symbol, type, side, amount, price = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['future'] ? 'privatePostFutureTrade' : 'privatePostTrade'; - const orderSide = (type === 'market') ? (side + '_market') : side; - const isMarketBuy = ((market['spot']) && (type === 'market') && (side === 'buy') && (!this.options['marketBuyPrice'])); - const orderPrice = isMarketBuy ? this.safeFloat (params, 'cost') : price; - const request = this.createRequest (market, { - 'type': orderSide, - }); - if (market['future']) { - request['match_price'] = (type === 'market') ? 1 : 0; // match best counter party price? 0 or 1, ignores price if 1 - request['lever_rate'] = 10; // leverage rate value: 10 or 20 (10 by default) - request['type'] = (side === 'buy') ? '1' : '2'; - } else if (type === 'market') { - if (side === 'buy') { - if (!orderPrice) { - if (this.options['marketBuyPrice']) { - // eslint-disable-next-line quotes - throw new ExchangeError (this.id + " market buy orders require a price argument (the amount you want to spend or the cost of the order) when this.options['marketBuyPrice'] is true."); - } else { - // eslint-disable-next-line quotes - throw new ExchangeError (this.id + " market buy orders require an additional cost parameter, cost = price * amount. If you want to pass the cost of the market order (the amount you want to spend) in the price argument (the default " + this.id + " behaviour), set this.options['marketBuyPrice'] = true. It will effectively suppress this warning exception as well."); - } - } else { - request['price'] = orderPrice; - } - } else { - request['amount'] = amount; - } - } - if (type !== 'market') { - request['price'] = orderPrice; - request['amount'] = amount; - } - params = this.omit (params, 'cost'); - const response = await this[method] (this.extend (request, params)); - const timestamp = this.milliseconds (); - return { - 'info': response, - 'id': this.safeString (response, 'order_id'), - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'lastTradeTimestamp': undefined, - 'status': undefined, - 'symbol': symbol, - 'type': type, - 'side': side, - 'price': price, - 'amount': amount, - 'filled': undefined, - 'remaining': undefined, - 'cost': undefined, - 'trades': undefined, - 'fee': undefined, - }; - } - - async cancelOrder (id, symbol = undefined, params = {}) { - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument'); - } - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['future'] ? 'privatePostFutureCancel' : 'privatePostCancelOrder'; - const request = this.createRequest (market, { - 'order_id': id, - }); - const response = await this[method] (this.extend (request, params)); - return response; - } - - parseOrderStatus (status) { - const statuses = { - '-1': 'canceled', - '0': 'open', - '1': 'open', - '2': 'closed', - '3': 'open', - '4': 'canceled', - }; - return this.safeValue (statuses, status, status); - } - - parseOrderSide (side) { - if (side === 1) { - return 'buy'; // open long position - } else if (side === 2) { - return 'sell'; // open short position - } else if (side === 3) { - return 'sell'; // liquidate long position - } else if (side === 4) { - return 'buy'; // liquidate short position - } - return side; - } - - parseOrder (order, market = undefined) { - let side = undefined; - let type = undefined; - if ('type' in order) { - if ((order['type'] === 'buy') || (order['type'] === 'sell')) { - side = order['type']; - type = 'limit'; - } else if (order['type'] === 'buy_market') { - side = 'buy'; - type = 'market'; - } else if (order['type'] === 'sell_market') { - side = 'sell'; - type = 'market'; - } else { - side = this.parseOrderSide (order['type']); - if (('contract_name' in order) || ('lever_rate' in order)) { - type = 'margin'; - } - } - } - const status = this.parseOrderStatus (this.safeString (order, 'status')); - let symbol = undefined; - if (market === undefined) { - const marketId = this.safeString (order, 'symbol'); - if (marketId in this.markets_by_id) { - market = this.markets_by_id[marketId]; - } - } - if (market) { - symbol = market['symbol']; - } - const createDateField = this.getCreateDateField (); - const timestamp = this.safeInteger (order, createDateField); - let amount = this.safeFloat (order, 'amount'); - const filled = this.safeFloat (order, 'deal_amount'); - amount = Math.max (amount, filled); - let remaining = Math.max (0, amount - filled); - if (type === 'market') { - remaining = 0; - } - let average = this.safeFloat (order, 'avg_price'); - // https://github.com/ccxt/ccxt/issues/2452 - average = this.safeFloat (order, 'price_avg', average); - const cost = average * filled; - return { - 'info': order, - 'id': this.safeString (order, 'order_id'), - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'lastTradeTimestamp': undefined, - 'symbol': symbol, - 'type': type, - 'side': side, - 'price': this.safeFloat (order, 'price'), - 'average': average, - 'cost': cost, - 'amount': amount, - 'filled': filled, - 'remaining': remaining, - 'status': status, - 'fee': undefined, - }; - } - - getCreateDateField () { - // needed for derived exchanges - // allcoin typo create_data instead of create_date - return 'create_date'; - } - - getOrdersField () { - // needed for derived exchanges - // allcoin typo order instead of orders (expected based on their API docs) - return 'orders'; - } - - async fetchOrder (id, symbol = undefined, params = {}) { - if (symbol === undefined) { - throw new ExchangeError (this.id + ' fetchOrder requires a symbol argument'); - } - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['future'] ? 'privatePostFutureOrderInfo' : 'privatePostOrderInfo'; - const request = this.createRequest (market, { - 'order_id': id, - // 'status': 0, // 0 for unfilled orders, 1 for filled orders - // 'current_page': 1, // current page number - // 'page_length': 200, // number of orders returned per page, maximum 200 - }); - const response = await this[method] (this.extend (request, params)); - const ordersField = this.getOrdersField (); - const numOrders = response[ordersField].length; - if (numOrders > 0) { - return this.parseOrder (response[ordersField][0]); - } - throw new OrderNotFound (this.id + ' order ' + id + ' not found'); - } - - async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - if (symbol === undefined) { - throw new ExchangeError (this.id + ' fetchOrders requires a symbol argument'); - } - await this.loadMarkets (); - const market = this.market (symbol); - let method = market['future'] ? 'privatePostFutureOrdersInfo' : 'privatePost'; - let request = this.createRequest (market); - const order_id_in_params = ('order_id' in params); - if (market['future']) { - if (!order_id_in_params) { - throw new ExchangeError (this.id + ' fetchOrders() requires order_id param for futures market ' + symbol + ' (a string of one or more order ids, comma-separated)'); - } - } else { - const status = ('type' in params) ? params['type'] : params['status']; - if (typeof status === 'undefined') { - const name = order_id_in_params ? 'type' : 'status'; - throw new ExchangeError (this.id + ' fetchOrders() requires ' + name + ' param for spot market ' + symbol + ' (0 - for unfilled orders, 1 - for filled/canceled orders)'); - } - if (order_id_in_params) { - method += 'OrdersInfo'; - request = this.extend (request, { - 'type': status, - 'order_id': params['order_id'], - }); - } else { - method += 'OrderHistory'; - request = this.extend (request, { - 'status': status, - 'current_page': 1, // current page number - 'page_length': 200, // number of orders returned per page, maximum 200 - }); - } - params = this.omit (params, [ 'type', 'status' ]); - } - const response = await this[method] (this.extend (request, params)); - const ordersField = this.getOrdersField (); - return this.parseOrders (response[ordersField], market, since, limit); - } - - async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - const request = { - 'status': 0, // 0 for unfilled orders, 1 for filled orders - }; - return await this.fetchOrders (symbol, since, limit, this.extend (request, params)); - } - - async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - const request = { - 'status': 1, // 0 for unfilled orders, 1 for filled orders - }; - return await this.fetchOrders (symbol, since, limit, this.extend (request, params)); - } - - async withdraw (code, amount, address, tag = undefined, params = {}) { - this.checkAddress (address); - await this.loadMarkets (); - const currency = this.currency (code); - // if (amount < 0.01) - // throw new ExchangeError (this.id + ' withdraw() requires amount > 0.01'); - // for some reason they require to supply a pair of currencies for withdrawing one currency - const currencyId = currency['id'] + '_usd'; - if (tag) { - address = address + ':' + tag; - } - const request = { - 'symbol': currencyId, - 'withdraw_address': address, - 'withdraw_amount': amount, - 'target': 'address', // or 'okcn', 'okcom', 'okex' - }; - let query = params; - if ('chargefee' in query) { - request['chargefee'] = query['chargefee']; - query = this.omit (query, 'chargefee'); - } else { - throw new ExchangeError (this.id + ' withdraw() requires a `chargefee` parameter'); - } - if (this.password) { - request['trade_pwd'] = this.password; - } else if ('password' in query) { - request['trade_pwd'] = query['password']; - query = this.omit (query, 'password'); - } else if ('trade_pwd' in query) { - request['trade_pwd'] = query['trade_pwd']; - query = this.omit (query, 'trade_pwd'); - } - const passwordInRequest = ('trade_pwd' in request); - if (!passwordInRequest) { - throw new ExchangeError (this.id + ' withdraw() requires this.password set on the exchange instance or a password / trade_pwd parameter'); - } - const response = await this.privatePostWithdraw (this.extend (request, query)); - return { - 'info': response, - 'id': this.safeString (response, 'withdraw_id'), - }; - } - - sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = '/'; - const isWebApi = (api === 'web') || (api === 'v3'); - if (!isWebApi) { - url += this.version + '/'; - } - url += path; - if (!isWebApi) { - url += this.extension; - } - if (api === 'private') { - this.checkRequiredCredentials (); - const query = this.keysort (this.extend ({ - 'api_key': this.apiKey, - }, params)); - // secret key must be at the end of query - const queryString = this.rawencode (query) + '&secret_key=' + this.secret; - query['sign'] = this.hash (this.encode (queryString)).toUpperCase (); - body = this.urlencode (query); - headers = { 'Content-Type': 'application/x-www-form-urlencoded' }; - } else { - if (Object.keys (params).length) { - url += '?' + this.urlencode (params); - } - } - url = this.urls['api'][api] + url; - return { 'url': url, 'method': method, 'body': body, 'headers': headers }; - } - - createRequest (market, params = {}) { - if (market['future']) { - return this.deepExtend ({ - 'symbol': market['lowercaseId'], - 'contract_type': market['contractType'], - }, params); - } - return this.deepExtend ({ - 'symbol': market['id'], - }, params); - } - - handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { - if (response === undefined) { - return; // fallback to default error handler - } - if ('error_code' in response) { - const error = this.safeString (response, 'error_code'); - const message = this.id + ' ' + body; - this.throwExactlyMatchedException (this.exceptions, error, message); - throw new ExchangeError (message); - } - if ('result' in response) { - if (!response['result']) { - throw new ExchangeError (this.id + ' ' + body); - } - } - } -}; - -},{"./base/Exchange":7,"./base/errors":9}],116:[function(require,module,exports){ -'use strict'; - -// --------------------------------------------------------------------------- - -const okcoinusd = require ('./okcoinusd.js'); - -// --------------------------------------------------------------------------- - -module.exports = class okex extends okcoinusd { - describe () { - return this.deepExtend (super.describe (), { - 'id': 'okex', - 'name': 'OKEX', - 'countries': [ 'CN', 'US' ], - 'has': { - 'CORS': false, - 'futures': true, - 'fetchTickers': true, - }, - 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/32552768-0d6dd3c6-c4a6-11e7-90f8-c043b64756a7.jpg', - 'api': { - 'v3': 'https://www.okex.com/v3', - 'web': 'https://www.okex.com/v2', - 'public': 'https://www.okex.com/api', - 'private': 'https://www.okex.com/api', - }, - 'www': 'https://www.okex.com', - 'doc': [ - 'https://github.com/okcoin-okex/API-docs-OKEx.com', - 'https://www.okex.com/docs/en/', - ], - 'fees': 'https://www.okex.com/pages/products/fees.html', - 'referral': 'https://www.okex.com', - }, - 'fees': { - 'trading': { - 'taker': 0.0015, - 'maker': 0.0010, - }, - 'spot': { - 'taker': 0.0015, - 'maker': 0.0010, - }, - 'future': { - 'taker': 0.0005, - 'maker': 0.0002, - }, - 'swap': { - 'taker': 0.00075, - 'maker': 0.0002, - }, - }, - 'commonCurrencies': { - // OKEX refers to ERC20 version of Aeternity (AEToken) - 'AE': 'AET', // https://github.com/ccxt/ccxt/issues/4981 - 'HOT': 'Hydro Protocol', - 'HSR': 'HC', - 'MAG': 'Maggie', - 'YOYO': 'YOYOW', - 'WIN': 'WinToken', // https://github.com/ccxt/ccxt/issues/5701 + 'fetchMarkets': [ 'spot' ], }, }); } }; -},{"./okcoinusd.js":115}],117:[function(require,module,exports){ +},{"./okex.js":115}],115:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); const { ExchangeError, ExchangeNotAvailable, ArgumentsRequired, BadRequest, AccountSuspended, InvalidAddress, PermissionDenied, DDoSProtection, InsufficientFunds, InvalidNonce, CancelPending, InvalidOrder, OrderNotFound, AuthenticationError, RequestTimeout, NotSupported, BadSymbol } = require ('./base/errors'); +const { TICK_SIZE, TRUNCATE } = require ('./base/functions/number'); // --------------------------------------------------------------------------- -module.exports = class okex3 extends Exchange { +module.exports = class okex extends Exchange { describe () { return this.deepExtend (super.describe (), { - 'id': 'okex3', + 'id': 'okex', 'name': 'OKEX', 'countries': [ 'CN', 'US' ], 'version': 'v3', 'rateLimit': 1000, // up to 3000 requests per 5 minutes ≈ 600 requests per minute ≈ 10 requests per second ≈ 100 ms + 'pro': true, 'has': { 'CORS': false, 'fetchOHLCV': true, @@ -71712,7 +75114,7 @@ module.exports = class okex3 extends Exchange { 'fetchWithdrawals': true, 'fetchTime': true, 'fetchTransactions': false, - 'fetchMyTrades': false, // they don't have it + 'fetchMyTrades': true, 'fetchDepositAddress': true, 'fetchOrderTrades': true, 'fetchTickers': true, @@ -71734,12 +75136,16 @@ module.exports = class okex3 extends Exchange { '1d': '86400', '1w': '604800', }, + 'hostname': 'okex.com', 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/32552768-0d6dd3c6-c4a6-11e7-90f8-c043b64756a7.jpg', - 'api': 'https://www.okex.com', + 'api': { + 'rest': 'https://www.{hostname}', + }, 'www': 'https://www.okex.com', 'doc': 'https://www.okex.com/docs/en/', 'fees': 'https://www.okex.com/pages/products/fees.html', + 'referral': 'https://www.okex.com/join/1888677', }, 'api': { 'general': { @@ -71749,16 +75155,18 @@ module.exports = class okex3 extends Exchange { }, 'account': { 'get': [ - 'currencies', 'wallet', + 'sub-account', + 'asset-valuation', 'wallet/{currency}', - 'withdrawal/fee', 'withdrawal/history', 'withdrawal/history/{currency}', 'ledger', 'deposit/address', 'deposit/history', 'deposit/history/{currency}', + 'currencies', + 'withdrawal/fee', ], 'post': [ 'transfer', @@ -71774,6 +75182,7 @@ module.exports = class okex3 extends Exchange { 'orders_pending', 'orders/{order_id}', 'orders/{client_oid}', + 'trade_fee', 'fills', 'algo', // public @@ -71804,10 +75213,13 @@ module.exports = class okex3 extends Exchange { 'accounts/borrowed', 'accounts/{instrument_id}/borrowed', 'orders', + 'accounts/{instrument_id}/leverage', 'orders/{order_id}', 'orders/{client_oid}', 'orders_pending', 'fills', + // public + 'instruments/{instrument_id}/mark_price', ], 'post': [ 'accounts/borrow', @@ -71818,6 +75230,7 @@ module.exports = class okex3 extends Exchange { 'cancel_orders/{order_id}', 'cancel_orders/{client_oid}', 'cancel_batch_orders', + 'accounts/{instrument_id}/leverage', ], }, 'futures': { @@ -71825,14 +75238,17 @@ module.exports = class okex3 extends Exchange { 'position', '{instrument_id}/position', 'accounts', - 'accounts/{currency}', - 'accounts/{currency}/leverage', - 'accounts/{currency}/ledger', + 'accounts/{underlying}', + 'accounts/{underlying}/leverage', + 'accounts/{underlying}/ledger', 'order_algo/{instrument_id}', 'orders/{instrument_id}', 'orders/{instrument_id}/{order_id}', 'orders/{instrument_id}/{client_oid}', 'fills', + 'trade_fee', + 'accounts/{instrument_id}/holds', + 'order_algo/{instrument_id}', // public 'instruments', 'instruments/{instrument_id}/book', @@ -71840,27 +75256,26 @@ module.exports = class okex3 extends Exchange { 'instruments/{instrument_id}/ticker', 'instruments/{instrument_id}/trades', 'instruments/{instrument_id}/candles', - 'accounts/{instrument_id}/holds', 'instruments/{instrument_id}/index', 'rate', 'instruments/{instrument_id}/estimated_price', 'instruments/{instrument_id}/open_interest', 'instruments/{instrument_id}/price_limit', - 'instruments/{instrument_id}/liquidation', 'instruments/{instrument_id}/mark_price', + 'instruments/{instrument_id}/liquidation', ], 'post': [ - 'accounts/{currency}/leverage', - 'accounts/margin_mode', + 'accounts/{underlying}/leverage', 'order', 'orders', - 'order_algo', - 'cancel_algos', 'cancel_order/{instrument_id}/{order_id}', 'cancel_order/{instrument_id}/{client_oid}', 'cancel_batch_orders/{instrument_id}', + 'accounts/margin_mode', 'close_position', 'cancel_all', + 'order_algo', + 'cancel_algos', ], }, 'swap': { @@ -71871,12 +75286,13 @@ module.exports = class okex3 extends Exchange { '{instrument_id}/accounts', 'accounts/{instrument_id}/settings', 'accounts/{instrument_id}/ledger', - 'accounts/{instrument_id}/holds', - 'order_algo/{instrument_id}', 'orders/{instrument_id}', 'orders/{instrument_id}/{order_id}', 'orders/{instrument_id}/{client_oid}', 'fills', + 'accounts/{instrument_id}/holds', + 'trade_fee', + 'order_algo/{instrument_id}', // public 'instruments', 'instruments/{instrument_id}/depth', @@ -71896,28 +75312,48 @@ module.exports = class okex3 extends Exchange { 'post': [ 'accounts/{instrument_id}/leverage', 'order', - 'order_algo', 'orders', - 'cancel_algos', 'cancel_order/{instrument_id}/{order_id}', 'cancel_order/{instrument_id}/{client_oid}', 'cancel_batch_orders/{instrument_id}', + 'order_algo', + 'cancel_algos', ], }, - // they have removed this part from public - 'ett': { + 'option': { 'get': [ 'accounts', - 'accounts/{currency}', - 'accounts/{currency}/ledger', - 'orders', // fetchOrder, fetchOrders + '{underlying}/position', + 'accounts/{underlying}', + 'orders/{underlying}', + 'fills/{underlying}', + 'accounts/{underlying}/ledger', + 'trade_fee', + 'orders/{underlying}/{order_id}', + 'orders/{underlying}/{client_oid}', // public - 'constituents/{ett}', - 'define-price/{ett}', + 'underlying', + 'instruments/{underlying}', + 'instruments/{underlying}/summary', + 'instruments/{underlying}/summary/{instrument_id}', + 'instruments/{instrument_id}/book', + 'instruments/{instrument_id}/trades', + 'instruments/{instrument_id}/ticker', + 'instruments/{instrument_id}/candles', ], 'post': [ + 'order', 'orders', - 'orders/{order_id}', + 'cancel_order/{underlying}/{order_id}', + 'cancel_order/{underlying}/{client_oid}', + 'cancel_batch_orders/{underlying}', + 'amend_order/{underlying}', + 'amend_batch_orders/{underlying}', + ], + }, + 'index': { + 'get': [ + '{instrument_id}/constituents', ], }, }, @@ -71957,6 +75393,10 @@ module.exports = class okex3 extends Exchange { 'failure to get a peer from the ring-balancer': ExchangeNotAvailable, // { "message": "failure to get a peer from the ring-balancer" } '4010': PermissionDenied, // { "code": 4010, "message": "For the security of your funds, withdrawals are not permitted within 24 hours after changing fund password / mobile number / Google Authenticator settings " } // common + // '0': ExchangeError, // 200 successful,when the order placement / cancellation / operation is successful + '4001': ExchangeError, // no data received in 30s + '4002': ExchangeError, // Buffer full. cannot write data + // -------------------------------------------------------- '30001': AuthenticationError, // { "code": 30001, "message": 'request header "OK_ACCESS_KEY" cannot be blank'} '30002': AuthenticationError, // { "code": 30002, "message": 'request header "OK_ACCESS_SIGN" cannot be blank'} '30003': AuthenticationError, // { "code": 30003, "message": 'request header "OK_ACCESS_TIMESTAMP" cannot be blank'} @@ -72022,10 +75462,51 @@ module.exports = class okex3 extends Exchange { '32024': ExchangeError, // { "code": 32024, "message": "order cannot be placed during delivery" } '32025': ExchangeError, // { "code": 32025, "message": "order cannot be placed during settlement" } '32026': ExchangeError, // { "code": 32026, "message": "your account is restricted from opening positions" } - '32029': ExchangeError, // { "code": 32029, "message": "order info does not exist" } - '32028': ExchangeError, // { "code": 32028, "message": "account is suspended and liquidated" } '32027': ExchangeError, // { "code": 32027, "message": "cancelled over 20 orders" } + '32028': ExchangeError, // { "code": 32028, "message": "account is suspended and liquidated" } + '32029': ExchangeError, // { "code": 32029, "message": "order info does not exist" } + '32030': InvalidOrder, // The order cannot be cancelled + '32031': ArgumentsRequired, // client_oid or order_id is required. + '32038': AuthenticationError, // User does not exist + '32040': ExchangeError, // User have open contract orders or position '32044': ExchangeError, // { "code": 32044, "message": "The margin ratio after submitting this order is lower than the minimum requirement ({0}) for your tier." } + '32045': ExchangeError, // String of commission over 1 million + '32046': ExchangeError, // Each user can hold up to 10 trade plans at the same time + '32047': ExchangeError, // system error + '32048': InvalidOrder, // Order strategy track range error + '32049': ExchangeError, // Each user can hold up to 10 track plans at the same time + '32050': InvalidOrder, // Order strategy rang error + '32051': InvalidOrder, // Order strategy ice depth error + '32052': ExchangeError, // String of commission over 100 thousand + '32053': ExchangeError, // Each user can hold up to 6 ice plans at the same time + '32057': ExchangeError, // The order price is zero. Market-close-all function cannot be executed + '32054': ExchangeError, // Trade not allow + '32055': InvalidOrder, // cancel order error + '32056': ExchangeError, // iceberg per order average should between {0}-{1} contracts + '32058': ExchangeError, // Each user can hold up to 6 initiative plans at the same time + '32059': InvalidOrder, // Total amount should exceed per order amount + '32060': InvalidOrder, // Order strategy type error + '32061': InvalidOrder, // Order strategy initiative limit error + '32062': InvalidOrder, // Order strategy initiative range error + '32063': InvalidOrder, // Order strategy initiative rate error + '32064': ExchangeError, // Time Stringerval of orders should set between 5-120s + '32065': ExchangeError, // Close amount exceeds the limit of Market-close-all (999 for BTC, and 9999 for the rest tokens) + '32066': ExchangeError, // You have open orders. Please cancel all open orders before changing your leverage level. + '32067': ExchangeError, // Account equity < required margin in this setting. Please adjust your leverage level again. + '32068': ExchangeError, // The margin for this position will fall short of the required margin in this setting. Please adjust your leverage level or increase your margin to proceed. + '32069': ExchangeError, // Target leverage level too low. Your account balance is insufficient to cover the margin required. Please adjust the leverage level again. + '32070': ExchangeError, // Please check open position or unfilled order + '32071': ExchangeError, // Your current liquidation mode does not support this action. + '32072': ExchangeError, // The highest available margin for your order’s tier is {0}. Please edit your margin and place a new order. + '32073': ExchangeError, // The action does not apply to the token + '32074': ExchangeError, // The number of contracts of your position, open orders, and the current order has exceeded the maximum order limit of this asset. + '32075': ExchangeError, // Account risk rate breach + '32076': ExchangeError, // Liquidation of the holding position(s) at market price will require cancellation of all pending close orders of the contracts. + '32077': ExchangeError, // Your margin for this asset in futures account is insufficient and the position has been taken over for liquidation. (You will not be able to place orders, close positions, transfer funds, or add margin during this period of time. Your account will be restored after the liquidation is complete.) + '32078': ExchangeError, // Please cancel all open orders before switching the liquidation mode(Please cancel all open orders before switching the liquidation mode) + '32079': ExchangeError, // Your open positions are at high risk.(Please add margin or reduce positions before switching the mode) + '32080': ExchangeError, // Funds cannot be transferred out within 30 minutes after futures settlement + '32083': ExchangeError, // The number of contracts should be a positive multiple of %%. Please place your order again // token and margin trading '33001': PermissionDenied, // { "code": 33001, "message": "margin account for this pair is not enabled yet" } '33002': AccountSuspended, // { "code": 33002, "message": "margin account for this pair is suspended" } @@ -72056,9 +75537,32 @@ module.exports = class okex3 extends Exchange { '33028': InvalidOrder, // { "code": 33028, "message": "the decimal places of the trading price exceeded the limit" } '33029': InvalidOrder, // { "code": 33029, "message": "the decimal places of the trading size exceeded the limit" } '33034': ExchangeError, // { "code": 33034, "message": "You can only place limit order after Call Auction has started" } + '33035': ExchangeError, // This type of order cannot be canceled(This type of order cannot be canceled) + '33036': ExchangeError, // Exceeding the limit of entrust order + '33037': ExchangeError, // The buy order price should be lower than 130% of the trigger price + '33038': ExchangeError, // The sell order price should be higher than 70% of the trigger price + '33039': ExchangeError, // The limit of callback rate is 0 < x <= 5% + '33040': ExchangeError, // The trigger price of a buy order should be lower than the latest transaction price + '33041': ExchangeError, // The trigger price of a sell order should be higher than the latest transaction price + '33042': ExchangeError, // The limit of price variance is 0 < x <= 1% + '33043': ExchangeError, // The total amount must be larger than 0 + '33044': ExchangeError, // The average amount should be 1/1000 * total amount <= x <= total amount + '33045': ExchangeError, // The price should not be 0, including trigger price, order price, and price limit + '33046': ExchangeError, // Price variance should be 0 < x <= 1% + '33047': ExchangeError, // Sweep ratio should be 0 < x <= 100% + '33048': ExchangeError, // Per order limit: Total amount/1000 < x <= Total amount + '33049': ExchangeError, // Total amount should be X > 0 + '33050': ExchangeError, // Time interval should be 5 <= x <= 120s + '33051': ExchangeError, // cancel order number not higher limit: plan and track entrust no more than 10, ice and time entrust no more than 6 '33059': BadRequest, // { "code": 33059, "message": "client_oid or order_id is required" } '33060': BadRequest, // { "code": 33060, "message": "Only fill in either parameter client_oid or order_id" } + '33061': ExchangeError, // Value of a single market price order cannot exceed 100,000 USD + '33062': ExchangeError, // The leverage ratio is too high. The borrowed position has exceeded the maximum position of this leverage ratio. Please readjust the leverage ratio + '33063': ExchangeError, // Leverage multiple is too low, there is insufficient margin in the account, please readjust the leverage ratio + '33064': ExchangeError, // The setting of the leverage ratio cannot be less than 2, please readjust the leverage ratio + '33065': ExchangeError, // Leverage ratio exceeds maximum leverage ratio, please readjust leverage ratio // account + '21009': ExchangeError, // Funds cannot be transferred out within 30 minutes after swap settlement(Funds cannot be transferred out within 30 minutes after swap settlement) '34001': PermissionDenied, // { "code": 34001, "message": "withdrawal suspended" } '34002': InvalidAddress, // { "code": 34002, "message": "please add a withdrawal address" } '34003': ExchangeError, // { "code": 34003, "message": "sorry, this token cannot be withdrawn to xx at the moment" } @@ -72082,6 +75586,11 @@ module.exports = class okex3 extends Exchange { '34021': InvalidAddress, // { "code": 34021, "message": "Not verified address" } '34022': ExchangeError, // { "code": 34022, "message": "Withdrawals are not available for sub accounts" } '34023': PermissionDenied, // { "code": 34023, "message": "Please enable futures trading before transferring your funds" } + '34026': ExchangeError, // transfer too frequently(transfer too frequently) + '34036': ExchangeError, // Parameter is incorrect, please refer to API documentation + '34037': ExchangeError, // Get the sub-account balance interface, account type is not supported + '34038': ExchangeError, // Since your C2C transaction is unusual, you are restricted from fund transfer. Please contact our customer support to cancel the restriction + '34039': ExchangeError, // You are now restricted from transferring out your funds due to abnormal trades on C2C Market. Please transfer your fund on our website or app instead to verify your identity // swap '35001': ExchangeError, // { "code": 35001, "message": "Contract does not exist" } '35002': ExchangeError, // { "code": 35002, "message": "Contract settling" } @@ -72105,6 +75614,7 @@ module.exports = class okex3 extends Exchange { '35030': InvalidOrder, // { "code": 35030, "message": "Order size too large" } '35031': InvalidOrder, // { "code": 35031, "message": "Cancel order size too large" } '35032': ExchangeError, // { "code": 35032, "message": "Invalid user status" } + '35037': ExchangeError, // No last traded price in cache '35039': ExchangeError, // { "code": 35039, "message": "Open order quantity exceeds limit" } '35040': InvalidOrder, // {"error_message":"Invalid order type","result":"true","error_code":"35040","order_id":"-1"} '35044': ExchangeError, // { "code": 35044, "message": "Invalid order status" } @@ -72124,21 +75634,97 @@ module.exports = class okex3 extends Exchange { '35062': InvalidOrder, // { "code": 35062, "message": "Invalid match_price" } '35063': InvalidOrder, // { "code": 35063, "message": "Invalid order_size" } '35064': InvalidOrder, // { "code": 35064, "message": "Invalid client_oid" } + '35066': InvalidOrder, // Order interval error + '35067': InvalidOrder, // Time-weighted order ratio error + '35068': InvalidOrder, // Time-weighted order range error + '35069': InvalidOrder, // Time-weighted single transaction limit error + '35070': InvalidOrder, // Algo order type error + '35071': InvalidOrder, // Order total must be larger than single order limit + '35072': InvalidOrder, // Maximum 6 unfulfilled time-weighted orders can be held at the same time + '35073': InvalidOrder, // Order price is 0. Market-close-all not available + '35074': InvalidOrder, // Iceberg order single transaction average error + '35075': InvalidOrder, // Failed to cancel order + '35076': InvalidOrder, // LTC 20x leverage. Not allowed to open position + '35077': InvalidOrder, // Maximum 6 unfulfilled iceberg orders can be held at the same time + '35078': InvalidOrder, // Order amount exceeded 100,000 + '35079': InvalidOrder, // Iceberg order price variance error + '35080': InvalidOrder, // Callback rate error + '35081': InvalidOrder, // Maximum 10 unfulfilled trail orders can be held at the same time + '35082': InvalidOrder, // Trail order callback rate error + '35083': InvalidOrder, // Each user can only hold a maximum of 10 unfulfilled stop-limit orders at the same time + '35084': InvalidOrder, // Order amount exceeded 1 million + '35085': InvalidOrder, // Order amount is not in the correct range + '35086': InvalidOrder, // Price exceeds 100 thousand + '35087': InvalidOrder, // Price exceeds 100 thousand + '35088': InvalidOrder, // Average amount error + '35089': InvalidOrder, // Price exceeds 100 thousand + '35090': ExchangeError, // No stop-limit orders available for cancelation + '35091': ExchangeError, // No trail orders available for cancellation + '35092': ExchangeError, // No iceberg orders available for cancellation + '35093': ExchangeError, // No trail orders available for cancellation + '35094': ExchangeError, // Stop-limit order last traded price error + '35095': BadRequest, // Instrument_id error + '35096': ExchangeError, // Algo order status error + '35097': ExchangeError, // Order status and order ID cannot exist at the same time + '35098': ExchangeError, // An order status or order ID must exist + '35099': ExchangeError, // Algo order ID error + // option + '36001': BadRequest, // Invalid underlying index. + '36002': BadRequest, // Instrument does not exist. + '36005': ExchangeError, // Instrument status is invalid. + '36101': AuthenticationError, // Account does not exist. + '36102': PermissionDenied, // Account status is invalid. + '36103': PermissionDenied, // Account is suspended due to ongoing liquidation. + '36104': PermissionDenied, // Account is not enabled for options trading. + '36105': PermissionDenied, // Please enable the account for option contract. + '36106': PermissionDenied, // Funds cannot be transferred in or out, as account is suspended. + '36107': PermissionDenied, // Funds cannot be transferred out within 30 minutes after option exercising or settlement. + '36108': InsufficientFunds, // Funds cannot be transferred in or out, as equity of the account is less than zero. + '36109': PermissionDenied, // Funds cannot be transferred in or out during option exercising or settlement. + '36201': PermissionDenied, // New order function is blocked. + '36202': PermissionDenied, // Account does not have permission to short option. + '36203': InvalidOrder, // Invalid format for client_oid. + '36204': ExchangeError, // Invalid format for request_id. + '36205': BadRequest, // Instrument id does not match underlying index. + '36206': BadRequest, // Order_id and client_oid can not be used at the same time. + '36207': InvalidOrder, // Either order price or fartouch price must be present. + '36208': InvalidOrder, // Either order price or size must be present. + '36209': InvalidOrder, // Either order_id or client_oid must be present. + '36210': InvalidOrder, // Either order_ids or client_oids must be present. + '36211': InvalidOrder, // Exceeding max batch size for order submission. + '36212': InvalidOrder, // Exceeding max batch size for oder cancellation. + '36213': InvalidOrder, // Exceeding max batch size for order amendment. + '36214': ExchangeError, // Instrument does not have valid bid/ask quote. + '36216': OrderNotFound, // Order does not exist. + '36217': InvalidOrder, // Order submission failed. + '36218': InvalidOrder, // Order cancellation failed. + '36219': InvalidOrder, // Order amendment failed. + '36220': InvalidOrder, // Order is pending cancel. + '36221': InvalidOrder, // Order qty is not valid multiple of lot size. + '36222': InvalidOrder, // Order price is breaching highest buy limit. + '36223': InvalidOrder, // Order price is breaching lowest sell limit. + '36224': InvalidOrder, // Exceeding max order size. + '36225': InvalidOrder, // Exceeding max open order count for instrument. + '36226': InvalidOrder, // Exceeding max open order count for underlying. + '36227': InvalidOrder, // Exceeding max open size across all orders for underlying + '36228': InvalidOrder, // Exceeding max available qty for instrument. + '36229': InvalidOrder, // Exceeding max available qty for underlying. + '36230': InvalidOrder, // Exceeding max position limit for underlying. }, 'broad': { }, }, + 'precisionMode': TICK_SIZE, 'options': { 'createMarketBuyOrderRequiresPrice': true, - 'fetchMarkets': [ 'spot', 'futures', 'swap' ], - 'defaultType': 'spot', // 'account', 'spot', 'margin', 'futures', 'swap' + 'fetchMarkets': [ 'spot', 'futures', 'swap', 'option' ], + 'defaultType': 'spot', // 'account', 'spot', 'margin', 'futures', 'swap', 'option' 'auth': { 'time': 'public', 'currencies': 'private', 'instruments': 'public', 'rate': 'public', - 'constituents/{ett}': 'public', - 'define-price/{ett}': 'public', + '{instrument_id}/constituents': 'public', }, }, 'commonCurrencies': { @@ -72186,85 +75772,109 @@ module.exports = class okex3 extends Exchange { // // spot markets // - // [ { base_currency: "EOS", - // instrument_id: "EOS-OKB", - // min_size: "0.01", - // product_id: "EOS-OKB", - // quote_currency: "OKB", - // size_increment: "0.000001", - // tick_size: "0.0001" }, - // - // ..., // the spot endpoint also returns ETT instruments - // - // { base_currency: "OK06ETT", - // base_increment: "0.00000001", - // base_min_size: "0.01", - // instrument_id: "OK06ETT-USDT", - // min_size: "0.01", - // product_id: "OK06ETT-USDT", - // quote_currency: "USDT", - // quote_increment: "0.0001", - // size_increment: "0.00000001", - // tick_size: "0.0001" } ] + // { + // base_currency: "EOS", + // instrument_id: "EOS-OKB", + // min_size: "0.01", + // quote_currency: "OKB", + // size_increment: "0.000001", + // tick_size: "0.0001" + // } // // futures markets // - // [ { instrument_id: "BTG-USD-190329", - // underlying_index: "BTG", - // quote_currency: "USD", - // tick_size: "0.01", - // contract_val: "10", - // listing: "2018-12-14", - // delivery: "2019-03-29", - // trade_increment: "1" } ] + // { + // instrument_id: "XRP-USD-200320", + // underlying_index: "XRP", + // quote_currency: "USD", + // tick_size: "0.0001", + // contract_val: "10", + // listing: "2020-03-06", + // delivery: "2020-03-20", + // trade_increment: "1", + // alias: "this_week", + // underlying: "XRP-USD", + // base_currency: "XRP", + // settlement_currency: "XRP", + // is_inverse: "true", + // contract_val_currency: "USD", + // } // // swap markets // - // [ { instrument_id: "BTC-USD-SWAP", - // underlying_index: "BTC", - // quote_currency: "USD", - // coin: "BTC", - // contract_val: "100", - // listing: "2018-10-23T20:11:00.443Z", - // delivery: "2018-10-24T20:11:00.443Z", - // size_increment: "4", - // tick_size: "4" } ] + // { + // instrument_id: "BSV-USD-SWAP", + // underlying_index: "BSV", + // quote_currency: "USD", + // coin: "BSV", + // contract_val: "10", + // listing: "2018-12-21T07:53:47.000Z", + // delivery: "2020-03-14T08:00:00.000Z", + // size_increment: "1", + // tick_size: "0.01", + // base_currency: "BSV", + // underlying: "BSV-USD", + // settlement_currency: "BSV", + // is_inverse: "true", + // contract_val_currency: "USD" + // } + // + // options markets + // + // { + // instrument_id: 'BTC-USD-200327-4000-C', + // underlying: 'BTC-USD', + // settlement_currency: 'BTC', + // contract_val: '0.1000', + // option_type: 'C', + // strike: '4000', + // tick_size: '0.0005', + // lot_size: '1.0000', + // listing: '2019-12-25T08:30:36.302Z', + // delivery: '2020-03-27T08:00:00.000Z', + // state: '2', + // trading_start_time: '2019-12-25T08:30:36.302Z', + // timestamp: '2020-03-13T08:05:09.456Z', + // } // const id = this.safeString (market, 'instrument_id'); let marketType = 'spot'; let spot = true; let future = false; let swap = false; + let option = false; let baseId = this.safeString (market, 'base_currency'); + let quoteId = this.safeString (market, 'quote_currency'); const contractVal = this.safeFloat (market, 'contract_val'); if (contractVal !== undefined) { - marketType = 'swap'; - spot = false; - swap = true; - baseId = this.safeString (market, 'coin'); - const futuresAlias = this.safeString (market, 'alias'); - if (futuresAlias !== undefined) { - swap = false; - future = true; - marketType = 'futures'; - baseId = this.safeString (market, 'underlying_index'); + if ('option_type' in market) { + marketType = 'option'; + spot = false; + option = true; + const underlying = this.safeString (market, 'underlying'); + const parts = underlying.split ('-'); + baseId = this.safeString (parts, 0); + quoteId = this.safeString (parts, 1); + } else { + marketType = 'swap'; + spot = false; + swap = true; + const futuresAlias = this.safeString (market, 'alias'); + if (futuresAlias !== undefined) { + swap = false; + future = true; + marketType = 'futures'; + baseId = this.safeString (market, 'underlying_index'); + } } } - const quoteId = this.safeString (market, 'quote_currency'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const symbol = spot ? (base + '/' + quote) : id; - let amountPrecision = this.safeString (market, 'size_increment'); - if (amountPrecision !== undefined) { - amountPrecision = this.precisionFromString (amountPrecision); - } - let pricePrecision = this.safeString (market, 'tick_size'); - if (pricePrecision !== undefined) { - pricePrecision = this.precisionFromString (pricePrecision); - } + const lotSize = this.safeFloat2 (market, 'lot_size', 'trade_increment'); const precision = { - 'amount': amountPrecision, - 'price': pricePrecision, + 'amount': this.safeFloat (market, 'size_increment', lotSize), + 'price': this.safeFloat (market, 'tick_size'), }; const minAmount = this.safeFloat2 (market, 'min_size', 'base_min_size'); let minPrice = this.safeFloat (market, 'tick_size'); @@ -72289,6 +75899,7 @@ module.exports = class okex3 extends Exchange { 'spot': spot, 'futures': future, 'swap': swap, + 'option': option, 'active': active, 'precision': precision, 'limits': { @@ -72309,46 +75920,100 @@ module.exports = class okex3 extends Exchange { } async fetchMarketsByType (type, params = {}) { - const method = type + 'GetInstruments'; - const response = await this[method] (params); - // - // spot markets - // - // [ { base_currency: "EOS", - // base_increment: "0.000001", - // base_min_size: "0.01", - // instrument_id: "EOS-OKB", - // min_size: "0.01", - // product_id: "EOS-OKB", - // quote_currency: "OKB", - // quote_increment: "0.0001", - // size_increment: "0.000001", - // tick_size: "0.0001" } ] - // - // futures markets - // - // [ { instrument_id: "BTG-USD-190329", - // underlying_index: "BTG", - // quote_currency: "USD", - // tick_size: "0.01", - // contract_val: "10", - // listing: "2018-12-14", - // delivery: "2019-03-29", - // trade_increment: "1" } ] - // - // swap markets - // - // [ { instrument_id: "BTC-USD-SWAP", - // underlying_index: "BTC", - // quote_currency: "USD", - // coin: "BTC", - // contract_val: "100", - // listing: "2018-10-23T20:11:00.443Z", - // delivery: "2018-10-24T20:11:00.443Z", - // size_increment: "4", - // tick_size: "4" } ] - // - return this.parseMarkets (response); + if (type === 'option') { + const underlying = await this.optionGetUnderlying (params); + let result = []; + for (let i = 0; i < underlying.length; i++) { + const response = await this.optionGetInstrumentsUnderlying ({ + 'underlying': underlying[i], + }); + // + // options markets + // + // [ + // { + // instrument_id: 'BTC-USD-200327-4000-C', + // underlying: 'BTC-USD', + // settlement_currency: 'BTC', + // contract_val: '0.1000', + // option_type: 'C', + // strike: '4000', + // tick_size: '0.0005', + // lot_size: '1.0000', + // listing: '2019-12-25T08:30:36.302Z', + // delivery: '2020-03-27T08:00:00.000Z', + // state: '2', + // trading_start_time: '2019-12-25T08:30:36.302Z', + // timestamp: '2020-03-13T08:05:09.456Z', + // }, + // ] + // + result = this.arrayConcat (result, response); + } + return this.parseMarkets (result); + } else if ((type === 'spot') || (type === 'futures') || (type === 'swap')) { + const method = type + 'GetInstruments'; + const response = await this[method] (params); + // + // spot markets + // + // [ + // { + // base_currency: "EOS", + // instrument_id: "EOS-OKB", + // min_size: "0.01", + // quote_currency: "OKB", + // size_increment: "0.000001", + // tick_size: "0.0001" + // } + // ] + // + // futures markets + // + // [ + // { + // instrument_id: "XRP-USD-200320", + // underlying_index: "XRP", + // quote_currency: "USD", + // tick_size: "0.0001", + // contract_val: "10", + // listing: "2020-03-06", + // delivery: "2020-03-20", + // trade_increment: "1", + // alias: "this_week", + // underlying: "XRP-USD", + // base_currency: "XRP", + // settlement_currency: "XRP", + // is_inverse: "true", + // contract_val_currency: "USD", + // } + // ] + // + // swap markets + // + // [ + // { + // instrument_id: "BSV-USD-SWAP", + // underlying_index: "BSV", + // quote_currency: "USD", + // coin: "BSV", + // contract_val: "10", + // listing: "2018-12-21T07:53:47.000Z", + // delivery: "2020-03-14T08:00:00.000Z", + // size_increment: "1", + // tick_size: "0.01", + // base_currency: "BSV", + // underlying: "BSV-USD", + // settlement_currency: "BSV", + // is_inverse: "true", + // contract_val_currency: "USD" + // } + // ] + // + return this.parseMarkets (response); + } else { + throw new NotSupported (this.id + ' fetchMarketsByType does not support market type ' + type); + } } async fetchCurrencies (params = {}) { @@ -72453,6 +76118,7 @@ module.exports = class okex3 extends Exchange { const marketId = this.safeString (ticker, 'instrument_id'); if (marketId in this.markets_by_id) { market = this.markets_by_id[marketId]; + symbol = market['symbol']; } else if (marketId !== undefined) { const parts = marketId.split ('-'); const numParts = parts.length; @@ -72465,7 +76131,7 @@ module.exports = class okex3 extends Exchange { symbol = marketId; } } - if (market !== undefined) { + if ((symbol === undefined) && (market !== undefined)) { symbol = market['symbol']; } const last = this.safeFloat (ticker, 'last'); @@ -72477,9 +76143,9 @@ module.exports = class okex3 extends Exchange { 'high': this.safeFloat (ticker, 'high_24h'), 'low': this.safeFloat (ticker, 'low_24h'), 'bid': this.safeFloat (ticker, 'best_bid'), - 'bidVolume': undefined, + 'bidVolume': this.safeFloat (ticker, 'best_bid_size'), 'ask': this.safeFloat (ticker, 'best_ask'), - 'askVolume': undefined, + 'askVolume': this.safeFloat (ticker, 'best_ask_size'), 'vwap': undefined, 'open': open, 'close': last, @@ -72600,8 +76266,30 @@ module.exports = class okex3 extends Exchange { // } // let symbol = undefined; - if (market !== undefined) { + const marketId = this.safeString (trade, 'instrument_id'); + let base = undefined; + let quote = undefined; + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; symbol = market['symbol']; + base = market['base']; + quote = market['quote']; + } else if (marketId !== undefined) { + const parts = marketId.split ('-'); + const numParts = parts.length; + if (numParts === 2) { + const [ baseId, quoteId ] = parts; + base = this.safeCurrencyCode (baseId); + quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } else { + symbol = marketId; + } + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + base = market['base']; + quote = market['quote']; } const timestamp = this.parse8601 (this.safeString2 (trade, 'timestamp', 'created_at')); const price = this.safeFloat (trade, 'price'); @@ -72623,10 +76311,7 @@ module.exports = class okex3 extends Exchange { const feeCost = this.safeFloat (trade, 'fee'); let fee = undefined; if (feeCost !== undefined) { - let feeCurrency = undefined; - if (market !== undefined) { - feeCurrency = (side === 'buy') ? market['base'] : market['quote']; - } + const feeCurrency = (side === 'buy') ? base : quote; fee = { // fee is either a positive number (invitation rebate) // or a negative number (transaction fee deduction) @@ -73025,12 +76710,12 @@ module.exports = class okex3 extends Exchange { } async fetchBalance (params = {}) { - await this.loadMarkets (); const defaultType = this.safeString2 (this.options, 'fetchBalance', 'defaultType'); const type = this.safeString (params, 'type', defaultType); if (type === undefined) { throw new ArgumentsRequired (this.id + " fetchBalance requires a type parameter (one of 'account', 'spot', 'margin', 'futures', 'swap')"); } + await this.loadMarkets (); const suffix = (type === 'account') ? 'Wallet' : 'Accounts'; const method = type + 'Get' + suffix; const query = this.omit (params, 'type'); @@ -73160,6 +76845,10 @@ module.exports = class okex3 extends Exchange { // ] // } // + return this.parseBalanceByType (type, response); + } + + parseBalanceByType (type, response) { if ((type === 'account') || (type === 'spot')) { return this.parseAccountBalance (response); } else if (type === 'margin') { @@ -73214,10 +76903,13 @@ module.exports = class okex3 extends Exchange { notional = amount * price; } } else if (notional === undefined) { - throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'notional' extra parameter (the exchange-specific behaviour)"); + throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'amount' argument or in the 'notional' extra parameter (the exchange-specific behaviour)"); } + } else { + notional = (notional === undefined) ? amount : notional; } - request['notional'] = this.costToPrecision (symbol, notional); + const precision = market['precision']['price']; + request['notional'] = this.decimalToPrecision (notional, TRUNCATE, precision, this.precisionMode); } else { request['size'] = this.amountToPrecision (symbol, amount); } @@ -73253,6 +76945,8 @@ module.exports = class okex3 extends Exchange { 'cost': undefined, 'trades': undefined, 'fee': undefined, + 'clientOrderId': undefined, + 'average': undefined, }; } @@ -73460,9 +77154,11 @@ module.exports = class okex3 extends Exchange { 'currency': feeCurrency, }; } + const clientOrderId = this.safeString (order, 'client_oid'); return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -73477,6 +77173,7 @@ module.exports = class okex3 extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; } @@ -73952,25 +77649,162 @@ module.exports = class okex3 extends Exchange { }; } - async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { + parseMyTrade (pair, market = undefined) { + // check that trading symbols match in both entries + const first = pair[0]; + const second = pair[1]; + const firstMarketId = this.safeString (first, 'instrument_id'); + const secondMarketId = this.safeString (second, 'instrument_id'); + if (firstMarketId !== secondMarketId) { + throw new NotSupported (this.id + ' parseMyTrade() received unrecognized response format, differing instrument_ids in one fill, the exchange API might have changed, paste your verbose output: https://github.com/ccxt/ccxt/wiki/FAQ#what-is-required-to-get-help'); + } + const marketId = firstMarketId; + // determine the base and quote + let quoteId = undefined; + let symbol = undefined; + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + quoteId = market['quoteId']; + symbol = market['symbol']; + } else { + const parts = marketId.split ('-'); + quoteId = this.safeString (parts, 1); + symbol = marketId; + } + const id = this.safeString (first, 'trade_id'); + const price = this.safeFloat (first, 'price'); + // determine buy/sell side and amounts + // get the side from either the first trade or the second trade + let feeCost = this.safeFloat (first, 'fee'); + const index = (feeCost !== 0) ? 0 : 1; + const userTrade = this.safeValue (pair, index); + const otherTrade = this.safeValue (pair, 1 - index); + const receivedCurrencyId = this.safeString (userTrade, 'currency'); + let side = undefined; + let amount = undefined; + let cost = undefined; + if (receivedCurrencyId === quoteId) { + side = 'sell'; + amount = this.safeFloat (otherTrade, 'size'); + cost = this.safeFloat (userTrade, 'size'); + } else { + side = 'buy'; + amount = this.safeFloat (userTrade, 'size'); + cost = this.safeFloat (otherTrade, 'size'); + } + feeCost = (feeCost !== 0) ? feeCost : this.safeFloat (second, 'fee'); + const trade = this.safeValue (pair, index); + // + // simplified structures to show the underlying semantics + // + // // market/limit sell + // + // { + // "currency":"USDT", + // "fee":"-0.04647925", // ←--- fee in received quote currency + // "price":"129.13", // ←------ price + // "size":"30.98616393", // ←-- cost + // }, + // { + // "currency":"ETH", + // "fee":"0", + // "price":"129.13", + // "size":"0.23996099", // ←--- amount + // }, + // + // // market/limit buy + // + // { + // "currency":"ETH", + // "fee":"-0.00036049", // ←--- fee in received base currency + // "price":"129.16", // ←------ price + // "size":"0.240322", // ←----- amount + // }, + // { + // "currency":"USDT", + // "fee":"0", + // "price":"129.16", + // "size":"31.03998952", // ←-- cost + // } + // + const timestamp = this.parse8601 (this.safeString2 (trade, 'timestamp', 'created_at')); + let takerOrMaker = this.safeString2 (trade, 'exec_type', 'liquidity'); + if (takerOrMaker === 'M') { + takerOrMaker = 'maker'; + } else if (takerOrMaker === 'T') { + takerOrMaker = 'taker'; + } + let fee = undefined; + if (feeCost !== undefined) { + const feeCurrencyId = this.safeString (userTrade, 'currency'); + const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); + fee = { + // fee is either a positive number (invitation rebate) + // or a negative number (transaction fee deduction) + // therefore we need to invert the fee + // more about it https://github.com/ccxt/ccxt/issues/5909 + 'cost': -feeCost, + 'currency': feeCurrencyCode, + }; + } + const orderId = this.safeString (trade, 'order_id'); + return { + 'info': pair, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'symbol': symbol, + 'id': id, + 'order': orderId, + 'type': undefined, + 'takerOrMaker': takerOrMaker, + 'side': side, + 'price': price, + 'amount': amount, + 'cost': cost, + 'fee': fee, + }; + } + + parseMyTrades (trades, market = undefined, since = undefined, limit = undefined, params = {}) { + const grouped = this.groupBy (trades, 'trade_id'); + const tradeIds = Object.keys (grouped); + const result = []; + for (let i = 0; i < tradeIds.length; i++) { + const tradeId = tradeIds[i]; + const pair = grouped[tradeId]; + // make sure it has exactly 2 trades, no more, no less + const numTradesInPair = pair.length; + if (numTradesInPair === 2) { + const trade = this.parseMyTrade (pair); + result.push (trade); + } + } + let symbol = undefined; + if (market !== undefined) { + symbol = market['symbol']; + } + return this.filterBySymbolSinceLimit (result, symbol, since, limit); + } + + async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { // okex actually returns ledger entries instead of fills here, so each fill in the order // is represented by two trades with opposite buy/sell sides, not one :\ // this aspect renders the 'fills' endpoint unusable for fetchOrderTrades // until either OKEX fixes the API or we workaround this on our side somehow if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchOrderTrades requires a symbol argument'); + throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument'); } await this.loadMarkets (); const market = this.market (symbol); - if ((limit === undefined) || (limit > 100)) { + if ((limit !== undefined) && (limit > 100)) { limit = 100; } const request = { 'instrument_id': market['id'], - 'order_id': id, - // from: '1', // return the page after the specified page number - // to: '1', // return the page before the specified page number - 'limit': limit, // optional, number of results per request, default = maximum = 100 + // 'order_id': id, // string + // 'after': '1', // return the page after the specified page number + // 'before': '1', // return the page before the specified page number + // 'limit': limit, // optional, number of results per request, default = maximum = 100 }; const defaultType = this.safeString2 (this.options, 'fetchMyTrades', 'defaultType'); const type = this.safeString (params, 'type', defaultType); @@ -73978,43 +77812,87 @@ module.exports = class okex3 extends Exchange { const method = type + 'GetFills'; const response = await this[method] (this.extend (request, query)); // - // spot trades, margin trades - // // [ + // // sell // { - // "created_at":"2019-09-20T07:15:24.000Z", + // "created_at":"2020-03-29T11:55:25.000Z", + // "currency":"USDT", + // "exec_type":"T", + // "fee":"-0.04647925", + // "instrument_id":"ETH-USDT", + // "ledger_id":"10562924353", + // "liquidity":"T", + // "order_id":"4636470489136128", + // "price":"129.13", + // "product_id":"ETH-USDT", + // "side":"buy", + // "size":"30.98616393", + // "timestamp":"2020-03-29T11:55:25.000Z", + // "trade_id":"18551601" + // }, + // { + // "created_at":"2020-03-29T11:55:25.000Z", + // "currency":"ETH", // "exec_type":"T", // "fee":"0", // "instrument_id":"ETH-USDT", - // "ledger_id":"7173486113", + // "ledger_id":"10562924352", // "liquidity":"T", - // "order_id":"3553868136523776", - // "price":"217.59", + // "order_id":"4636470489136128", + // "price":"129.13", // "product_id":"ETH-USDT", // "side":"sell", - // "size":"0.04619899", - // "timestamp":"2019-09-20T07:15:24.000Z" - // } - // ] - // - // futures trades, swap trades - // - // [ + // "size":"0.23996099", + // "timestamp":"2020-03-29T11:55:25.000Z", + // "trade_id":"18551601" + // }, + // // buy // { - // "trade_id":"197429674631450625", - // "instrument_id":"EOS-USD-SWAP", - // "order_id":"6a-7-54d663a28-0", - // "price":"3.633", - // "order_qty":"1.0000", - // "fee":"-0.000551", - // "created_at":"2019-03-21T04:41:58.0Z", // missing in swap trades - // "timestamp":"2019-03-25T05:56:31.287Z", // missing in futures trades - // "exec_type":"M", // whether the order is taker or maker - // "side":"short", // "buy" in futures trades + // "created_at":"2020-03-29T11:55:16.000Z", + // "currency":"ETH", + // "exec_type":"T", + // "fee":"-0.00036049", + // "instrument_id":"ETH-USDT", + // "ledger_id":"10562922669", + // "liquidity":"T", + // "order_id": "4636469894136832", + // "price":"129.16", + // "product_id":"ETH-USDT", + // "side":"buy", + // "size":"0.240322", + // "timestamp":"2020-03-29T11:55:16.000Z", + // "trade_id":"18551600" + // }, + // { + // "created_at":"2020-03-29T11:55:16.000Z", + // "currency":"USDT", + // "exec_type":"T", + // "fee":"0", + // "instrument_id":"ETH-USDT", + // "ledger_id":"10562922668", + // "liquidity":"T", + // "order_id":"4636469894136832", + // "price":"129.16", + // "product_id":"ETH-USDT", + // "side":"sell", + // "size":"31.03998952", + // "timestamp":"2020-03-29T11:55:16.000Z", + // "trade_id":"18551600" // } // ] // - return this.parseTrades (response, market, since, limit); + return this.parseMyTrades (response, market, since, limit, params); + } + + async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { + const request = { + // 'instrument_id': market['id'], + 'order_id': id, + // 'after': '1', // return the page after the specified page number + // 'before': '1', // return the page before the specified page number + // 'limit': limit, // optional, number of results per request, default = maximum = 100 + }; + return await this.fetchMyTrades (symbol, since, limit, this.extend (request, params)); } async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) { @@ -74342,7 +78220,7 @@ module.exports = class okex3 extends Exchange { let request = '/api/' + api + '/' + this.version + '/'; request += isArray ? path : this.implodeParams (path, params); const query = isArray ? params : this.omit (params, this.extractParams (path)); - let url = this.urls['api'] + request; + let url = this.implodeParams (this.urls['api']['rest'], { 'hostname': this.hostname }) + request; const type = this.getPathAuthenticationType (path); if (type === 'public') { if (Object.keys (query).length) { @@ -74380,6 +78258,12 @@ module.exports = class okex3 extends Exchange { } getPathAuthenticationType (path) { + // https://github.com/ccxt/ccxt/issues/6651 + // a special case to handle the optionGetUnderlying interefering with + // other endpoints containing this keyword + if (path === 'underlying') { + return 'public'; + } const auth = this.safeValue (this.options, 'auth', {}); const key = this.findBroadlyMatchedKey (auth, path); return this.safeString (auth, key, 'private'); @@ -74388,7 +78272,8 @@ module.exports = class okex3 extends Exchange { handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { const feedback = this.id + ' ' + body; if (code === 503) { - throw new ExchangeError (feedback); + // {"message":"name resolution failed"} + throw new ExchangeNotAvailable (feedback); } if (!response) { return; // fallback to default error handler @@ -74398,15 +78283,17 @@ module.exports = class okex3 extends Exchange { if (message !== undefined) { this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback); this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback); - } - this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback); - if (message !== undefined) { - throw new ExchangeError (feedback); // unknown message + this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback); + const nonEmptyMessage = (message !== ''); + const nonZeroErrorCode = (errorCode !== undefined) && (errorCode !== '0'); + if (nonZeroErrorCode || nonEmptyMessage) { + throw new ExchangeError (feedback); // unknown message + } } } }; -},{"./base/Exchange":7,"./base/errors":9}],118:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],116:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -74654,7 +78541,7 @@ module.exports = class paymium extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],119:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],117:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -74672,6 +78559,7 @@ module.exports = class poloniex extends Exchange { 'countries': [ 'US' ], 'rateLimit': 1000, // up to 6 calls per second 'certified': true, // 2019-06-07 + 'pro': true, 'has': { 'CORS': false, 'createDepositAddress': true, @@ -74885,7 +78773,7 @@ module.exports = class poloniex extends Exchange { if (limit === undefined) { request['start'] = request['end'] - this.parseTimeframe ('1w'); // max range = 1 week } else { - request['start'] = request['end'] - this.sum (limit) * this.parseTimeframe (timeframe); + request['start'] = request['end'] - limit * this.parseTimeframe (timeframe); } } else { request['start'] = parseInt (since / 1000); @@ -75080,9 +78968,6 @@ module.exports = class poloniex extends Exchange { for (let i = 0; i < ids.length; i++) { const id = ids[i]; const currency = response[id]; - // todo: will need to rethink the fees - // to add support for multiple withdrawal/deposit methods and - // differentiated fees for each particular method const precision = 8; // default precision, todo: fix "magic constants" const code = this.safeCurrencyCode (id); const active = (currency['delisted'] === 0) && !currency['disabled']; @@ -75408,6 +79293,7 @@ module.exports = class poloniex extends Exchange { // }, // ], // 'fee': '0.00000000', + // 'clientOrderId': '12345', // 'currencyPair': 'BTC_MANA', // // --------------------------------------------------------- // // the following fields are injected by createOrder @@ -75494,9 +79380,11 @@ module.exports = class poloniex extends Exchange { 'currency': feeCurrencyCode, }; } + const clientOrderId = this.safeString (order, 'clientOrderId'); return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -76107,7 +79995,7 @@ module.exports = class poloniex extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],120:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],118:[function(require,module,exports){ 'use strict'; const Exchange = require ('./base/Exchange'); @@ -76652,6 +80540,7 @@ module.exports = class rightbtc extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -76666,6 +80555,7 @@ module.exports = class rightbtc extends Exchange { 'status': status, 'fee': fee, 'trades': trades, + 'average': undefined, }; } @@ -76870,7 +80760,7 @@ module.exports = class rightbtc extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],121:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10,"./base/functions/number":16}],119:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -76934,6 +80824,7 @@ module.exports = class southxchange extends Exchange { 'commonCurrencies': { 'SMT': 'SmartNode', 'MTC': 'Marinecoin', + 'BHD': 'Bithold', }, }); } @@ -76958,6 +80849,8 @@ module.exports = class southxchange extends Exchange { 'quoteId': quoteId, 'active': undefined, 'info': market, + 'precision': this.precision, + 'limits': this.limits, }); } return result; @@ -77118,6 +81011,7 @@ module.exports = class southxchange extends Exchange { const result = { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -77131,6 +81025,8 @@ module.exports = class southxchange extends Exchange { 'remaining': remaining, 'status': status, 'fee': undefined, + 'average': undefined, + 'trades': undefined, }; return result; } @@ -77234,7 +81130,7 @@ module.exports = class southxchange extends Exchange { } }; -},{"./base/Exchange":7}],122:[function(require,module,exports){ +},{"./base/Exchange":8}],120:[function(require,module,exports){ (function (module, exports) { 'use strict'; @@ -80762,7 +84658,7 @@ module.exports = class southxchange extends Exchange { }; })(typeof module === 'undefined' || module, this); -},{"buffer":180}],123:[function(require,module,exports){ +},{"buffer":179}],121:[function(require,module,exports){ ;(function (root, factory) { if (typeof exports === "object") { // CommonJS @@ -86751,7 +90647,7 @@ module.exports = class southxchange extends Exchange { return CryptoJS; })); -},{}],124:[function(require,module,exports){ +},{}],122:[function(require,module,exports){ 'use strict'; var elliptic = exports; @@ -86774,7 +90670,7 @@ elliptic.curves = require('./elliptic/curves'); // Protocols elliptic.ec = require('./elliptic/ec'); -},{"./elliptic/curve":127,"./elliptic/curves":130,"./elliptic/ec":131,"./elliptic/utils":135}],125:[function(require,module,exports){ +},{"./elliptic/curve":125,"./elliptic/curves":128,"./elliptic/ec":129,"./elliptic/utils":133}],123:[function(require,module,exports){ 'use strict'; var BN = require('../../../../BN/bn'); @@ -87151,7 +91047,7 @@ BasePoint.prototype.dblp = function dblp(k) { return r; }; -},{"../../../../BN/bn":122,"../../elliptic":124}],126:[function(require,module,exports){ +},{"../../../../BN/bn":120,"../../elliptic":122}],124:[function(require,module,exports){ 'use strict'; var curve = require('../curve'); @@ -87586,7 +91482,7 @@ Point.prototype.eqXToP = function eqXToP(x) { Point.prototype.toP = Point.prototype.normalize; Point.prototype.mixedAdd = Point.prototype.add; -},{"../../../../BN/bn":122,"../../elliptic":124,"../curve":127}],127:[function(require,module,exports){ +},{"../../../../BN/bn":120,"../../elliptic":122,"../curve":125}],125:[function(require,module,exports){ 'use strict'; var curve = exports; @@ -87596,7 +91492,7 @@ curve.short = require('./short'); curve.mont = require('./mont'); curve.edwards = require('./edwards'); -},{"./base":125,"./edwards":126,"./mont":128,"./short":129}],128:[function(require,module,exports){ +},{"./base":123,"./edwards":124,"./mont":126,"./short":127}],126:[function(require,module,exports){ 'use strict'; var curve = require('../curve'); @@ -87778,7 +91674,7 @@ Point.prototype.getX = function getX() { return this.x.fromRed(); }; -},{"../../../../BN/bn":122,"../../elliptic":124,"../curve":127}],129:[function(require,module,exports){ +},{"../../../../BN/bn":120,"../../elliptic":122,"../curve":125}],127:[function(require,module,exports){ 'use strict'; var curve = require('../curve'); @@ -88718,7 +92614,7 @@ JPoint.prototype.isInfinity = function isInfinity() { return this.z.cmpn(0) === 0; }; -},{"../../../../BN/bn":122,"../../elliptic":124,"../curve":127}],130:[function(require,module,exports){ +},{"../../../../BN/bn":120,"../../elliptic":122,"../curve":125}],128:[function(require,module,exports){ 'use strict'; var curves = exports; @@ -88924,7 +92820,7 @@ defineCurve('secp256k1', { ] }); -},{"../elliptic":124,"./precomputed/secp256k1":134}],131:[function(require,module,exports){ +},{"../elliptic":122,"./precomputed/secp256k1":132}],129:[function(require,module,exports){ 'use strict'; var BN = require('../../../../BN/bn'); @@ -89166,7 +93062,7 @@ EC.prototype.getKeyRecoveryParam = function(e, signature, Q, enc) { throw new Error('Unable to find valid recovery factor'); }; -},{"../../../../BN/bn":122,"../../elliptic":124,"../../hmac-drbg/hmac-drbg":136,"./key":132,"./signature":133}],132:[function(require,module,exports){ +},{"../../../../BN/bn":120,"../../elliptic":122,"../../hmac-drbg/hmac-drbg":134,"./key":130,"./signature":131}],130:[function(require,module,exports){ 'use strict'; var BN = require('../../../../BN/bn'); @@ -89287,7 +93183,7 @@ KeyPair.prototype.inspect = function inspect() { ' pub: ' + (this.pub && this.pub.inspect()) + ' >'; }; -},{"../../../../BN/bn":122,"../../elliptic":124}],133:[function(require,module,exports){ +},{"../../../../BN/bn":120,"../../elliptic":122}],131:[function(require,module,exports){ 'use strict'; var BN = require('../../../../BN/bn'); @@ -89313,7 +93209,7 @@ function Signature(options, enc) { } module.exports = Signature; -},{"../../../../BN/bn":122,"../../elliptic":124}],134:[function(require,module,exports){ +},{"../../../../BN/bn":120,"../../elliptic":122}],132:[function(require,module,exports){ module.exports = { doubles: { step: 4, @@ -90095,7 +93991,7 @@ module.exports = { } }; -},{}],135:[function(require,module,exports){ +},{}],133:[function(require,module,exports){ 'use strict'; var utils = exports; @@ -90253,7 +94149,7 @@ function wordArrayToBuffer(wordArray) { utils.wordArrayToBuffer = wordArrayToBuffer; -},{"../../../BN/bn":122}],136:[function(require,module,exports){ +},{"../../../BN/bn":120}],134:[function(require,module,exports){ 'use strict'; var CryptoJS = require('../../../crypto-js/crypto-js'); @@ -90369,7 +94265,7 @@ HmacDRBG.prototype.generate = function generate(len, enc, add, addEnc) { return utils.wordArrayToBuffer(res); }; -},{"../../../../base/functions/encode":12,"../../../crypto-js/crypto-js":123,"../elliptic/utils":135}],137:[function(require,module,exports){ +},{"../../../../base/functions/encode":13,"../../../crypto-js/crypto-js":121,"../elliptic/utils":133}],135:[function(require,module,exports){ 'use strict'; var fetch = require('../node-fetch/index'); @@ -90410,7 +94306,7 @@ module.exports = function (context) { }; }; -},{"../node-fetch/index":138}],138:[function(require,module,exports){ +},{"../node-fetch/index":136}],136:[function(require,module,exports){ (function (global,Buffer){ 'use strict'; @@ -91978,7 +95874,7 @@ exports.Response = Response; exports.FetchError = FetchError; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer) -},{"buffer":180,"http":222,"https":185,"stream":221,"url":228,"zlib":179}],139:[function(require,module,exports){ +},{"buffer":179,"http":221,"https":184,"stream":220,"url":227,"zlib":178}],137:[function(require,module,exports){ (function (Buffer){ /*! * RSA library for Node.js @@ -92205,7 +96101,7 @@ module.exports = (function () { })(); }).call(this,require("buffer").Buffer) -},{"./formats/formats.js":146,"./libs/rsa.js":150,"./schemes/schemes.js":152,"./utils":153,"buffer":180}],140:[function(require,module,exports){ +},{"./formats/formats.js":144,"./libs/rsa.js":148,"./schemes/schemes.js":150,"./utils":151,"buffer":179}],138:[function(require,module,exports){ // Copyright 2011 Mark Cavage All rights reserved. @@ -92220,7 +96116,7 @@ module.exports = { }; -},{}],141:[function(require,module,exports){ +},{}],139:[function(require,module,exports){ // Copyright 2011 Mark Cavage All rights reserved. var errors = require('./errors'); @@ -92243,7 +96139,7 @@ for (var e in errors) { module.exports[e] = errors[e]; } -},{"./errors":140,"./reader":142,"./types":143}],142:[function(require,module,exports){ +},{"./errors":138,"./reader":140,"./types":141}],140:[function(require,module,exports){ (function (Buffer){ // Copyright 2011 Mark Cavage All rights reserved. @@ -92509,7 +96405,7 @@ Reader.prototype._readTag = function (tag) { module.exports = Reader; }).call(this,require("buffer").Buffer) -},{"./errors":140,"./types":143,"assert":175,"buffer":180}],143:[function(require,module,exports){ +},{"./errors":138,"./types":141,"assert":174,"buffer":179}],141:[function(require,module,exports){ // Copyright 2011 Mark Cavage All rights reserved. @@ -92547,7 +96443,7 @@ module.exports = { Context: 128 }; -},{}],144:[function(require,module,exports){ +},{}],142:[function(require,module,exports){ // Copyright 2011 Mark Cavage All rights reserved. // If you have no idea what ASN.1 or BER is, see this: @@ -92566,7 +96462,7 @@ module.exports = { BerReader: Ber.Reader, }; -},{"./ber/index":141}],145:[function(require,module,exports){ +},{"./ber/index":139}],143:[function(require,module,exports){ var _ = require('../utils')._; var utils = require('../utils'); @@ -92639,7 +96535,7 @@ module.exports = { } }; -},{"../utils":153}],146:[function(require,module,exports){ +},{"../utils":151}],144:[function(require,module,exports){ var _ = require('../utils')._; module.exports = { @@ -92672,7 +96568,7 @@ module.exports = { }, }; -},{"../utils":153,"./components":145,"./pkcs1":147,"./pkcs8":148}],147:[function(require,module,exports){ +},{"../utils":151,"./components":143,"./pkcs1":145,"./pkcs8":146}],145:[function(require,module,exports){ (function (Buffer){ var ber = require('../asn1/index').Ber; var _ = require('../utils')._; @@ -92824,7 +96720,7 @@ module.exports = { }; }).call(this,require("buffer").Buffer) -},{"../asn1/index":144,"../utils":153,"buffer":180}],148:[function(require,module,exports){ +},{"../asn1/index":142,"../utils":151,"buffer":179}],146:[function(require,module,exports){ (function (Buffer){ var ber = require('../asn1/index').Ber; var _ = require('../utils')._; @@ -93015,7 +96911,7 @@ module.exports = { }; }).call(this,require("buffer").Buffer) -},{"../asn1/index":144,"../utils":153,"buffer":180}],149:[function(require,module,exports){ +},{"../asn1/index":142,"../utils":151,"buffer":179}],147:[function(require,module,exports){ (function (Buffer){ /* * Basic JavaScript BN library - subset useful for RSA encryption. @@ -94271,7 +98167,7 @@ BigInteger.prototype.square = bnSquare; module.exports = BigInteger; }).call(this,require("buffer").Buffer) -},{"../utils":153,"buffer":180}],150:[function(require,module,exports){ +},{"../utils":151,"buffer":179}],148:[function(require,module,exports){ /* * RSA Encryption / Decryption with PKCS1 v2 Padding. * @@ -94420,7 +98316,7 @@ module.exports.Key = (function () { })(); -},{"../schemes/schemes.js":152,"../utils":153,"../utils.js":153,"./jsbn.js":149}],151:[function(require,module,exports){ +},{"../schemes/schemes.js":150,"../utils":151,"../utils.js":151,"./jsbn.js":147}],149:[function(require,module,exports){ (function (Buffer){ /** * PKCS1 padding and signature scheme @@ -94600,7 +98496,7 @@ function wordArrayToBuffer(wordArray) { } }).call(this,require("buffer").Buffer) -},{"../../crypto-js/crypto-js":123,"../libs/jsbn":149,"buffer":180,"constants":182}],152:[function(require,module,exports){ +},{"../../crypto-js/crypto-js":121,"../libs/jsbn":147,"buffer":179,"constants":181}],150:[function(require,module,exports){ module.exports = { pkcs1: require('./pkcs1'), @@ -94623,7 +98519,7 @@ module.exports = { } }; -},{"./pkcs1":151}],153:[function(require,module,exports){ +},{"./pkcs1":149}],151:[function(require,module,exports){ /* * Utils functions * @@ -94723,7 +98619,7 @@ module.exports.trimSurroundingText = function (data, opening, closing) { return data.substring(trimStartIndex, trimEndIndex); } -},{}],154:[function(require,module,exports){ +},{}],152:[function(require,module,exports){ 'use strict'; var replace = String.prototype.replace; @@ -94743,7 +98639,7 @@ module.exports = { RFC3986: 'RFC3986' }; -},{}],155:[function(require,module,exports){ +},{}],153:[function(require,module,exports){ 'use strict'; var stringify = require('./stringify'); @@ -94756,7 +98652,7 @@ module.exports = { stringify: stringify }; -},{"./formats":154,"./parse":156,"./stringify":157}],156:[function(require,module,exports){ +},{"./formats":152,"./parse":154,"./stringify":155}],154:[function(require,module,exports){ 'use strict'; var utils = require('./utils'); @@ -95000,7 +98896,7 @@ module.exports = function (str, opts) { return utils.compact(obj); }; -},{"./utils":158}],157:[function(require,module,exports){ +},{"./utils":156}],155:[function(require,module,exports){ 'use strict'; var utils = require('./utils'); @@ -95271,7 +99167,7 @@ module.exports = function (object, opts) { return joined.length > 0 ? prefix + joined : ''; }; -},{"./formats":154,"./utils":158}],158:[function(require,module,exports){ +},{"./formats":152,"./utils":156}],156:[function(require,module,exports){ 'use strict'; var has = Object.prototype.hasOwnProperty; @@ -95503,7 +99399,7 @@ module.exports = { merge: merge }; -},{}],159:[function(require,module,exports){ +},{}],157:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -95681,6 +99577,9 @@ module.exports = class stex extends Exchange { 'maker': 0.002, }, }, + 'commonCurrencies': { + 'BHD': 'Bithold', + }, 'options': { 'parseOrderToPrecision': false, }, @@ -96010,7 +99909,7 @@ module.exports = class stex extends Exchange { let change = undefined; let percentage = undefined; if (last !== undefined) { - if (open !== undefined) { + if ((open !== undefined) && (open > 0)) { change = last - open; percentage = ((100 / open) * last) - 100; } @@ -96421,6 +100320,7 @@ module.exports = class stex extends Exchange { const result = { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -97300,7 +101200,7 @@ module.exports = class stex extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],160:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],158:[function(require,module,exports){ 'use strict'; // ---------------------------------------------------------------------------- @@ -97525,6 +101425,7 @@ module.exports = class stronghold extends Exchange { 'precision': precision, 'info': entry, 'limits': limits, + 'active': undefined, }; } return result; @@ -97582,6 +101483,7 @@ module.exports = class stronghold extends Exchange { 'active': undefined, 'name': undefined, 'limits': limits, + 'fee': undefined, }; } return result; @@ -97879,6 +101781,7 @@ module.exports = class stronghold extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'info': order, 'symbol': symbol, 'datetime': datetime, @@ -97894,6 +101797,7 @@ module.exports = class stronghold extends Exchange { 'status': undefined, 'type': undefined, 'average': undefined, + 'fee': undefined, }; } @@ -98089,7 +101993,7 @@ module.exports = class stronghold extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],161:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],159:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -98123,7 +102027,7 @@ module.exports = class surbitcoin extends foxbit { } }; -},{"./foxbit.js":86}],162:[function(require,module,exports){ +},{"./foxbit.js":85}],160:[function(require,module,exports){ 'use strict'; const Exchange = require ('./base/Exchange'); @@ -98260,16 +102164,16 @@ module.exports = class theocean extends Exchange { 'price': -parseInt (quoteToken['precision']), }; const amountLimits = { - 'min': this.fromWei (this.safeString (baseToken, 'minAmount'), 'ether', baseDecimals), - 'max': this.fromWei (this.safeString (baseToken, 'maxAmount'), 'ether', baseDecimals), + 'min': this.fromWei (this.safeString (baseToken, 'minAmount'), baseDecimals), + 'max': this.fromWei (this.safeString (baseToken, 'maxAmount'), baseDecimals), }; const priceLimits = { 'min': undefined, 'max': undefined, }; const costLimits = { - 'min': this.fromWei (this.safeString (quoteToken, 'minAmount'), 'ether', quoteDecimals), - 'max': this.fromWei (this.safeString (quoteToken, 'maxAmount'), 'ether', quoteDecimals), + 'min': this.fromWei (this.safeString (quoteToken, 'minAmount'), quoteDecimals), + 'max': this.fromWei (this.safeString (quoteToken, 'maxAmount'), quoteDecimals), }; const limits = { 'amount': amountLimits, @@ -98301,7 +102205,7 @@ module.exports = class theocean extends Exchange { this.safeFloat (ohlcv, 'high'), this.safeFloat (ohlcv, 'low'), this.safeFloat (ohlcv, 'close'), - this.fromWei (this.safeString (ohlcv, 'baseVolume'), 'ether', baseDecimals), + this.fromWei (this.safeString (ohlcv, 'baseVolume'), baseDecimals), ]; } @@ -98358,9 +102262,9 @@ module.exports = class theocean extends Exchange { // {"available":"0","committed":"0","total":"0"} // const decimals = this.safeInteger (this.options['decimals'], code, 18); - const free = this.fromWei (this.safeString (response, 'available'), 'ether', decimals); - const used = this.fromWei (this.safeString (response, 'committed'), 'ether', decimals); - const total = this.fromWei (this.safeString (response, 'total'), 'ether', decimals); + const free = this.fromWei (this.safeString (response, 'available'), decimals); + const used = this.fromWei (this.safeString (response, 'committed'), decimals); + const total = this.fromWei (this.safeString (response, 'total'), decimals); return { 'free': free, 'used': used, @@ -98471,7 +102375,7 @@ module.exports = class theocean extends Exchange { base = market['base']; } const baseDecimals = this.safeInteger (this.options['decimals'], base, 18); - const baseVolume = this.fromWei (this.safeString (ticker, 'volume'), 'ether', baseDecimals); + const baseVolume = this.fromWei (this.safeString (ticker, 'volume'), baseDecimals); const last = this.safeFloat (ticker, 'last'); return { 'symbol': symbol, @@ -98578,7 +102482,7 @@ module.exports = class theocean extends Exchange { base = market['base']; } const baseDecimals = this.safeInteger (this.options['decimals'], base, 18); - const amount = this.fromWei (this.safeString (trade, 'amount'), 'ether', baseDecimals); + const amount = this.fromWei (this.safeString (trade, 'amount'), baseDecimals); let cost = undefined; if (amount !== undefined && price !== undefined) { cost = amount * price; @@ -98663,7 +102567,7 @@ module.exports = class theocean extends Exchange { 'baseTokenAddress': market['baseId'], // Base token address 'quoteTokenAddress': market['quoteId'], // Quote token address 'side': side, // "buy" or "sell" - 'amount': this.toWei (this.amountToPrecision (symbol, amount), 'ether', baseDecimals), // Base token amount in wei + 'amount': this.toWei (this.amountToPrecision (symbol, amount), baseDecimals), // Base token amount in wei }; let method = undefined; if (type === 'limit') { @@ -98749,13 +102653,13 @@ module.exports = class theocean extends Exchange { } const baseDecimals = this.safeInteger (this.options['decimals'], base, 18); const price = this.safeFloat (order, 'price'); - const filledAmount = this.fromWei (this.safeString (order, 'filledAmount'), 'ether', baseDecimals); - const settledAmount = this.fromWei (this.safeString (order, 'settledAmount'), 'ether', baseDecimals); - const confirmedAmount = this.fromWei (this.safeString (order, 'confirmedAmount'), 'ether', baseDecimals); - const failedAmount = this.fromWei (this.safeString (order, 'failedAmount'), 'ether', baseDecimals); - const deadAmount = this.fromWei (this.safeString (order, 'deadAmount'), 'ether', baseDecimals); - const prunedAmount = this.fromWei (this.safeString (order, 'prunedAmount'), 'ether', baseDecimals); - const amount = this.fromWei (this.safeString (order, 'initialAmount'), 'ether', baseDecimals); + const filledAmount = this.fromWei (this.safeString (order, 'filledAmount'), baseDecimals); + const settledAmount = this.fromWei (this.safeString (order, 'settledAmount'), baseDecimals); + const confirmedAmount = this.fromWei (this.safeString (order, 'confirmedAmount'), baseDecimals); + const failedAmount = this.fromWei (this.safeString (order, 'failedAmount'), baseDecimals); + const deadAmount = this.fromWei (this.safeString (order, 'deadAmount'), baseDecimals); + const prunedAmount = this.fromWei (this.safeString (order, 'prunedAmount'), baseDecimals); + const amount = this.fromWei (this.safeString (order, 'initialAmount'), baseDecimals); const filled = this.sum (filledAmount, settledAmount, confirmedAmount); let remaining = undefined; let lastTradeTimestamp = undefined; @@ -98815,7 +102719,7 @@ module.exports = class theocean extends Exchange { } const feeDecimals = this.safeInteger (this.options['decimals'], feeCurrency, 18); fee = { - 'cost': this.fromWei (feeCost, 'ether', feeDecimals), + 'cost': this.fromWei (feeCost, feeDecimals), 'currency': feeCurrency, }; } @@ -98832,6 +102736,7 @@ module.exports = class theocean extends Exchange { const result = { 'info': order, 'id': id, + 'clientOrderId': undefined, 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -98846,6 +102751,7 @@ module.exports = class theocean extends Exchange { 'status': status, 'fee': fee, 'trades': trades, + 'average': undefined, }; return result; } @@ -99036,7 +102942,7 @@ module.exports = class theocean extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],163:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],161:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -99995,6 +103901,7 @@ module.exports = class therock extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -100266,7 +104173,7 @@ module.exports = class therock extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],164:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],162:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -100286,7 +104193,7 @@ module.exports = class tidebit extends Exchange { 'version': 'v2', 'has': { 'fetchDepositAddress': true, - 'CORS': true, + 'CORS': false, 'fetchTickers': true, 'fetchOHLCV': true, 'withdraw': true, @@ -100426,6 +104333,9 @@ module.exports = class tidebit extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'info': market, + 'active': undefined, + 'precision': this.precision, + 'limits': this.limits, }); } return result; @@ -100611,6 +104521,41 @@ module.exports = class tidebit extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "id": 7, // 唯一的 Order ID + // "side": "sell", // Buy/Sell 代表买单/卖单 + // "price": "3100.0", // 出价 + // "avg_price": "3101.2", // 平均成交价 + // "state": "wait", // 订单的当前状态 [wait,done,cancel] + // // wait 表明订单正在市场上挂单 + // // 是一个active order + // // 此时订单可能部分成交或者尚未成交 + // // done 代表订单已经完全成交 + // // cancel 代表订单已经被撤销 + // "market": "btccny", // 订单参与的交易市场 + // "created_at": "2014-04-18T02:02:33Z", // 下单时间 ISO8601格式 + // "volume": "100.0", // 购买/卖出数量 + // "remaining_volume": "89.8", // 还未成交的数量 remaining_volume 总是小于等于 volume + // // 在订单完全成交时变成 0 + // "executed_volume": "10.2", // 已成交的数量 + // // volume = remaining_volume + executed_volume + // "trades_count": 1, // 订单的成交数 整数值 + // // 未成交的订单为 0 有一笔成交的订单为 1 + // // 通过该字段可以判断订单是否处于部分成交状态 + // "trades": [ // 订单的详细成交记录 参见Trade + // // 注意: 只有某些返回详细订单数据的 API 才会包含 Trade 数据 + // { + // "id": 2, + // "price": "3100.0", + // "volume": "10.2", + // "market": "btccny", + // "created_at": "2014-04-18T02:04:49Z", + // "side": "sell" + // } + // ] + // } + // let symbol = undefined; if (market !== undefined) { symbol = market['symbol']; @@ -100635,6 +104580,7 @@ module.exports = class tidebit extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -100650,6 +104596,7 @@ module.exports = class tidebit extends Exchange { 'trades': undefined, 'fee': undefined, 'info': order, + 'average': undefined, }; } @@ -100759,7 +104706,7 @@ module.exports = class tidebit extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],165:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],163:[function(require,module,exports){ 'use strict'; const Exchange = require ('./base/Exchange'); @@ -100926,11 +104873,11 @@ module.exports = class tidex extends Exchange { 'max': undefined, }, 'withdraw': { - 'min': currency['withdrawMinAmout'], + 'min': this.safeFloat (currency, 'withdrawMinAmount'), 'max': undefined, }, 'deposit': { - 'min': currency['depositMinAmount'], + 'min': this.safeFloat (currency, 'depositMinAmount'), 'max': undefined, }, }, @@ -101290,9 +105237,13 @@ module.exports = class tidex extends Exchange { 'filled': filled, 'fee': undefined, // 'trades': this.parseTrades (order['trades'], market), + 'info': response, + 'clientOrderId': undefined, + 'average': undefined, + 'trades': undefined, }; this.orders[id] = order; - return this.extend ({ 'info': response }, order); + return order; } async cancelOrder (id, symbol = undefined, params = {}) { @@ -101368,6 +105319,9 @@ module.exports = class tidex extends Exchange { 'filled': filled, 'status': status, 'fee': fee, + 'clientOrderId': undefined, + 'average': undefined, + 'trades': undefined, }; } @@ -101615,7 +105569,7 @@ module.exports = class tidex extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],166:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],164:[function(require,module,exports){ 'use strict'; const Exchange = require ('./base/Exchange'); @@ -102793,9 +106747,11 @@ module.exports = class timex extends Exchange { lastTradeTimestamp = trades[numTrades - 1]['timestamp']; } } + const clientOrderId = this.safeString (order, 'clientOrderId'); return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -102852,13 +106808,40 @@ module.exports = class timex extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],167:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],165:[function(require,module,exports){ +'use strict'; + +// --------------------------------------------------------------------------- + +const bw = require ('./bw.js'); + +// --------------------------------------------------------------------------- + +module.exports = class topq extends bw { + describe () { + return this.deepExtend (super.describe (), { + 'id': 'topq', + 'countries': [ 'SG' ], + 'name': 'TOP.Q', + 'hostname': 'topliq.com', + 'urls': { + 'logo': 'https://user-images.githubusercontent.com/1294454/74596147-50247000-505c-11ea-9224-4fd347cfbb49.jpg', + 'api': 'https://www.{hostname}', + 'www': 'https://www.topliq.com', + 'doc': 'https://github.com/topq-exchange/api_docs_en/wiki/REST_api_reference', + 'fees': 'https://www.topliq.com/feesRate', + }, + }); + } +}; + +},{"./bw.js":56}],166:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, BadRequest, AuthenticationError, InvalidOrder, InsufficientFunds, OrderNotFound, PermissionDenied } = require ('./base/errors'); +const { ExchangeError, BadRequest, AuthenticationError, InvalidOrder, InsufficientFunds, OrderNotFound, PermissionDenied, AddressPending } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -102871,6 +106854,7 @@ module.exports = class upbit extends Exchange { 'version': 'v1', 'rateLimit': 1000, 'certified': true, + 'pro': true, // new metainfo interface 'has': { 'CORS': true, @@ -102905,7 +106889,10 @@ module.exports = class upbit extends Exchange { 'hostname': 'api.upbit.com', 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/49245610-eeaabe00-f423-11e8-9cba-4b0aed794799.jpg', - 'api': 'https://{hostname}', + 'api': { + 'public': 'https://{hostname}', + 'private': 'https://{hostname}', + }, 'www': 'https://upbit.com', 'doc': 'https://docs.upbit.com/docs/%EC%9A%94%EC%B2%AD-%EC%88%98-%EC%A0%9C%ED%95%9C', 'fees': 'https://upbit.com/service_center/guide', @@ -103394,7 +107381,7 @@ module.exports = class upbit extends Exchange { // timestamp: 1542883543813 } // const timestamp = this.safeInteger (ticker, 'trade_timestamp'); - const symbol = this.getSymbolFromMarketId (this.safeString (ticker, 'market'), market); + const symbol = this.getSymbolFromMarketId (this.safeString2 (ticker, 'market', 'code'), market); const previous = this.safeFloat (ticker, 'prev_closing_price'); const last = this.safeFloat (ticker, 'trade_price'); const change = this.safeFloat (ticker, 'signed_change_price'); @@ -103535,8 +107522,8 @@ module.exports = class upbit extends Exchange { } } } - const marketId = this.safeString (trade, 'market'); - market = this.safeValue (this.markets_by_id, marketId); + const marketId = this.safeString2 (trade, 'market', 'code'); + market = this.safeValue (this.markets_by_id, marketId, market); let fee = undefined; let feeCurrency = undefined; let symbol = undefined; @@ -104052,6 +108039,7 @@ module.exports = class upbit extends Exchange { const result = { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -104249,7 +108237,8 @@ module.exports = class upbit extends Exchange { const request = { 'currency': currency['id'], }; - const response = await this.fetchDepositAddress (code, this.extend (request, params)); + // https://github.com/ccxt/ccxt/issues/6452 + const response = await this.privatePostDepositsGenerateCoinAddress (this.extend (request, params)); // // https://docs.upbit.com/v1.0/reference#%EC%9E%85%EA%B8%88-%EC%A3%BC%EC%86%8C-%EC%83%9D%EC%84%B1-%EC%9A%94%EC%B2%AD // can be any of the two responses: @@ -104267,12 +108256,7 @@ module.exports = class upbit extends Exchange { // const message = this.safeString (response, 'message'); if (message !== undefined) { - return { - 'currency': code, - 'address': undefined, - 'tag': undefined, - 'info': response, - }; + throw new AddressPending (this.id + ' is generating ' + code + ' deposit address, call fetchDepositAddress or createDepositAddress one more time later to retrieve the generated address'); } return this.parseDepositAddress (response); } @@ -104318,7 +108302,7 @@ module.exports = class upbit extends Exchange { } sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = this.implodeParams (this.urls['api'], { + let url = this.implodeParams (this.urls['api'][api], { 'hostname': this.hostname, }); url += '/' + this.version + '/' + this.implodeParams (path, params); @@ -104382,7 +108366,7 @@ module.exports = class upbit extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],168:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],167:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -104468,6 +108452,9 @@ module.exports = class vaultoro extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'info': market, + 'active': undefined, + 'precision': this.precision, + 'limits': this.limits, }); return result; } @@ -104584,7 +108571,7 @@ module.exports = class vaultoro extends Exchange { } }; -},{"./base/Exchange":7}],169:[function(require,module,exports){ +},{"./base/Exchange":8}],168:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -104618,13 +108605,13 @@ module.exports = class vbtc extends foxbit { } }; -},{"./foxbit.js":86}],170:[function(require,module,exports){ +},{"./foxbit.js":85}],169:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, DDoSProtection, BadSymbol } = require ('./base/errors'); +const { ExchangeNotAvailable, ExchangeError, DDoSProtection, BadSymbol } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -104728,6 +108715,7 @@ module.exports = class whitebit extends Exchange { }, 'exceptions': { 'exact': { + '503': ExchangeNotAvailable, // {"response":null,"status":503,"errors":{"message":[""]},"notification":null,"warning":null,"_token":null} }, 'broad': { 'Market is not available': BadSymbol, // {"success":false,"message":{"market":["Market is not available"]},"result":[]} @@ -105205,7 +109193,7 @@ module.exports = class whitebit extends Exchange { } async fetchStatus (params = {}) { - const response = await this.webGetV1Healthcheck (); + const response = await this.webGetV1Healthcheck (params); const status = this.safeInteger (response, 'status'); let formattedStatus = 'ok'; if (status === 503) { @@ -105238,9 +109226,9 @@ module.exports = class whitebit extends Exchange { const success = this.safeValue (response, 'success'); if (!success) { const feedback = this.id + ' ' + body; - const message = this.safeValue (response, 'message'); - if (typeof message === 'string') { - this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback); + const status = this.safeString (response, 'status'); + if (typeof status === 'string') { + this.throwExactlyMatchedException (this.exceptions['exact'], status, feedback); } this.throwBroadlyMatchedException (this.exceptions['broad'], body, feedback); throw new ExchangeError (feedback); @@ -105249,7 +109237,7 @@ module.exports = class whitebit extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],171:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],170:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -105381,6 +109369,9 @@ module.exports = class xbtce extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'info': market, + 'active': undefined, + 'precision': this.precision, + 'limits': this.limits, }); } return result; @@ -105611,7 +109602,7 @@ module.exports = class xbtce extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],172:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],171:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -106156,9 +110147,13 @@ module.exports = class yobit extends Exchange { 'filled': filled, 'fee': undefined, // 'trades': this.parseTrades (order['trades'], market), + 'info': response, + 'clientOrderId': undefined, + 'average': undefined, + 'trades': undefined, }; this.orders[id] = order; - return this.extend ({ 'info': response }, order); + return order; } async cancelOrder (id, symbol = undefined, params = {}) { @@ -106221,6 +110216,7 @@ module.exports = class yobit extends Exchange { const result = { 'info': order, 'id': id, + 'clientOrderId': undefined, 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -106234,6 +110230,8 @@ module.exports = class yobit extends Exchange { 'filled': filled, 'status': status, 'fee': fee, + 'average': undefined, + 'trades': undefined, }; return result; } @@ -106539,7 +110537,7 @@ module.exports = class yobit extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],173:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],172:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -106866,6 +110864,16 @@ module.exports = class zaif extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "currency_pair": "btc_jpy", + // "action": "ask", + // "amount": 0.03, + // "price": 56000, + // "timestamp": 1402021125, + // "comment" : "demo" + // } + // let side = this.safeString (order, 'action'); side = (side === 'bid') ? 'buy' : 'sell'; const timestamp = this.safeTimestamp (order, 'timestamp'); @@ -106890,6 +110898,7 @@ module.exports = class zaif extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -106904,6 +110913,8 @@ module.exports = class zaif extends Exchange { 'remaining': undefined, 'trades': undefined, 'fee': undefined, + 'info': undefined, + 'average': undefined, }; } @@ -107038,7 +111049,7 @@ module.exports = class zaif extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],174:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],173:[function(require,module,exports){ 'use strict'; // --------------------------------------------------------------------------- @@ -107600,6 +111611,7 @@ module.exports = class zb extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -107614,6 +111626,7 @@ module.exports = class zb extends Exchange { 'remaining': remaining, 'status': status, 'fee': undefined, + 'trades': undefined, }; } @@ -107687,7 +111700,7 @@ module.exports = class zb extends Exchange { } }; -},{"./base/Exchange":7,"./base/errors":9}],175:[function(require,module,exports){ +},{"./base/Exchange":8,"./base/errors":10}],174:[function(require,module,exports){ (function (global){ 'use strict'; @@ -108181,7 +112194,7 @@ var objectKeys = Object.keys || function (obj) { }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"util/":233}],176:[function(require,module,exports){ +},{"util/":232}],175:[function(require,module,exports){ 'use strict' exports.byteLength = byteLength @@ -108297,9 +112310,9 @@ function fromByteArray (uint8) { return parts.join('') } -},{}],177:[function(require,module,exports){ +},{}],176:[function(require,module,exports){ -},{}],178:[function(require,module,exports){ +},{}],177:[function(require,module,exports){ (function (process,Buffer){ 'use strict'; /* eslint camelcase: "off" */ @@ -108711,7 +112724,7 @@ Zlib.prototype._reset = function () { exports.Zlib = Zlib; }).call(this,require('_process'),require("buffer").Buffer) -},{"_process":202,"assert":175,"buffer":180,"pako/lib/zlib/constants":192,"pako/lib/zlib/deflate.js":194,"pako/lib/zlib/inflate.js":196,"pako/lib/zlib/zstream":200}],179:[function(require,module,exports){ +},{"_process":201,"assert":174,"buffer":179,"pako/lib/zlib/constants":191,"pako/lib/zlib/deflate.js":193,"pako/lib/zlib/inflate.js":195,"pako/lib/zlib/zstream":199}],178:[function(require,module,exports){ (function (process){ 'use strict'; @@ -109323,7 +113336,7 @@ util.inherits(DeflateRaw, Zlib); util.inherits(InflateRaw, Zlib); util.inherits(Unzip, Zlib); }).call(this,require('_process')) -},{"./binding":178,"_process":202,"assert":175,"buffer":180,"stream":221,"util":233}],180:[function(require,module,exports){ +},{"./binding":177,"_process":201,"assert":174,"buffer":179,"stream":220,"util":232}],179:[function(require,module,exports){ /*! * The buffer module from node.js, for the browser. * @@ -111039,7 +115052,7 @@ function numberIsNaN (obj) { return obj !== obj // eslint-disable-line no-self-compare } -},{"base64-js":176,"ieee754":186}],181:[function(require,module,exports){ +},{"base64-js":175,"ieee754":185}],180:[function(require,module,exports){ module.exports = { "100": "Continue", "101": "Switching Protocols", @@ -111105,7 +115118,7 @@ module.exports = { "511": "Network Authentication Required" } -},{}],182:[function(require,module,exports){ +},{}],181:[function(require,module,exports){ module.exports={ "O_RDONLY": 0, "O_WRONLY": 1, @@ -111316,7 +115329,7 @@ module.exports={ "UV_UDP_REUSEADDR": 4 } -},{}],183:[function(require,module,exports){ +},{}],182:[function(require,module,exports){ (function (Buffer){ // Copyright Joyent, Inc. and other Node contributors. // @@ -111427,7 +115440,7 @@ function objectToString(o) { } }).call(this,{"isBuffer":require("../../is-buffer/index.js")}) -},{"../../is-buffer/index.js":188}],184:[function(require,module,exports){ +},{"../../is-buffer/index.js":187}],183:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -111731,7 +115744,7 @@ function isUndefined(arg) { return arg === void 0; } -},{}],185:[function(require,module,exports){ +},{}],184:[function(require,module,exports){ var http = require('http') var url = require('url') @@ -111764,7 +115777,7 @@ function validateParams (params) { return params } -},{"http":222,"url":228}],186:[function(require,module,exports){ +},{"http":221,"url":227}],185:[function(require,module,exports){ exports.read = function (buffer, offset, isLE, mLen, nBytes) { var e, m var eLen = nBytes * 8 - mLen - 1 @@ -111850,7 +115863,7 @@ exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { buffer[offset + i - d] |= s * 128 } -},{}],187:[function(require,module,exports){ +},{}],186:[function(require,module,exports){ if (typeof Object.create === 'function') { // implementation from standard node.js 'util' module module.exports = function inherits(ctor, superCtor) { @@ -111875,7 +115888,7 @@ if (typeof Object.create === 'function') { } } -},{}],188:[function(require,module,exports){ +},{}],187:[function(require,module,exports){ /*! * Determine if an object is a Buffer * @@ -111898,14 +115911,14 @@ function isSlowBuffer (obj) { return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) } -},{}],189:[function(require,module,exports){ +},{}],188:[function(require,module,exports){ var toString = {}.toString; module.exports = Array.isArray || function (arr) { return toString.call(arr) == '[object Array]'; }; -},{}],190:[function(require,module,exports){ +},{}],189:[function(require,module,exports){ 'use strict'; @@ -112012,7 +116025,7 @@ exports.setTyped = function (on) { exports.setTyped(TYPED_OK); -},{}],191:[function(require,module,exports){ +},{}],190:[function(require,module,exports){ 'use strict'; // Note: adler32 takes 12% for level 0 and 2% for level 6. @@ -112065,7 +116078,7 @@ function adler32(adler, buf, len, pos) { module.exports = adler32; -},{}],192:[function(require,module,exports){ +},{}],191:[function(require,module,exports){ 'use strict'; // (C) 1995-2013 Jean-loup Gailly and Mark Adler @@ -112135,7 +116148,7 @@ module.exports = { //Z_NULL: null // Use -1 or null inline, depending on var type }; -},{}],193:[function(require,module,exports){ +},{}],192:[function(require,module,exports){ 'use strict'; // Note: we can't get significant speed boost here. @@ -112196,7 +116209,7 @@ function crc32(crc, buf, len, pos) { module.exports = crc32; -},{}],194:[function(require,module,exports){ +},{}],193:[function(require,module,exports){ 'use strict'; // (C) 1995-2013 Jean-loup Gailly and Mark Adler @@ -114072,7 +118085,7 @@ exports.deflatePrime = deflatePrime; exports.deflateTune = deflateTune; */ -},{"../utils/common":190,"./adler32":191,"./crc32":193,"./messages":198,"./trees":199}],195:[function(require,module,exports){ +},{"../utils/common":189,"./adler32":190,"./crc32":192,"./messages":197,"./trees":198}],194:[function(require,module,exports){ 'use strict'; // (C) 1995-2013 Jean-loup Gailly and Mark Adler @@ -114419,7 +118432,7 @@ module.exports = function inflate_fast(strm, start) { return; }; -},{}],196:[function(require,module,exports){ +},{}],195:[function(require,module,exports){ 'use strict'; // (C) 1995-2013 Jean-loup Gailly and Mark Adler @@ -115977,7 +119990,7 @@ exports.inflateSyncPoint = inflateSyncPoint; exports.inflateUndermine = inflateUndermine; */ -},{"../utils/common":190,"./adler32":191,"./crc32":193,"./inffast":195,"./inftrees":197}],197:[function(require,module,exports){ +},{"../utils/common":189,"./adler32":190,"./crc32":192,"./inffast":194,"./inftrees":196}],196:[function(require,module,exports){ 'use strict'; // (C) 1995-2013 Jean-loup Gailly and Mark Adler @@ -116322,7 +120335,7 @@ module.exports = function inflate_table(type, lens, lens_index, codes, table, ta return 0; }; -},{"../utils/common":190}],198:[function(require,module,exports){ +},{"../utils/common":189}],197:[function(require,module,exports){ 'use strict'; // (C) 1995-2013 Jean-loup Gailly and Mark Adler @@ -116356,7 +120369,7 @@ module.exports = { '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */ }; -},{}],199:[function(require,module,exports){ +},{}],198:[function(require,module,exports){ 'use strict'; // (C) 1995-2013 Jean-loup Gailly and Mark Adler @@ -117578,7 +121591,7 @@ exports._tr_flush_block = _tr_flush_block; exports._tr_tally = _tr_tally; exports._tr_align = _tr_align; -},{"../utils/common":190}],200:[function(require,module,exports){ +},{"../utils/common":189}],199:[function(require,module,exports){ 'use strict'; // (C) 1995-2013 Jean-loup Gailly and Mark Adler @@ -117627,7 +121640,7 @@ function ZStream() { module.exports = ZStream; -},{}],201:[function(require,module,exports){ +},{}],200:[function(require,module,exports){ (function (process){ 'use strict'; @@ -117674,7 +121687,7 @@ function nextTick(fn, arg1, arg2, arg3) { } }).call(this,require('_process')) -},{"_process":202}],202:[function(require,module,exports){ +},{"_process":201}],201:[function(require,module,exports){ // shim for using process in browser var process = module.exports = {}; @@ -117860,7 +121873,7 @@ process.chdir = function (dir) { }; process.umask = function() { return 0; }; -},{}],203:[function(require,module,exports){ +},{}],202:[function(require,module,exports){ (function (global){ /*! https://mths.be/punycode v1.4.1 by @mathias */ ;(function(root) { @@ -118397,7 +122410,7 @@ process.umask = function() { return 0; }; }(this)); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],204:[function(require,module,exports){ +},{}],203:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -118483,7 +122496,7 @@ var isArray = Array.isArray || function (xs) { return Object.prototype.toString.call(xs) === '[object Array]'; }; -},{}],205:[function(require,module,exports){ +},{}],204:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -118570,16 +122583,16 @@ var objectKeys = Object.keys || function (obj) { return res; }; -},{}],206:[function(require,module,exports){ +},{}],205:[function(require,module,exports){ 'use strict'; exports.decode = exports.parse = require('./decode'); exports.encode = exports.stringify = require('./encode'); -},{"./decode":204,"./encode":205}],207:[function(require,module,exports){ +},{"./decode":203,"./encode":204}],206:[function(require,module,exports){ module.exports = require('./lib/_stream_duplex.js'); -},{"./lib/_stream_duplex.js":208}],208:[function(require,module,exports){ +},{"./lib/_stream_duplex.js":207}],207:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -118704,7 +122717,7 @@ function forEach(xs, f) { f(xs[i], i); } } -},{"./_stream_readable":210,"./_stream_writable":212,"core-util-is":183,"inherits":187,"process-nextick-args":201}],209:[function(require,module,exports){ +},{"./_stream_readable":209,"./_stream_writable":211,"core-util-is":182,"inherits":186,"process-nextick-args":200}],208:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -118752,7 +122765,7 @@ function PassThrough(options) { PassThrough.prototype._transform = function (chunk, encoding, cb) { cb(null, chunk); }; -},{"./_stream_transform":211,"core-util-is":183,"inherits":187}],210:[function(require,module,exports){ +},{"./_stream_transform":210,"core-util-is":182,"inherits":186}],209:[function(require,module,exports){ (function (process,global){ // Copyright Joyent, Inc. and other Node contributors. // @@ -119762,7 +123775,7 @@ function indexOf(xs, x) { return -1; } }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./_stream_duplex":208,"./internal/streams/BufferList":213,"./internal/streams/destroy":214,"./internal/streams/stream":215,"_process":202,"core-util-is":183,"events":184,"inherits":187,"isarray":189,"process-nextick-args":201,"safe-buffer":220,"string_decoder/":226,"util":177}],211:[function(require,module,exports){ +},{"./_stream_duplex":207,"./internal/streams/BufferList":212,"./internal/streams/destroy":213,"./internal/streams/stream":214,"_process":201,"core-util-is":182,"events":183,"inherits":186,"isarray":188,"process-nextick-args":200,"safe-buffer":219,"string_decoder/":225,"util":176}],210:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -119977,7 +123990,7 @@ function done(stream, er, data) { return stream.push(null); } -},{"./_stream_duplex":208,"core-util-is":183,"inherits":187}],212:[function(require,module,exports){ +},{"./_stream_duplex":207,"core-util-is":182,"inherits":186}],211:[function(require,module,exports){ (function (process,global){ // Copyright Joyent, Inc. and other Node contributors. // @@ -120644,7 +124657,7 @@ Writable.prototype._destroy = function (err, cb) { cb(err); }; }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./_stream_duplex":208,"./internal/streams/destroy":214,"./internal/streams/stream":215,"_process":202,"core-util-is":183,"inherits":187,"process-nextick-args":201,"safe-buffer":220,"util-deprecate":230}],213:[function(require,module,exports){ +},{"./_stream_duplex":207,"./internal/streams/destroy":213,"./internal/streams/stream":214,"_process":201,"core-util-is":182,"inherits":186,"process-nextick-args":200,"safe-buffer":219,"util-deprecate":229}],212:[function(require,module,exports){ 'use strict'; /**/ @@ -120719,7 +124732,7 @@ module.exports = function () { return BufferList; }(); -},{"safe-buffer":220}],214:[function(require,module,exports){ +},{"safe-buffer":219}],213:[function(require,module,exports){ 'use strict'; /**/ @@ -120792,13 +124805,13 @@ module.exports = { destroy: destroy, undestroy: undestroy }; -},{"process-nextick-args":201}],215:[function(require,module,exports){ +},{"process-nextick-args":200}],214:[function(require,module,exports){ module.exports = require('events').EventEmitter; -},{"events":184}],216:[function(require,module,exports){ +},{"events":183}],215:[function(require,module,exports){ module.exports = require('./readable').PassThrough -},{"./readable":217}],217:[function(require,module,exports){ +},{"./readable":216}],216:[function(require,module,exports){ exports = module.exports = require('./lib/_stream_readable.js'); exports.Stream = exports; exports.Readable = exports; @@ -120807,13 +124820,13 @@ exports.Duplex = require('./lib/_stream_duplex.js'); exports.Transform = require('./lib/_stream_transform.js'); exports.PassThrough = require('./lib/_stream_passthrough.js'); -},{"./lib/_stream_duplex.js":208,"./lib/_stream_passthrough.js":209,"./lib/_stream_readable.js":210,"./lib/_stream_transform.js":211,"./lib/_stream_writable.js":212}],218:[function(require,module,exports){ +},{"./lib/_stream_duplex.js":207,"./lib/_stream_passthrough.js":208,"./lib/_stream_readable.js":209,"./lib/_stream_transform.js":210,"./lib/_stream_writable.js":211}],217:[function(require,module,exports){ module.exports = require('./readable').Transform -},{"./readable":217}],219:[function(require,module,exports){ +},{"./readable":216}],218:[function(require,module,exports){ module.exports = require('./lib/_stream_writable.js'); -},{"./lib/_stream_writable.js":212}],220:[function(require,module,exports){ +},{"./lib/_stream_writable.js":211}],219:[function(require,module,exports){ /* eslint-disable node/no-deprecated-api */ var buffer = require('buffer') var Buffer = buffer.Buffer @@ -120877,7 +124890,7 @@ SafeBuffer.allocUnsafeSlow = function (size) { return buffer.SlowBuffer(size) } -},{"buffer":180}],221:[function(require,module,exports){ +},{"buffer":179}],220:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -121006,7 +125019,7 @@ Stream.prototype.pipe = function(dest, options) { return dest; }; -},{"events":184,"inherits":187,"readable-stream/duplex.js":207,"readable-stream/passthrough.js":216,"readable-stream/readable.js":217,"readable-stream/transform.js":218,"readable-stream/writable.js":219}],222:[function(require,module,exports){ +},{"events":183,"inherits":186,"readable-stream/duplex.js":206,"readable-stream/passthrough.js":215,"readable-stream/readable.js":216,"readable-stream/transform.js":217,"readable-stream/writable.js":218}],221:[function(require,module,exports){ (function (global){ var ClientRequest = require('./lib/request') var extend = require('xtend') @@ -121088,7 +125101,7 @@ http.METHODS = [ 'UNSUBSCRIBE' ] }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./lib/request":224,"builtin-status-codes":181,"url":228,"xtend":234}],223:[function(require,module,exports){ +},{"./lib/request":223,"builtin-status-codes":180,"url":227,"xtend":233}],222:[function(require,module,exports){ (function (global){ exports.fetch = isFunction(global.fetch) && isFunction(global.ReadableStream) @@ -121161,7 +125174,7 @@ function isFunction (value) { xhr = null // Help gc }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],224:[function(require,module,exports){ +},{}],223:[function(require,module,exports){ (function (process,global,Buffer){ var capability = require('./capability') var inherits = require('inherits') @@ -121471,7 +125484,7 @@ var unsafeHeaders = [ ] }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer) -},{"./capability":223,"./response":225,"_process":202,"buffer":180,"inherits":187,"readable-stream":217,"to-arraybuffer":227}],225:[function(require,module,exports){ +},{"./capability":222,"./response":224,"_process":201,"buffer":179,"inherits":186,"readable-stream":216,"to-arraybuffer":226}],224:[function(require,module,exports){ (function (process,global,Buffer){ var capability = require('./capability') var inherits = require('inherits') @@ -121657,7 +125670,7 @@ IncomingMessage.prototype._onXHRProgress = function () { } }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer) -},{"./capability":223,"_process":202,"buffer":180,"inherits":187,"readable-stream":217}],226:[function(require,module,exports){ +},{"./capability":222,"_process":201,"buffer":179,"inherits":186,"readable-stream":216}],225:[function(require,module,exports){ 'use strict'; var Buffer = require('safe-buffer').Buffer; @@ -121930,7 +125943,7 @@ function simpleWrite(buf) { function simpleEnd(buf) { return buf && buf.length ? this.write(buf) : ''; } -},{"safe-buffer":220}],227:[function(require,module,exports){ +},{"safe-buffer":219}],226:[function(require,module,exports){ var Buffer = require('buffer').Buffer module.exports = function (buf) { @@ -121959,7 +125972,7 @@ module.exports = function (buf) { } } -},{"buffer":180}],228:[function(require,module,exports){ +},{"buffer":179}],227:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -122693,7 +126706,7 @@ Url.prototype.parseHost = function() { if (host) this.hostname = host; }; -},{"./util":229,"punycode":203,"querystring":206}],229:[function(require,module,exports){ +},{"./util":228,"punycode":202,"querystring":205}],228:[function(require,module,exports){ 'use strict'; module.exports = { @@ -122711,7 +126724,7 @@ module.exports = { } }; -},{}],230:[function(require,module,exports){ +},{}],229:[function(require,module,exports){ (function (global){ /** @@ -122782,16 +126795,16 @@ function config (name) { } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],231:[function(require,module,exports){ -arguments[4][187][0].apply(exports,arguments) -},{"dup":187}],232:[function(require,module,exports){ +},{}],230:[function(require,module,exports){ +arguments[4][186][0].apply(exports,arguments) +},{"dup":186}],231:[function(require,module,exports){ module.exports = function isBuffer(arg) { return arg && typeof arg === 'object' && typeof arg.copy === 'function' && typeof arg.fill === 'function' && typeof arg.readUInt8 === 'function'; } -},{}],233:[function(require,module,exports){ +},{}],232:[function(require,module,exports){ (function (process,global){ // Copyright Joyent, Inc. and other Node contributors. // @@ -123381,7 +127394,7 @@ function hasOwnProperty(obj, prop) { } }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./support/isBuffer":232,"_process":202,"inherits":231}],234:[function(require,module,exports){ +},{"./support/isBuffer":231,"_process":201,"inherits":230}],233:[function(require,module,exports){ module.exports = extend var hasOwnProperty = Object.prototype.hasOwnProperty; diff --git a/TaskServer/node_modules/ccxt/js/_1btcxe.js b/TaskServer/node_modules/ccxt/js/_1btcxe.js index f18280a68..90aacb4f5 100644 --- a/TaskServer/node_modules/ccxt/js/_1btcxe.js +++ b/TaskServer/node_modules/ccxt/js/_1btcxe.js @@ -91,6 +91,7 @@ module.exports = class _1btcxe extends Exchange { } async fetchBalance (params = {}) { + await this.loadMarkets (); const response = await this.privatePostBalancesAndInfo (params); const balance = response['balances-and-info']; const result = { 'info': balance }; @@ -108,6 +109,7 @@ module.exports = class _1btcxe extends Exchange { } async fetchOrderBook (symbol, limit = undefined, params = {}) { + await this.loadMarkets (); const request = { 'currency': this.marketId (symbol), }; @@ -116,6 +118,7 @@ module.exports = class _1btcxe extends Exchange { } async fetchTicker (symbol, params = {}) { + await this.loadMarkets (); const request = { 'currency': this.marketId (symbol), }; @@ -158,6 +161,7 @@ module.exports = class _1btcxe extends Exchange { } async fetchOHLCV (symbol, timeframe = '1d', since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); const market = this.market (symbol); const response = await this.publicGetHistoricalPrices (this.extend ({ 'currency': market['id'], @@ -202,6 +206,7 @@ module.exports = class _1btcxe extends Exchange { } async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); const market = this.market (symbol); const request = { 'currency': market['id'], @@ -215,6 +220,7 @@ module.exports = class _1btcxe extends Exchange { } async createOrder (symbol, type, side, amount, price = undefined, params = {}) { + await this.loadMarkets (); const request = { 'side': side, 'type': type, @@ -232,6 +238,7 @@ module.exports = class _1btcxe extends Exchange { } async cancelOrder (id, symbol = undefined, params = {}) { + await this.loadMarkets (); const request = { 'id': id, }; diff --git a/TaskServer/node_modules/ccxt/js/acx.js b/TaskServer/node_modules/ccxt/js/acx.js index 798d473da..d1b31388a 100644 --- a/TaskServer/node_modules/ccxt/js/acx.js +++ b/TaskServer/node_modules/ccxt/js/acx.js @@ -92,6 +92,9 @@ module.exports = class acx extends Exchange { 'withdraw': {}, // There is only 1% fee on withdrawals to your bank account. }, }, + 'commonCurrencies': { + 'PLA': 'Plair', + }, 'exceptions': { '2002': InsufficientFunds, '2003': OrderNotFound, @@ -131,6 +134,8 @@ module.exports = class acx extends Exchange { 'quoteId': quoteId, 'precision': precision, 'info': market, + 'active': undefined, + 'limits': this.limits, }); } return result; @@ -322,6 +327,7 @@ module.exports = class acx extends Exchange { const id = this.safeString (order, 'id'); return { 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -336,6 +342,8 @@ module.exports = class acx extends Exchange { 'trades': undefined, 'fee': undefined, 'info': order, + 'cost': undefined, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/adara.js b/TaskServer/node_modules/ccxt/js/adara.js index 96da8e0ea..d816df1c3 100644 --- a/TaskServer/node_modules/ccxt/js/adara.js +++ b/TaskServer/node_modules/ccxt/js/adara.js @@ -18,7 +18,7 @@ module.exports = class adara extends Exchange { 'certified': false, // new metainfo interface 'has': { - 'CORS': true, + 'CORS': false, 'fetchCurrencies': true, 'fetchOrderBooks': false, 'createMarketOrder': false, @@ -970,6 +970,7 @@ module.exports = class adara extends Exchange { const result = { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, diff --git a/TaskServer/node_modules/ccxt/js/anxpro.js b/TaskServer/node_modules/ccxt/js/anxpro.js index d27fb71aa..092e58ac4 100644 --- a/TaskServer/node_modules/ccxt/js/anxpro.js +++ b/TaskServer/node_modules/ccxt/js/anxpro.js @@ -469,6 +469,7 @@ module.exports = class anxpro extends Exchange { 'cost': cost, 'fee': undefined, 'info': trade, + 'takerOrMaker': undefined, }; } @@ -974,6 +975,7 @@ module.exports = class anxpro extends Exchange { const cost = executedAverageRate * filled; return { 'id': this.safeString (order, 'orderId'), + 'clientOrderId': undefined, 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -989,6 +991,7 @@ module.exports = class anxpro extends Exchange { 'fee': undefined, 'trades': trades, 'info': order, + 'average': undefined, }; } @@ -1066,6 +1069,7 @@ module.exports = class anxpro extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -1080,6 +1084,7 @@ module.exports = class anxpro extends Exchange { 'status': status, 'fee': fee, 'trades': trades, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/aofex.js b/TaskServer/node_modules/ccxt/js/aofex.js new file mode 100644 index 000000000..f5e72f678 --- /dev/null +++ b/TaskServer/node_modules/ccxt/js/aofex.js @@ -0,0 +1,1119 @@ +'use strict'; + +// --------------------------------------------------------------------------- + +const Exchange = require ('./base/Exchange'); +const { ArgumentsRequired, ExchangeError, BadSymbol, InvalidOrder, PermissionDenied, InvalidAddress, AuthenticationError, InvalidNonce, BadRequest, InsufficientFunds, OrderNotFound } = require ('./base/errors'); +const { TRUNCATE } = require ('./base/functions/number'); + +// --------------------------------------------------------------------------- + +module.exports = class aofex extends Exchange { + describe () { + return this.deepExtend (super.describe (), { + 'id': 'aofex', + 'name': 'AOFEX', + 'countries': [ 'GB' ], + 'rateLimit': 1000, + 'has': { + 'fetchMarkets': true, + 'fetchCurrencies': false, + 'fetchOrderBook': true, + 'fetchTrades': true, + 'fetchTicker': true, + 'fetchTickers': true, + 'fetchOHLCV': true, + 'fetchBalance': true, + 'createOrder': true, + 'cancelOrder': true, + 'cancelAllOrders': true, + 'fetchOpenOrders': true, + 'fetchClosedOrders': true, + 'fetchClosedOrder': true, + 'fetchTradingFee': true, + }, + 'timeframes': { + '1m': '1min', + '5m': '5min', + '15m': '15min', + '30m': '30min', + '1h': '1hour', + '6h': '6hour', + '12h': '12hour', + '1d': '1day', + '1w': '1week', + }, + 'urls': { + 'logo': 'https://user-images.githubusercontent.com/51840849/77670271-056d1080-6f97-11ea-9ac2-4268e9ed0c1f.jpg', + 'api': { + 'public': 'https://openapi.aofex.com/openApi', + 'private': 'https://openapi.aofex.com/openApi', + }, + 'www': 'https://aofex.com', + 'doc': 'https://aofex.zendesk.com/hc/en-us/sections/360005576574-API', + 'fees': 'https://aofex.zendesk.com/hc/en-us/articles/360025814934-Fees-on-AOFEX', + 'referral': 'https://aofex.com/#/register?key=9763840', + }, + 'api': { + 'public': { + 'get': [ + 'market/symbols', + 'market/trade', + 'market/depth', + 'market/kline', + 'market/precision', + 'market/24kline', + 'market/gears_depth', + 'market/detail', + ], + }, + 'private': { + 'get': [ + 'entrust/currentList', + 'entrust/historyList', + 'entrust/rate', + 'wallet/list', + 'entrust/detail', + ], + 'post': [ + 'entrust/add', + 'entrust/cancel', + ], + }, + }, + 'fees': { + 'trading': { + 'maker': 0.0019, + 'taker': 0.002, + }, + }, + 'exceptions': { + 'exact': { + '20001': ExchangeError, // request failure + '20401': PermissionDenied, // no permission + '20500': ExchangeError, // system error + '20501': BadSymbol, // base symbol error + '20502': ExchangeError, // base currency error + '20503': ExchangeError, // base date error + '20504': InsufficientFunds, // account frozen balance insufficient error + '20505': BadRequest, // bad argument + '20506': AuthenticationError, // api signature not valid + '20507': ExchangeError, // gateway internal error + '20508': InvalidAddress, // ad ethereum addresss + '20509': InsufficientFunds, // order accountbalance error + '20510': InvalidOrder, // order limitorder price error + '20511': InvalidOrder, // order limitorder amount error + '20512': InvalidOrder, // order orderprice precision error + '20513': InvalidOrder, // order orderamount precision error + '20514': InvalidOrder, // order marketorder amount error + '20515': InvalidOrder, // order queryorder invalid + '20516': InvalidOrder, // order orderstate error + '20517': InvalidOrder, // order datelimit error + '50518': InvalidOrder, // order update error + '20519': InvalidNonce, // the nonce has been used + '20520': InvalidNonce, // nonce expires, please verify server time + '20521': BadRequest, // incomplete header parameters + '20522': ExchangeError, // not getting the current user + '20523': AuthenticationError, // please authenticate + '20524': PermissionDenied, // btc account lockout + '20525': AuthenticationError, // get API Key error + '20526': PermissionDenied, // no query permission + '20527': PermissionDenied, // no deal permission + '20528': PermissionDenied, // no withdrawal permission + '20529': AuthenticationError, // API Key expired + '20530': PermissionDenied, // no permission + }, + 'broad': { + }, + }, + 'options': { + 'fetchBalance': { + 'show_all': '0', // '1' to show zero balances + }, + }, + }); + } + + async fetchMarkets (params = {}) { + let markets = await this.publicGetMarketSymbols (params); + // + // { + // errno: 0, + // errmsg: 'success', + // result: [ + // { + // id: 2, + // symbol: 'BTC-USDT', + // base_currency: 'BTC', + // quote_currency: 'USDT', + // min_size: 0.00008, + // max_size: 1300, + // min_price: 1000, + // max_price: 110000, + // maker_fee: 1, + // taker_fee: 1, + // isHot: null, + // isNew: null, + // crown: null + // }, + // ] + // } + // + let precisions = await this.publicGetMarketPrecision (); + // + // { + // errno: 0, + // errmsg: 'success', + // result: { + // 'MANA-USDT': { + // amount: '2', + // minQuantity: '32', + // maxQuantity: '46000000', + // price: '4', + // minPrice: '0.003', + // maxPrice: '0.35' + // }, + // } + // } + // + precisions = this.safeValue (precisions, 'result', {}); + markets = this.safeValue (markets, 'result', []); + const result = []; + for (let i = 0; i < markets.length; i++) { + const market = markets[i]; + const id = this.safeString (market, 'symbol'); + const baseId = this.safeString (market, 'base_currency'); + const quoteId = this.safeString (market, 'quote_currency'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + const symbol = base + '/' + quote; + const numericId = this.safeInteger (market, 'id'); + const precision = this.safeValue (precisions, id, {}); + const makerFee = this.safeFloat (market, 'maker_fee'); + const takerFee = this.safeFloat (market, 'taker_fee'); + result.push ({ + 'id': id, + 'numericId': numericId, + 'symbol': symbol, + 'baseId': baseId, + 'quoteId': quoteId, + 'base': base, + 'quote': quote, + 'active': undefined, + 'maker': makerFee / 1000, + 'taker': takerFee / 1000, + 'precision': { + 'amount': this.safeInteger (precision, 'amount'), + 'price': this.safeInteger (precision, 'price'), + }, + 'limits': { + 'amount': { + 'min': this.safeFloat (market, 'min_size'), + 'max': this.safeFloat (market, 'max_size'), + }, + 'price': { + 'min': this.safeFloat (market, 'min_price'), + 'max': this.safeFloat (market, 'max_price'), + }, + 'cost': { + 'min': undefined, + 'max': undefined, + }, + }, + 'info': market, + }); + } + return result; + } + + parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) { + // + // { + // id: 1584950100, + // amount: "329.196", + // count: 81, + // open: "0.021155", + // close: "0.021158", + // low: "0.021144", + // high: "0.021161", + // vol: "6.963557767" + // } + // + return [ + this.safeTimestamp (ohlcv, 'id'), + this.safeFloat (ohlcv, 'open'), + this.safeFloat (ohlcv, 'high'), + this.safeFloat (ohlcv, 'low'), + this.safeFloat (ohlcv, 'close'), + this.safeFloat (ohlcv, 'amount'), + ]; + } + + async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + if (limit === undefined) { + limit = 150; // default 150, max 2000 + } + const request = { + 'symbol': market['id'], + 'period': this.timeframes[timeframe], + 'size': limit, // default 150, max 2000 + }; + const response = await this.publicGetMarketKline (this.extend (request, params)); + // + // { + // errno: 0, + // errmsg: "success", + // result: { + // ts: 1584950139003, + // symbol: "ETH-BTC", + // period: "1min", + // data: [ + // { + // id: 1584950100, + // amount: "329.196", + // count: 81, + // open: "0.021155", + // close: "0.021158", + // low: "0.021144", + // high: "0.021161", + // vol: "6.963557767" + // }, + // { + // id: 1584950040, + // amount: "513.265", + // count: 151, + // open: "0.021165", + // close: "0.021155", + // low: "0.021151", + // high: "0.02118", + // vol: "10.862806573" + // }, + // ] + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const data = this.safeValue (result, 'data', []); + return this.parseOHLCVs (data, market, timeframe, since, limit); + } + + async fetchBalance (params = {}) { + await this.loadMarkets (); + const options = this.safeValue (this.options, 'fetchBalance', {}); + const showAll = this.safeValue (options, 'show_all', '0'); + const request = { + // 'currency': 'BTC', + 'show_all': showAll, // required to show zero balances + }; + const response = await this.privateGetWalletList (this.extend (request, params)); + // + // { + // "errno": 0, + // "errmsg": "success", + // "result": [ + // { "available": "0", "frozen": "0", "currency": "BTC" } + // ] + // } + // + const result = { 'info': response }; + const balances = this.safeValue (response, 'result', []); + for (let i = 0; i < balances.length; i++) { + const balance = balances[i]; + const currencyId = this.safeString (balance, 'currency'); + const code = this.safeCurrencyCode (currencyId); + const account = this.account (); + account['free'] = this.safeFloat (balance, 'available'); + account['used'] = this.safeFloat (balance, 'frozen'); + result[code] = account; + } + return this.parseBalance (result); + } + + async fetchTradingFee (symbol, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.privateGetEntrustRate (this.extend (request, params)); + // + // { + // "errno":0, + // "errmsg":"success", + // "result": { + // "toFee":"0.002","fromFee":"0.002" + // } + // } + // + const result = this.safeValue (response, 'result', {}); + return { + 'info': response, + 'symbol': symbol, + 'maker': this.safeFloat (result, 'fromFee'), + 'taker': this.safeFloat (result, 'toFee'), + }; + } + + async fetchOrderBook (symbol, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + 'symbol': this.marketId (symbol), + }; + const response = await this.publicGetMarketDepth (this.extend (request, params)); + // + // { + // errno: 0, + // errmsg: "success", + // result: { + // buyType: 1, + // sellType: 1, + // ts: 1584950701050, + // symbol: "ETH-BTC", + // asks: [ + // ["0.021227", "0.182"], + // ["0.021249", "0.035"], + // ["0.021253", "0.058"], + // ], + // bids: [ + // ["0.021207", "0.039"], + // ["0.021203", "0.051"], + // ["0.02117", "2.326"], + // ] + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const timestamp = this.safeInteger (result, 'ts'); + return this.parseOrderBook (result, timestamp); + } + + parseTicker (ticker, market = undefined) { + // + // fetchTicker + // + // { + // id: 1584890087, + // amount: '150032.919', + // count: 134538, + // open: '0.021394', + // close: '0.021177', + // low: '0.021053', + // high: '0.021595', + // vol: '3201.72451442' + // } + // + const timestamp = this.safeTimestamp (ticker, 'id'); + let symbol = undefined; + if (market) { + symbol = market['symbol']; + } + const open = this.safeFloat (ticker, 'open'); + const last = this.safeFloat (ticker, 'close'); + let change = undefined; + if (symbol !== undefined) { + change = parseFloat (this.priceToPrecision (symbol, last - open)); + } else { + change = last - open; + } + const average = this.sum (last, open) / 2; + const percentage = change / open * 100; + const baseVolume = this.safeFloat (ticker, 'amount'); + const quoteVolume = this.safeFloat (ticker, 'vol'); + let vwap = undefined; + if (quoteVolume !== undefined) { + if (baseVolume !== undefined) { + if (baseVolume > 0) { + vwap = parseFloat (this.priceToPrecision (symbol, quoteVolume / baseVolume)); + } + } + } + return { + 'symbol': symbol, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'high': this.safeFloat (ticker, 'high'), + 'low': this.safeFloat (ticker, 'low'), + 'bid': undefined, + 'bidVolume': undefined, + 'ask': undefined, + 'askVolume': undefined, + 'vwap': vwap, + 'open': open, + 'close': last, + 'last': last, + 'previousClose': undefined, + 'change': change, + 'percentage': percentage, + 'average': average, + 'baseVolume': baseVolume, + 'quoteVolume': quoteVolume, + 'info': ticker, + }; + } + + async fetchTickers (symbols = undefined, params = {}) { + await this.loadMarkets (); + const request = {}; + if (symbols !== undefined) { + const ids = this.marketIds (symbols); + request['symbol'] = ids.join (','); + } + const response = await this.publicGetMarket24kline (this.extend (request, params)); + // + // { + // errno: 0, + // errmsg: "success", + // result: [ + // { + // symbol: "HB-AQ", + // data: { + // id: 1584893403, + // amount: "4753751.243400354852648809", + // count: 4724, + // open: "6.3497", + // close: "6.3318", + // low: "6.011", + // high: "6.5", + // vol: "29538384.7873528796542891343493" + // } + // }, + // ] + // } + // + const tickers = this.safeValue (response, 'result', []); + const result = {}; + for (let i = 0; i < tickers.length; i++) { + const marketId = this.safeString (tickers[i], 'symbol'); + let market = undefined; + let symbol = marketId; + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + const [ baseId, quoteId ] = marketId.split ('-'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + } + const data = this.safeValue (tickers[i], 'data', {}); + const ticker = this.parseTicker (data, market); + ticker['symbol'] = symbol; + result[symbol] = ticker; + } + return this.filterByArray (result, 'symbol', symbols); + } + + async fetchTicker (symbol, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.publicGetMarketDetail (this.extend (request, params)); + // + // { + // errno: 0, + // errmsg: 'success', + // result: { + // id: 1584890087, + // amount: '150032.919', + // count: 134538, + // open: '0.021394', + // close: '0.021177', + // low: '0.021053', + // high: '0.021595', + // vol: '3201.72451442' + // } + // } + // + const result = this.safeValue (response, 'result', {}); + return this.parseTicker (result, market); + } + + parseTrade (trade, market = undefined) { + // + // fetchTrades (public) + // + // { + // id: 1584948803298490, + // amount: "2.737", + // price: "0.021209", + // direction: "sell", + // ts: 1584948803 + // } + // + // fetchOrder trades + // + // { + // "id":null, + // "ctime":"2020-03-23 20:07:17", + // "price":"123.9", + // "number":"0.010688626311541565", + // "total_price":"1.324320799999999903", + // "fee":"0.000021377252623083" + // } + // + const id = this.safeString (trade, 'id'); + const ctime = this.parse8601 (this.safeString (trade, 'ctime')); + const timestamp = this.safeTimestamp (trade, 'ts', ctime); + let symbol = undefined; + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const side = this.safeString (trade, 'direction'); + const price = this.safeFloat (trade, 'price'); + const amount = this.safeFloat2 (trade, 'amount', 'number'); + let cost = this.safeFloat (trade, 'total_price'); + if ((cost === undefined) && (price !== undefined) && (amount !== undefined)) { + cost = price * amount; + } + const feeCost = this.safeFloat (trade, 'fee'); + let fee = undefined; + if (feeCost !== undefined) { + let feeCurrencyCode = undefined; + if (market !== undefined) { + if (side === 'buy') { + feeCurrencyCode = market['base']; + } else if (side === 'sell') { + feeCurrencyCode = market['quote']; + } + } + fee = { + 'cost': feeCost, + 'currency': feeCurrencyCode, + }; + } + return { + 'id': id, + 'info': trade, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'symbol': symbol, + 'order': undefined, + 'type': undefined, + 'side': side, + 'takerOrMaker': undefined, + 'price': price, + 'amount': amount, + 'cost': cost, + 'fee': fee, + }; + } + + async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.publicGetMarketTrade (this.extend (request, params)); + // + // { + // errno: 0, + // errmsg: "success", + // result: { + // symbol: "ETH-BTC", + // ts: 1584948805439, + // data: [ + // { + // id: 1584948803300883, + // amount: "0.583", + // price: "0.021209", + // direction: "buy", + // ts: 1584948803 + // }, + // { + // id: 1584948803298490, + // amount: "2.737", + // price: "0.021209", + // direction: "sell", + // ts: 1584948803 + // }, + // ] + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const data = this.safeValue (result, 'data', []); + return this.parseTrades (data, market, since, limit); + } + + parseOrderStatus (status) { + const statuses = { + '1': 'open', + '2': 'open', // partially filled + '3': 'closed', + '4': 'canceled', // canceling + '5': 'canceled', // partially canceled + '6': 'canceled', + }; + return this.safeString (statuses, status, status); + } + + parseOrder (order, market = undefined) { + // + // createOrder + // + // { order_sn: 'BM7442641584965237751ZMAKJ5' } + // + // fetchOpenOrders, fetchClosedOrders + // + // { + // "order_sn": "BL74426415849672087836G48N1", + // "symbol": "ETH-USDT", + // "ctime": "2020-03-23 20:40:08", + // "type": 2, + // "side": "buy", + // "price": "90", // undefined for market orders + // "number": "0.1", + // "total_price": "9.0", // 0 for market orders + // "deal_number": null, + // "deal_price": null, + // "status": 1, + // } + // + // fetchOrder + // + // { + // order_sn: 'BM7442641584965237751ZMAKJ5', + // symbol: 'ETH-USDT', + // ctime: '2020-03-23 20:07:17', + // type: 1, + // side: 'buy', + // price: '0', + // number: '10', + // total_price: '0', + // deal_number: '0.080718626311541565', + // deal_price: '123.890000000000000000', + // status: 3, + // // the trades field is injected by fetchOrder + // trades: [ + // { + // id: null, + // ctime: '2020-03-23 20:07:17', + // price: '123.9', + // number: '0.010688626311541565', + // total_price: '1.324320799999999903', + // fee: '0.000021377252623083' + // } + // ] + // } + // + const id = this.safeString (order, 'order_sn'); + const orderStatus = this.safeString (order, 'status'); + const status = this.parseOrderStatus (orderStatus); + let symbol = undefined; + const marketId = this.safeString (order, 'symbol'); + let base = undefined; + let quote = undefined; + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } else { + const [ baseId, quoteId ] = marketId.split ('-'); + base = this.safeCurrencyCode (baseId); + quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + base = market['base']; + quote = market['quote']; + } + const timestamp = this.parse8601 (this.safeString (order, 'ctime')); + const orderType = this.safeString (order, 'type'); + const type = (orderType === '2') ? 'limit' : 'market'; + const side = this.safeString (order, 'side'); + // const amount = this.safeFloat (order, 'number'); + // const price = this.safeFloat (order, 'price'); + let cost = undefined; + let price = undefined; + let amount = undefined; + let average = undefined; + const number = this.safeFloat (order, 'number'); + const totalPrice = this.safeFloat (order, 'total_price'); + if (type === 'limit') { + amount = number; + price = this.safeFloat (order, 'price'); + } else { + average = this.safeFloat (order, 'deal_price'); + if (side === 'buy') { + amount = this.safeFloat (order, 'deal_number'); + } else { + amount = number; + } + } + let fee = undefined; + let trades = undefined; + let filled = undefined; + let feeCost = undefined; + let remaining = undefined; + let lastTradeTimestamp = undefined; + // all orders except new orders and canceled orders + if ((orderStatus !== '1') && (orderStatus !== '6')) { + const rawTrades = this.safeValue (order, 'trades'); + if (rawTrades !== undefined) { + for (let i = 0; i < rawTrades.length; i++) { + rawTrades[i]['direction'] = side; + } + trades = this.parseTrades (rawTrades, market, undefined, undefined, { + 'symbol': market['symbol'], + 'order': id, + 'side': side, + 'type': type, + }); + const tradesLength = trades.length; + if (tradesLength > 0) { + const firstTrade = trades[0]; + feeCost = firstTrade['fee']['cost']; + lastTradeTimestamp = firstTrade['timestamp']; + filled = firstTrade['amount']; + cost = firstTrade['cost']; + for (let i = 1; i < trades.length; i++) { + const trade = trades[i]; + feeCost = this.sum (feeCost, trade['fee']['cost']); + filled = this.sum (filled, trade['amount']); + cost = this.sum (cost, trade['cost']); + lastTradeTimestamp = Math.max (lastTradeTimestamp, trade['timestamp']); + } + if (amount !== undefined) { + filled = Math.min (amount, filled); + } + if (filled > 0) { + average = cost / filled; + } + } + if (feeCost !== undefined) { + const feeCurrencyCode = (side === 'buy') ? base : quote; + fee = { + 'cost': feeCost, + 'currency': feeCurrencyCode, + }; + } + } + } else { + filled = 0; + cost = 0; + } + if (cost === undefined) { + if (type === 'limit') { + cost = totalPrice; + } else if (side === 'buy') { + cost = number; + } + } + if (filled === undefined) { + if ((type === 'limit') && (orderStatus === '3')) { + filled = amount; + } + } + if (filled !== undefined) { + if (amount !== undefined) { + remaining = Math.max (amount - filled, 0); + } + } + return { + 'info': order, + 'id': id, + 'clientOrderId': undefined, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': lastTradeTimestamp, + 'status': status, + 'symbol': symbol, + 'type': type, + 'side': side, + 'price': price, + 'cost': cost, + 'average': average, + 'amount': amount, + 'filled': filled, + 'remaining': remaining, + 'trades': trades, + 'fee': fee, + }; + } + + async fetchClosedOrder (id, symbol = undefined, params = {}) { + await this.loadMarkets (); + const request = { + 'order_sn': id, + }; + const response = await this.privateGetEntrustDetail (this.extend (request, params)); + // + // { + // "errno": 0, + // "errmsg": "success", + // "result": { + // "trades": [ + // { + // "id":null, + // "ctime":"2020-03-23 20:07:17", + // "price":"123.9", + // "number":"0.010688626311541565", + // "total_price":"1.324320799999999903", + // "fee":"0.000021377252623083" + // }, + // ], + // "entrust":{ + // "order_sn":"BM7442641584965237751ZMAKJ5", + // "symbol":"ETH-USDT", + // "ctime":"2020-03-23 20:07:17", + // "type":1, + // "side":"buy", + // "price":"0", + // "number":"10", + // "total_price":"0", + // "deal_number":"0.080718626311541565", + // "deal_price":"123.890000000000000000", + // "status":3 + // } + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const trades = this.safeValue (result, 'trades', []); + const order = this.safeValue (result, 'entrust', {}); + order['trades'] = trades; + return this.parseOrder (order); + } + + async fetchOrdersWithMethod (method, symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'from': 'BM7442641584965237751ZMAKJ5', // query start order_sn + // 'direct': 'prev', // next + }; + let market = undefined; + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + } + if (limit !== undefined) { + request['limit'] = limit; // default 20, max 100 + } + const response = await this[method] (this.extend (request, params)); + // + // { + // "errno": 0, + // "errmsg": "success", + // "result": [ + // { + // "order_sn": "BL74426415849672087836G48N1", + // "symbol": "ETH-USDT", + // "ctime": "2020-03-23 20:40:08", + // "type": 2, + // "side": "buy", + // "price": "90", + // "number": "0.1", + // "total_price": "9.0", + // "deal_number": null, + // "deal_price": null, + // "status": 1, + // } + // ] + // } + // + const result = this.safeValue (response, 'result', []); + return this.parseOrders (result, market, since, limit); + } + + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + return await this.fetchOrdersWithMethod ('privateGetEntrustCurrentList', symbol, since, limit, params); + } + + async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + return await this.fetchOrdersWithMethod ('privateGetEntrustHistoryList', symbol, since, limit, params); + } + + async createOrder (symbol, type, side, amount, price = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const orderType = side + '-' + type; + const request = { + 'symbol': market['id'], + 'type': orderType, + }; + if (type === 'limit') { + request['amount'] = this.amountToPrecision (symbol, amount); + request['price'] = this.priceToPrecision (symbol, price); + } else if (type === 'market') { + // for market buy it requires the amount of quote currency to spend + if (side === 'buy') { + const createMarketBuyOrderRequiresPrice = this.safeValue (this.options, 'createMarketBuyOrderRequiresPrice', true); + let cost = amount; + if (createMarketBuyOrderRequiresPrice) { + if (price !== undefined) { + cost = amount * price; + } else { + throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'amount' argument"); + } + } + const precision = market['precision']['price']; + request['amount'] = this.decimalToPrecision (cost, TRUNCATE, precision, this.precisionMode); + } else { + request['amount'] = this.amountToPrecision (symbol, amount); + } + } + const response = await this.privatePostEntrustAdd (this.extend (request, params)); + // + // { + // errno: 0, + // errmsg: 'success', + // result: { order_sn: 'BM7442641584965237751ZMAKJ5' } + // } + // + const result = this.safeValue (response, 'result', {}); + const order = this.parseOrder (result, market); + const timestamp = this.milliseconds (); + return this.extend (order, { + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'amount': amount, + 'price': price, + 'type': type, + 'side': side, + }); + } + + async cancelOrder (id, symbol = undefined, params = {}) { + await this.loadMarkets (); + const request = { + 'order_ids': id, + }; + const response = await this.privatePostEntrustCancel (this.extend (request, params)); + // + // { + // "errno": 0, + // "errmsg": "success", + // "result": { + // "success": [ "avl12121", "bl3123123" ], + // "failed": [ "sd24564", "sdf6564564" ] + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const success = this.safeValue (result, 'success', []); + if (!this.inArray (id, success)) { + throw new OrderNotFound (this.id + ' order id ' + id + ' not found in successfully canceled orders: ' + this.json (response)); + } + const timestamp = undefined; + return { + 'info': response, + 'id': id, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': undefined, + 'status': 'canceled', + 'symbol': symbol, + 'type': undefined, + 'side': undefined, + 'price': undefined, + 'cost': undefined, + 'average': undefined, + 'amount': undefined, + 'filled': undefined, + 'remaining': undefined, + 'trades': undefined, + 'fee': undefined, + 'clientOrderId': undefined, + }; + } + + async cancelAllOrders (symbol = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' cancelAllOrders() requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.privatePostEntrustCancel (this.extend (request, params)); + // + // { + // "errno": 0, + // "errmsg": "success", + // "result": { + // "success": [ "avl12121", "bl3123123" ], + // "failed": [ "sd24564", "sdf6564564" ] + // } + // } + // + return response; + } + + nonce () { + return this.milliseconds (); + } + + sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { + let url = this.urls['api'][api] + '/' + path; + let keys = Object.keys (params); + const keysLength = keys.length; + if (api === 'public') { + if (keysLength > 0) { + url += '?' + this.urlencode (params); + } + } else { + const nonce = this.nonce ().toString (); + const uuid = this.uuid (); + const randomString = uuid.slice (0, 5); + const nonceString = nonce + '_' + randomString; + const auth = {}; + auth[this.apiKey] = this.apiKey; + auth[this.secret] = this.secret; + auth[nonceString] = nonceString; + for (let i = 0; i < keysLength; i++) { + const key = keys[i]; + auth[key] = key + '=' + params[key]; + } + const keysorted = this.keysort (auth); + let stringToSign = ''; + keys = Object.keys (keysorted); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + stringToSign += keysorted[key]; + } + const signature = this.hash (this.encode (stringToSign), 'sha1'); + headers = { + 'Nonce': nonceString, + 'Token': this.apiKey, + 'Signature': signature, + }; + if (method === 'POST') { + headers['Content-Type'] = 'application/x-www-form-urlencoded'; + if (keysLength > 0) { + body = this.urlencode (params); + } + } else { + if (keysLength > 0) { + url += '?' + this.urlencode (params); + } + } + } + return { 'url': url, 'method': method, 'body': body, 'headers': headers }; + } + + handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (response === undefined) { + return; + } + // + // {"errno":20501,"errmsg":"base symbol error"} + // + const error = this.safeString (response, 'errno'); + if ((error !== undefined) && (error !== '0')) { + const message = this.safeString (response, 'errmsg'); + const feedback = this.id + ' ' + body; + this.throwExactlyMatchedException (this.exceptions['exact'], error, feedback); + this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback); + throw new ExchangeError (feedback); // unknown message + } + } +}; diff --git a/TaskServer/node_modules/ccxt/js/base/Exchange.js b/TaskServer/node_modules/ccxt/js/base/Exchange.js index c7511a1ec..52cdf8b0e 100644 --- a/TaskServer/node_modules/ccxt/js/base/Exchange.js +++ b/TaskServer/node_modules/ccxt/js/base/Exchange.js @@ -48,17 +48,13 @@ const BN = require ('../static_dependencies/BN/bn') // ---------------------------------------------------------------------------- // web3 / 0x imports -let Web3 = undefined - , ethAbi = undefined +let ethAbi = undefined , ethUtil = undefined - , BigNumber = undefined try { const requireFunction = require; - Web3 = requireFunction ('web3') // eslint-disable-line global-require ethAbi = requireFunction ('ethereumjs-abi') // eslint-disable-line global-require ethUtil = requireFunction ('ethereumjs-util') // eslint-disable-line global-require - BigNumber = requireFunction ('bignumber.js') // eslint-disable-line global-require // we prefer bignumber.js over BN.js // BN = requireFunction ('bn.js') // eslint-disable-line global-require } catch (e) { @@ -77,6 +73,7 @@ module.exports = class Exchange { 'enableRateLimit': false, 'rateLimit': 2000, // milliseconds = seconds * 1000 'certified': false, + 'pro': false, 'has': { 'cancelAllOrders': false, 'cancelOrder': true, @@ -169,6 +166,7 @@ module.exports = class Exchange { '429': RateLimitExceeded, '404': ExchangeNotAvailable, '409': ExchangeNotAvailable, + '410': ExchangeNotAvailable, '500': ExchangeNotAvailable, '501': ExchangeNotAvailable, '502': ExchangeNotAvailable, @@ -276,8 +274,6 @@ module.exports = class Exchange { this.last_json_response = undefined this.last_response_headers = undefined - this.arrayConcat = (a, b) => a.concat (b) - const unCamelCaseProperties = (obj = this) => { if (obj !== null) { for (const k of Object.getOwnPropertyNames (obj)) { @@ -315,11 +311,6 @@ module.exports = class Exchange { if (this.markets) this.setMarkets (this.markets) - - if (this.requiresWeb3 && !this.web3 && Web3) { - const provider = (this.web3ProviderURL) ? new Web3.providers.HttpProvider (this.web3ProviderURL) : new Web3.providers.HttpProvider () - this.web3 = new Web3 (Web3.givenProvider || provider) - } } defaults () { @@ -367,7 +358,6 @@ module.exports = class Exchange { throw new Error (this.id + '.rateLimit property is not configured') this.tokenBucket = this.extend ({ - refillRate: 1 / this.rateLimit, delay: 1, capacity: 1, defaultCost: 1, @@ -472,42 +462,50 @@ module.exports = class Exchange { } } + print (... args) { + console.log (... args) + } + fetch (url, method = 'GET', headers = undefined, body = undefined) { if (isNode && this.userAgent) { - if (typeof this.userAgent === 'string') + if (typeof this.userAgent === 'string') { headers = extend ({ 'User-Agent': this.userAgent }, headers) - else if ((typeof this.userAgent === 'object') && ('User-Agent' in this.userAgent)) + } else if ((typeof this.userAgent === 'object') && ('User-Agent' in this.userAgent)) { headers = extend (this.userAgent, headers) + } } if (typeof this.proxy === 'function') { url = this.proxy (url) - if (isNode) + if (isNode) { headers = extend ({ 'Origin': this.origin }, headers) + } } else if (typeof this.proxy === 'string') { - if (this.proxy.length) - if (isNode) - headers = extend ({ 'Origin': this.origin }, headers) + if (this.proxy.length && isNode) { + headers = extend ({ 'Origin': this.origin }, headers) + } url = this.proxy + url } headers = extend (this.headers, headers) - if (this.verbose) - console.log ("fetch:\n", this.id, method, url, "\nRequest:\n", headers, "\n", body, "\n") + if (this.verbose) { + this.print ("fetch:\n", this.id, method, url, "\nRequest:\n", headers, "\n", body, "\n") + } return this.executeRestRequest (url, method, headers, body) } async fetch2 (path, type = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - if (this.enableRateLimit) - await this.throttle () + if (this.enableRateLimit) { + await this.throttle (this.rateLimit) + } const request = this.sign (path, type, method, params, headers, body) return this.fetch (request.url, request.method, request.headers, request.body) @@ -622,8 +620,9 @@ module.exports = class Exchange { this.last_json_response = json // FIXME: for those classes that haven't switched to handleErrors yet } - if (this.verbose) - console.log ("handleRestResponse:\n", this.id, method, url, response.status, response.statusText, "\nResponse:\n", responseHeaders, "\n", responseBody, "\n") + if (this.verbose) { + this.print ("handleRestResponse:\n", this.id, method, url, response.status, response.statusText, "\nResponse:\n", responseHeaders, "\n", responseBody, "\n") + } this.handleErrors (response.status, response.statusText, url, method, responseHeaders, responseBody, json, requestHeaders, requestBody) this.defaultErrorHandler (response.status, response.statusText, url, method, responseHeaders, responseBody, json) @@ -645,7 +644,7 @@ module.exports = class Exchange { if (currencies) { this.currencies = deepExtend (currencies, this.currencies) } else { - const baseCurrencies = + let baseCurrencies = values.filter (market => 'base' in market) .map (market => ({ id: market.baseId || market.base, @@ -653,7 +652,7 @@ module.exports = class Exchange { code: market.base, precision: market.precision ? (market.precision.base || market.precision.amount) : 8, })) - const quoteCurrencies = + let quoteCurrencies = values.filter (market => 'quote' in market) .map (market => ({ id: market.quoteId || market.quote, @@ -661,6 +660,10 @@ module.exports = class Exchange { code: market.quote, precision: market.precision ? (market.precision.quote || market.precision.price) : 8, })) + baseCurrencies = sortBy (baseCurrencies, 'code') + quoteCurrencies = sortBy (quoteCurrencies, 'code') + this.baseCurrencies = indexBy (baseCurrencies, 'code') + this.quoteCurrencies = indexBy (quoteCurrencies, 'code') const allCurrencies = baseCurrencies.concat (quoteCurrencies) const groupedCurrencies = groupBy (allCurrencies, 'code') const currencies = Object.keys (groupedCurrencies).map (code => @@ -673,7 +676,7 @@ module.exports = class Exchange { return this.markets } - async loadMarkets (reload = false, params = {}) { + async loadMarketsHelper (reload = false, params = {}) { if (!reload && this.markets) { if (!this.markets_by_id) { return this.setMarkets (this.markets) @@ -688,6 +691,21 @@ module.exports = class Exchange { return this.setMarkets (markets, currencies) } + // is async (returns a promise) + loadMarkets (reload = false, params = {}) { + if ((reload && !this.reloadingMarkets) || !this.marketsLoading) { + this.reloadingMarkets = true + this.marketsLoading = this.loadMarketsHelper (reload, params).then ((resolved) => { + this.reloadingMarkets = false + return resolved + }, (error) => { + this.reloadingMarkets = false + throw error + }) + } + return this.marketsLoading + } + async loadAccounts (reload = false, params = {}) { if (reload) { this.accounts = await this.fetchAccounts (params) @@ -725,43 +743,42 @@ module.exports = class Exchange { } parseTradingViewOHLCV (ohlcvs, market = undefined, timeframe = '1m', since = undefined, limit = undefined) { - const result = this.convertTradingViewToOHLCV (ohlcvs); - return this.parseOHLCVs (result, market, timeframe, since, limit); + const result = this.convertTradingViewToOHLCV (ohlcvs) + return this.parseOHLCVs (result, market, timeframe, since, limit) } - convertTradingViewToOHLCV (ohlcvs) { + convertTradingViewToOHLCV (ohlcvs, t = 't', o = 'o', h = 'h', l = 'l', c = 'c', v = 'v', ms = false) { const result = []; - for (let i = 0; i < ohlcvs['t'].length; i++) { + for (let i = 0; i < ohlcvs[t].length; i++) { result.push ([ - ohlcvs['t'][i] * 1000, - ohlcvs['o'][i], - ohlcvs['h'][i], - ohlcvs['l'][i], - ohlcvs['c'][i], - ohlcvs['v'][i], - ]); + ms ? ohlcvs[t][i] : (ohlcvs[t][i] * 1000), + ohlcvs[o][i], + ohlcvs[h][i], + ohlcvs[l][i], + ohlcvs[c][i], + ohlcvs[v][i], + ]) } - return result; + return result } - convertOHLCVToTradingView (ohlcvs) { - const result = { - 't': [], - 'o': [], - 'h': [], - 'l': [], - 'c': [], - 'v': [], - }; + convertOHLCVToTradingView (ohlcvs, t = 't', o = 'o', h = 'h', l = 'l', c = 'c', v = 'v', ms = false) { + const result = {} + result[t] = [] + result[o] = [] + result[h] = [] + result[l] = [] + result[c] = [] + result[v] = [] for (let i = 0; i < ohlcvs.length; i++) { - result['t'].push (parseInt (ohlcvs[i][0] / 1000)); - result['o'].push (ohlcvs[i][1]); - result['h'].push (ohlcvs[i][2]); - result['l'].push (ohlcvs[i][3]); - result['c'].push (ohlcvs[i][4]); - result['v'].push (ohlcvs[i][5]); + result[t].push (ms ? ohlcvs[i][0] : parseInt (ohlcvs[i][0] / 1000)) + result[o].push (ohlcvs[i][1]) + result[h].push (ohlcvs[i][2]) + result[l].push (ohlcvs[i][3]) + result[c].push (ohlcvs[i][4]) + result[v].push (ohlcvs[i][5]) } - return result; + return result } fetchTicker (symbol, params = {}) { @@ -993,8 +1010,8 @@ module.exports = class Exchange { async fetchStatus (params = {}) { if (this.has['fetchTime']) { - const time = await this.fetchTime(params) - return this.status = this.extend(this.status, { + const time = await this.fetchTime (params) + this.status = this.extend (this.status, { 'updated': time, }) } @@ -1026,27 +1043,34 @@ module.exports = class Exchange { return this.markets; } - filterBySinceLimit (array, since = undefined, limit = undefined, key = 'timestamp') { - if (since !== undefined && since !== null) - array = array.filter (entry => entry[key] >= since) - if (limit !== undefined && limit !== null) - array = array.slice (0, limit) + filterBySinceLimit (array, since = undefined, limit = undefined, key = 'timestamp', tail = false) { + const sinceIsDefined = (since !== undefined && since !== null) + if (sinceIsDefined) { + array = array.filter ((entry) => entry[key] >= since) + } + if (limit !== undefined && limit !== null) { + array = (tail && !sinceIsDefined) ? array.slice (-limit) : array.slice (0, limit) + } return array } - filterByValueSinceLimit (array, field, value = undefined, since = undefined, limit = undefined) { + filterByValueSinceLimit (array, field, value = undefined, since = undefined, limit = undefined, key = 'timestamp', tail = false) { const valueIsDefined = value !== undefined && value !== null const sinceIsDefined = since !== undefined && since !== null // single-pass filter for both symbol and since - if (valueIsDefined || sinceIsDefined) - array = Object.values (array).filter (entry => - ((valueIsDefined ? (entry[field] === value) : true) && - (sinceIsDefined ? (entry.timestamp >= since) : true))) + if (valueIsDefined || sinceIsDefined) { + array = Object.values (array).filter ((entry) => + ((valueIsDefined ? (entry[field] === value) : true) && + (sinceIsDefined ? (entry[key] >= since) : true))) + } - if (limit !== undefined && limit !== null) - array = Object.values (array).slice (0, limit) + if (limit !== undefined && limit !== null) { + array = ((tail && !sinceIsDefined) ? + Object.values (array).slice (-limit) : + Object.values (array).slice (0, limit)) + } return array } @@ -1064,13 +1088,15 @@ module.exports = class Exchange { objects = Object.values (objects) // return all of them if no values were passed - if (values === undefined || values === null) + if (values === undefined || values === null) { return indexed ? indexBy (objects, key) : objects + } const result = [] for (let i = 0; i < objects.length; i++) { - if (values.includes (objects[i][key])) + if (values.includes (objects[i][key])) { result.push (objects[i]) + } } return indexed ? indexBy (result, key) : result @@ -1081,7 +1107,7 @@ module.exports = class Exchange { // if (!this.isArray (trades)) { // throw new ExchangeError (this.id + ' parseTrades expected an array in the trades argument, but got ' + typeof trades); // } - let result = Object.values (trades || []).map (trade => this.extend (this.parseTrade (trade, market), params)) + let result = Object.values (trades || []).map ((trade) => this.extend (this.parseTrade (trade, market), params)) result = sortBy (result, 'timestamp') const symbol = (market !== undefined) ? market['symbol'] : undefined return this.filterBySymbolSinceLimit (result, symbol, since, limit) @@ -1092,7 +1118,7 @@ module.exports = class Exchange { // if (!this.isArray (transactions)) { // throw new ExchangeError (this.id + ' parseTransactions expected an array in the transactions argument, but got ' + typeof transactions); // } - let result = Object.values (transactions || []).map (transaction => this.extend (this.parseTransaction (transaction, currency), params)) + let result = Object.values (transactions || []).map ((transaction) => this.extend (this.parseTransaction (transaction, currency), params)) result = this.sortBy (result, 'timestamp'); const code = (currency !== undefined) ? currency['code'] : undefined; return this.filterByCurrencySinceLimit (result, code, since, limit); @@ -1248,97 +1274,32 @@ module.exports = class Exchange { // ------------------------------------------------------------------------ // web3 / 0x methods static hasWeb3 () { - return Web3 && ethUtil && ethAbi && BigNumber + return ethUtil && ethAbi } checkRequiredDependencies () { if (!Exchange.hasWeb3 ()) { - throw new ExchangeError ("Required dependencies missing: \nnpm i web3 ethereumjs-util ethereumjs-abi bignumber.js --no-save"); + throw new ExchangeError ('Required dependencies missing: \nnpm i ethereumjs-util ethereumjs-abi --no-save'); } } - ethDecimals (unit = 'ether') { - const units = { - 'wei': 0, // 1 - 'kwei': 3, // 1000 - 'babbage': 3, // 1000 - 'femtoether': 3, // 1000 - 'mwei': 6, // 1000000 - 'lovelace': 6, // 1000000 - 'picoether': 6, // 1000000 - 'gwei': 9, // 1000000000 - 'shannon': 9, // 1000000000 - 'nanoether': 9, // 1000000000 - 'nano': 9, // 1000000000 - 'szabo': 12, // 1000000000000 - 'microether': 12, // 1000000000000 - 'micro': 12, // 1000000000000 - 'finney': 15, // 1000000000000000 - 'milliether': 15, // 1000000000000000 - 'milli': 15, // 1000000000000000 - 'ether': 18, // 1000000000000000000 - 'kether': 21, // 1000000000000000000000 - 'grand': 21, // 1000000000000000000000 - 'mether': 24, // 1000000000000000000000000 - 'gether': 27, // 1000000000000000000000000000 - 'tether': 30, // 1000000000000000000000000000000 - } - return this.safeValue (units, unit) - } - - ethUnit (decimals = 18) { - const units = { - 0: 'wei', // 1000000000000000000 - 3: 'kwei', // 1000000000000000 - 6: 'mwei', // 1000000000000 - 9: 'gwei', // 1000000000 - 12: 'szabo', // 1000000 - 15: 'finney', // 1000 - 18: 'ether', // 1 - 21: 'kether', // 0.001 - 24: 'mether', // 0.000001 - 27: 'gether', // 0.000000001 - 30: 'tether', // 0.000000000001 - } - return this.safeValue (units, decimals) - } - - fromWei (amount, unit = 'ether', decimals = 18) { - if (amount === undefined) { - return amount - } - if (decimals !== 18) { - amount = new BigNumber (amount).times (new BigNumber (10 ** (18 - decimals))).toFixed () - } else { - amount = new BigNumber (amount).toFixed () - } - return parseFloat (this.web3.utils.fromWei (amount, unit)) - } - - toWei (amount, unit = 'ether', decimals = 18) { - if (amount === undefined) { - return amount - } - if (decimals !== 18) { - amount = new BigNumber (this.numberToString (amount)).div (new BigNumber (10 ** (18 - decimals))).toFixed () - } else { - amount = this.numberToString (amount) - } - return this.web3.utils.toWei (amount, unit) - } - soliditySha3 (array) { - const values = this.solidityValues (array); - const types = this.solidityTypes (values); - return '0x' + ethAbi.soliditySHA3 (types, values).toString ('hex') - } - - solidityTypes (array) { - return array.map (value => (this.web3.utils.isAddress (value) ? 'address' : 'uint256')) - } - - solidityValues (array) { - return array.map (value => (this.web3.utils.isAddress (value) ? value : (new BigNumber (value).toFixed ()))) + // we only support address, uint256, and string solidity types + const encoded = [] + for (const value of array) { + if (Number.isInteger (value) || value.match (/^[0-9]+$/)) { + encoded.push (this.numberToBE (this.numberToString (value), 32)) + } else { + const noPrefix = Exchange.remove0xPrefix (value) + if (noPrefix.length === 40 && noPrefix.toLowerCase ().match (/^[0-9a-f]+$/)) { // check if it is an address + encoded.push (this.base16ToBinary (noPrefix)) + } else { + encoded.push (this.stringToBinary (noPrefix)) + } + } + } + const concated = this.binaryConcatArray (encoded) + return '0x' + this.hash (concated, 'keccak', 'hex') } getZeroExOrderHash (order) { @@ -1424,15 +1385,6 @@ module.exports = class Exchange { ])).toString ('hex'); } - signZeroExOrder (order, privateKey) { - const orderHash = this.getZeroExOrderHash (order); - const signature = this.signMessage (orderHash, privateKey); - return this.extend (order, { - 'orderHash': orderHash, - 'ecSignature': signature, // todo fix v if needed - }) - } - signZeroExOrderV2 (order, privateKey) { const orderHash = this.getZeroExOrderHashV2 (order); const signature = this.signMessage (orderHash, privateKey); diff --git a/TaskServer/node_modules/ccxt/js/base/functions/generic.js b/TaskServer/node_modules/ccxt/js/base/functions/generic.js index 3cb881a5f..23970d702 100644 --- a/TaskServer/node_modules/ccxt/js/base/functions/generic.js +++ b/TaskServer/node_modules/ccxt/js/base/functions/generic.js @@ -31,6 +31,7 @@ module.exports = , index , ordered: x => x // a stub to keep assoc keys in order (in JS it does nothing, it's mostly for Python) , unique: x => Array.from (index (x)) + , arrayConcat: (a, b) => a.concat (b) /* ............................................. */ @@ -199,7 +200,7 @@ module.exports = return out } - + return x } @@ -217,22 +218,19 @@ module.exports = /* ............................................. */ , deepExtend: function deepExtend (...xs) { - let out = undefined - for (const x of xs) { - if (isDictionary (x)) { - - if (!isObject (out)) + if (!isObject (out)) { out = {} - - for (const k in x) + } + for (const k in x) { out[k] = deepExtend (out[k], x[k]) - - } else out = x + } + } else { + out = x + } } - return out } diff --git a/TaskServer/node_modules/ccxt/js/base/functions/number.js b/TaskServer/node_modules/ccxt/js/base/functions/number.js index 5f6ce75e4..e2f28933c 100644 --- a/TaskServer/node_modules/ccxt/js/base/functions/number.js +++ b/TaskServer/node_modules/ccxt/js/base/functions/number.js @@ -106,9 +106,13 @@ const decimalToPrecision = (x, roundingMode /* handle tick size */ if (countingMode === TICK_SIZE) { - const missing = x % numPrecisionDigits - const reminder = x / numPrecisionDigits - if (reminder !== Math.floor (reminder)) { + const precisionDigitsString = decimalToPrecision (numPrecisionDigits, ROUND, 100, DECIMAL_PLACES, NO_PADDING) + const newNumPrecisionDigits = precisionFromString (precisionDigitsString) + let missing = x % numPrecisionDigits + // See: https://github.com/ccxt/ccxt/pull/6486 + missing = Number (decimalToPrecision (missing, ROUND, 8, DECIMAL_PLACES, NO_PADDING)); + const fpError = decimalToPrecision (missing / numPrecisionDigits, ROUND, Math.max (newNumPrecisionDigits, 8), DECIMAL_PLACES, NO_PADDING) + if (precisionFromString (fpError) !== 0) { if (roundingMode === ROUND) { if (x > 0) { if (missing >= numPrecisionDigits / 2) { @@ -127,8 +131,6 @@ const decimalToPrecision = (x, roundingMode x = x - missing } } - const precisionDigitsString = decimalToPrecision (numPrecisionDigits, ROUND, 100, DECIMAL_PLACES, NO_PADDING) - const newNumPrecisionDigits = precisionFromString (precisionDigitsString) return decimalToPrecision (x, ROUND, newNumPrecisionDigits, DECIMAL_PLACES, paddingMode); } @@ -282,10 +284,33 @@ const decimalToPrecision = (x, roundingMode return String.fromCharCode (...out) } +// toWei / fromWei + +function fromWei (amount, decimals = 18) { + if (amount === undefined) { + return amount + } + const exponential = Math.floor (amount).toExponential () // wei must be whole numbers + const [ n, exponent ] = exponential.split ('e') + const newExponent = parseInt (exponent) - decimals + return parseFloat (n + 'e' + newExponent) +} + +function toWei (amount, decimals = 18) { + if (amount === undefined) { + return amount + } + const exponential = parseFloat (amount).toExponential () + const [ n, exponent ] = exponential.split ('e') + const newExponent = parseInt (exponent) + decimals + return numberToString (Math.floor (parseFloat (n + 'e' + newExponent))) // wei must be whole numbers +} + /* ------------------------------------------------------------------------ */ module.exports = { - + toWei, + fromWei, numberToString, precisionFromString, decimalToPrecision, diff --git a/TaskServer/node_modules/ccxt/js/base/functions/throttle.js b/TaskServer/node_modules/ccxt/js/base/functions/throttle.js index a6a15f0ab..e117291ff 100644 --- a/TaskServer/node_modules/ccxt/js/base/functions/throttle.js +++ b/TaskServer/node_modules/ccxt/js/base/functions/throttle.js @@ -18,7 +18,7 @@ module.exports = { const queue = [] - return Object.assign ((cost) => { + return Object.assign ((rateLimit, cost) => { if (queue.length > cfg.maxCapacity) throw new Error ('Backlog is over max capacity of ' + cfg.maxCapacity) @@ -46,7 +46,7 @@ module.exports = { const t = now () , elapsed = t - lastTimestamp lastTimestamp = t - numTokens = Math.min (cfg.capacity, numTokens + elapsed * cfg.refillRate) + numTokens = Math.min (cfg.capacity, numTokens + elapsed * (1 / rateLimit)) await sleep (cfg.delay) } running = false diff --git a/TaskServer/node_modules/ccxt/js/base/functions/type.js b/TaskServer/node_modules/ccxt/js/base/functions/type.js index c65a098db..6c2ed66bc 100644 --- a/TaskServer/node_modules/ccxt/js/base/functions/type.js +++ b/TaskServer/node_modules/ccxt/js/base/functions/type.js @@ -3,6 +3,7 @@ /* ------------------------------------------------------------------------ */ const isNumber = Number.isFinite + , isInteger = Number.isInteger , isArray = Array.isArray , hasProps = o => ((o !== undefined) && (o !== null)) , isString = s => (typeof s === 'string') @@ -25,6 +26,7 @@ const asFloat = x => ((isNumber (x) || isString (x)) ? parseFloat (x) : Na module.exports = { isNumber + , isInteger , isArray , isObject , isString diff --git a/TaskServer/node_modules/ccxt/js/bcex.js b/TaskServer/node_modules/ccxt/js/bcex.js index afd15bc10..fbb7b4271 100644 --- a/TaskServer/node_modules/ccxt/js/bcex.js +++ b/TaskServer/node_modules/ccxt/js/bcex.js @@ -29,7 +29,7 @@ module.exports = class bcex extends Exchange { 'fetchTradingLimits': true, }, 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/43362240-21c26622-92ee-11e8-9464-5801ec526d77.jpg', + 'logo': 'https://user-images.githubusercontent.com/51840849/77231516-851c6900-6bac-11ea-8fd6-ee5c23eddbd4.jpg', 'api': 'https://www.bcex.top', 'www': 'https://www.bcex.top', 'doc': 'https://github.com/BCEX-TECHNOLOGY-LIMITED/API_Docs/wiki/Interface', @@ -75,8 +75,8 @@ module.exports = class bcex extends Exchange { 'trading': { 'tierBased': false, 'percentage': true, - 'buy': 0.0, - 'sell': 0.2 / 100, + 'maker': 0.1 / 100, + 'taker': 0.2 / 100, }, 'funding': { 'tierBased': false, @@ -369,6 +369,7 @@ module.exports = class bcex extends Exchange { 'cost': cost, 'order': orderId, 'fee': undefined, + 'takerOrMaker': undefined, }; } @@ -517,6 +518,8 @@ module.exports = class bcex extends Exchange { 'remaining': this.safeFloat (order, 'numberover'), 'status': status, 'fee': undefined, + 'clientOrderId': undefined, + 'trades': undefined, }; } @@ -543,6 +546,7 @@ module.exports = class bcex extends Exchange { const result = { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -557,6 +561,7 @@ module.exports = class bcex extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; return result; } @@ -671,16 +676,4 @@ module.exports = class bcex extends Exchange { } } } - - calculateFee (symbol, type, side, amount, price, takerOrMaker = 'taker', params = {}) { - const market = this.markets[symbol]; - const rate = market[side]; - const cost = parseFloat (this.costToPrecision (symbol, amount * price)); - return { - 'type': takerOrMaker, - 'currency': market['quote'], - 'rate': rate, - 'cost': parseFloat (this.feeToPrecision (symbol, rate * cost)), - }; - } }; diff --git a/TaskServer/node_modules/ccxt/js/bequant.js b/TaskServer/node_modules/ccxt/js/bequant.js index 78d3cda1d..a2d9348e1 100644 --- a/TaskServer/node_modules/ccxt/js/bequant.js +++ b/TaskServer/node_modules/ccxt/js/bequant.js @@ -2,18 +2,22 @@ // --------------------------------------------------------------------------- -const hitbtc2 = require ('./hitbtc2'); +const hitbtc = require ('./hitbtc'); // --------------------------------------------------------------------------- -module.exports = class bequant extends hitbtc2 { +module.exports = class bequant extends hitbtc { describe () { return this.deepExtend (super.describe (), { 'id': 'bequant', 'name': 'Bequant', 'countries': [ 'MT' ], // Malta + 'pro': true, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/55248342-a75dfe00-525a-11e9-8aa2-05e9dca943c6.jpg', - 'api': 'https://api.bequant.io', + 'api': { + 'public': 'https://api.bequant.io', + 'private': 'https://api.bequant.io', + }, 'www': 'https://bequant.io', 'doc': [ 'https://api.bequant.io/', diff --git a/TaskServer/node_modules/ccxt/js/bibox.js b/TaskServer/node_modules/ccxt/js/bibox.js index 4865c70e4..083fccbe2 100644 --- a/TaskServer/node_modules/ccxt/js/bibox.js +++ b/TaskServer/node_modules/ccxt/js/bibox.js @@ -46,14 +46,14 @@ module.exports = class bibox extends Exchange { '1w': 'week', }, 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/34902611-2be8bf1a-f830-11e7-91a2-11b2f292e750.jpg', + 'logo': 'https://user-images.githubusercontent.com/51840849/77257418-3262b000-6c85-11ea-8fb8-20bdf20b3592.jpg', 'api': 'https://api.bibox.com', 'www': 'https://www.bibox.com', 'doc': [ 'https://biboxcom.github.io/en/', ], 'fees': 'https://bibox.zendesk.com/hc/en-us/articles/360002336133', - 'referral': 'https://www.bibox.com/signPage?id=11114745&lang=en', + 'referral': 'https://w2.bibox.com/login/register?invite_code=05Kj3I', }, 'api': { 'public': { @@ -62,11 +62,14 @@ module.exports = class bibox extends Exchange { 'mdata', ], 'get': [ + 'cquery', 'mdata', ], }, 'private': { 'post': [ + 'cquery', + 'ctrade', 'user', 'orderpending', 'transfer', @@ -83,7 +86,7 @@ module.exports = class bibox extends Exchange { 'tierBased': false, 'percentage': true, 'taker': 0.001, - 'maker': 0.001, + 'maker': 0.0008, }, 'funding': { 'tierBased': false, @@ -710,6 +713,7 @@ module.exports = class bibox extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -724,6 +728,7 @@ module.exports = class bibox extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/bigone.js b/TaskServer/node_modules/ccxt/js/bigone.js index b8093a1c7..31eb326e7 100644 --- a/TaskServer/node_modules/ccxt/js/bigone.js +++ b/TaskServer/node_modules/ccxt/js/bigone.js @@ -44,7 +44,7 @@ module.exports = class bigone extends Exchange { '1w': 'week1', '1M': 'month1', }, - 'hostname': 'big.one', // set to 'b1.run' for China mainland + 'hostname': 'big.one', // or 'bigone.com' 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/69354403-1d532180-0c91-11ea-88ed-44c06cefdf87.jpg', 'api': { @@ -735,6 +735,7 @@ module.exports = class bigone extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -922,7 +923,7 @@ module.exports = class bigone extends Exchange { // } // const trades = this.safeValue (response, 'data', []); - return this.parseTrades (trades, market, since, limit, params); + return this.parseTrades (trades, market, since, limit); } parseOrderStatus (status) { diff --git a/TaskServer/node_modules/ccxt/js/binance.js b/TaskServer/node_modules/ccxt/js/binance.js index 4ba1bec15..5853cb91a 100644 --- a/TaskServer/node_modules/ccxt/js/binance.js +++ b/TaskServer/node_modules/ccxt/js/binance.js @@ -3,8 +3,8 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, InvalidAddress } = require ('./base/errors'); -const { ROUND } = require ('./base/functions/number'); +const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, InvalidAddress, RateLimitExceeded, PermissionDenied } = require ('./base/errors'); +const { ROUND, TRUNCATE } = require ('./base/functions/number'); // --------------------------------------------------------------------------- @@ -16,6 +16,7 @@ module.exports = class binance extends Exchange { 'countries': [ 'JP', 'MT' ], // Japan, Malta 'rateLimit': 500, 'certified': true, + 'pro': true, // new metainfo interface 'has': { 'fetchDepositAddress': true, @@ -120,6 +121,15 @@ module.exports = class binance extends Exchange { 'sub-account/margin/account', 'sub-account/margin/accountSummary', 'sub-account/status', + // lending endpoints + 'lending/daily/product/list', + 'lending/daily/userLeftQuota', + 'lending/daily/userRedemptionQuota', + 'lending/daily/token/position', + 'lending/union/account', + 'lending/union/purchaseRecord', + 'lending/union/redemptionRecord', + 'lending/union/interestHistory', ], 'post': [ 'asset/dust', @@ -135,6 +145,9 @@ module.exports = class binance extends Exchange { 'sub-account/futures/enable', 'userDataStream', 'futures/transfer', + // lending + 'lending/daily/purchase', + 'lending/daily/redeem', ], 'put': [ 'userDataStream', @@ -174,18 +187,20 @@ module.exports = class binance extends Exchange { 'historicalTrades', 'aggTrades', 'klines', + 'fundingRate', 'premiumIndex', 'ticker/24hr', 'ticker/price', 'ticker/bookTicker', + 'allForceOrders', + 'openInterest', + 'leverageBracket', ], - 'put': [ 'listenKey' ], - 'post': [ 'listenKey' ], - 'delete': [ 'listenKey' ], }, 'fapiPrivate': { 'get': [ 'allOrders', + 'openOrder', 'openOrders', 'order', 'account', @@ -200,10 +215,15 @@ module.exports = class binance extends Exchange { 'marginType', 'order', 'leverage', + 'listenKey', + ], + 'put': [ + 'listenKey', ], 'delete': [ 'order', 'allOpenOrders', + 'listenKey', ], }, 'v3': { @@ -266,7 +286,7 @@ module.exports = class binance extends Exchange { }, // exchange-specific options 'options': { - 'fetchTradesMethod': 'publicGetAggTrades', + 'fetchTradesMethod': 'publicGetAggTrades', // publicGetTrades, publicGetHistoricalTrades 'fetchTickersMethod': 'publicGetTicker24hr', 'defaultTimeInForce': 'GTC', // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel 'defaultLimitOrderType': 'limit', // or 'limit_maker' @@ -287,7 +307,10 @@ module.exports = class binance extends Exchange { 'Order would trigger immediately.': InvalidOrder, 'Account has insufficient balance for requested action.': InsufficientFunds, 'Rest API trading is not enabled.': ExchangeNotAvailable, + "You don't have permission.": PermissionDenied, // {"msg":"You don't have permission.","success":false} + 'Market is closed.': ExchangeNotAvailable, // {"code":-1013,"msg":"Market is closed."} '-1000': ExchangeNotAvailable, // {"code":-1000,"msg":"An unknown error occured while processing the request."} + '-1003': RateLimitExceeded, // {"code":-1003,"msg":"Too much request weight used, current limit is 1200 request weight per 1 MINUTE. Please use the websocket for live updates to avoid polling the API."} '-1013': InvalidOrder, // createOrder -> 'invalid quantity'/'invalid price'/MIN_NOTIONAL '-1021': InvalidNonce, // 'your time is ahead of server' '-1022': AuthenticationError, // {"code":-1022,"msg":"Signature for this request is not valid."} @@ -311,13 +334,13 @@ module.exports = class binance extends Exchange { const type = this.safeString2 (this.options, 'fetchTime', 'defaultType', 'spot'); const method = (type === 'spot') ? 'publicGetTime' : 'fapiPublicGetTime'; const response = await this[method] (params); - return this.safeFloat (response, 'serverTime'); + return this.safeInteger (response, 'serverTime'); } async loadTimeDifference () { const serverTime = await this.fetchTime (); const after = this.milliseconds (); - this.options['timeDifference'] = parseInt (after - serverTime); + this.options['timeDifference'] = after - serverTime; return this.options['timeDifference']; } @@ -414,6 +437,7 @@ module.exports = class binance extends Exchange { const spot = !future; const marketType = spot ? 'spot' : 'future'; const id = this.safeString (market, 'symbol'); + const lowercaseId = this.safeStringLower (market, 'symbol'); const baseId = market['baseAsset']; const quoteId = market['quoteAsset']; const base = this.safeCurrencyCode (baseId); @@ -430,6 +454,7 @@ module.exports = class binance extends Exchange { const active = (status === 'TRADING'); const entry = { 'id': id, + 'lowercaseId': lowercaseId, 'symbol': symbol, 'base': base, 'quote': quote, @@ -481,6 +506,13 @@ module.exports = class binance extends Exchange { 'max': this.safeFloat (filter, 'maxQty'), }; } + if ('MARKET_LOT_SIZE' in filters) { + const filter = this.safeValue (filters, 'MARKET_LOT_SIZE', {}); + entry['limits']['market'] = { + 'min': this.safeFloat (filter, 'minQty'), + 'max': this.safeFloat (filter, 'maxQty'), + }; + } if ('MIN_NOTIONAL' in filters) { entry['limits']['cost']['min'] = this.safeFloat (filters['MIN_NOTIONAL'], 'minNotional'); } @@ -655,7 +687,7 @@ module.exports = class binance extends Exchange { } async fetchStatus (params = {}) { - const response = await this.wapiGetSystemStatus (); + const response = await this.wapiGetSystemStatus (params); let status = this.safeValue (response, 'status'); if (status !== undefined) { status = (status === 0) ? 'ok' : 'maintenance'; @@ -865,13 +897,23 @@ module.exports = class binance extends Exchange { // 'endTime': 789, // Timestamp in ms to get aggregate trades until INCLUSIVE. // 'limit': 500, // default = 500, maximum = 1000 }; - if (this.options['fetchTradesMethod'] === 'publicGetAggTrades') { + const defaultType = this.safeString2 (this.options, 'fetchTrades', 'defaultType', 'spot'); + const type = this.safeString (params, 'type', defaultType); + const query = this.omit (params, 'type'); + const defaultMethod = (type === 'future') ? 'fapiPublicGetTrades' : 'publicGetTrades'; + let method = this.safeString (this.options, 'fetchTradesMethod', defaultMethod); + if (method === 'publicGetAggTrades') { if (since !== undefined) { request['startTime'] = since; // https://github.com/ccxt/ccxt/issues/6400 // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#compressedaggregate-trades-list request['endTime'] = this.sum (since, 3600000); } + if (type === 'future') { + method = 'fapiPublicGetAggTrades'; + } + } else if ((method === 'publicGetHistoricalTrades') && (type === 'future')) { + method = 'fapiPublicGetHistoricalTrades'; } if (limit !== undefined) { request['limit'] = limit; // default = 500, maximum = 1000 @@ -885,8 +927,7 @@ module.exports = class binance extends Exchange { // - 'tradeId' accepted and returned by this method is "aggregate" trade id // which is different from actual trade id // - setting both fromId and time window results in error - const method = this.safeValue (this.options, 'fetchTradesMethod', 'publicGetTrades'); - const response = await this[method] (this.extend (request, params)); + const response = await this[method] (this.extend (request, query)); // // aggregate trades // @@ -933,6 +974,46 @@ module.exports = class binance extends Exchange { } parseOrder (order, market = undefined) { + // + // spot + // + // { + // "symbol": "LTCBTC", + // "orderId": 1, + // "clientOrderId": "myOrder1", + // "price": "0.1", + // "origQty": "1.0", + // "executedQty": "0.0", + // "cummulativeQuoteQty": "0.0", + // "status": "NEW", + // "timeInForce": "GTC", + // "type": "LIMIT", + // "side": "BUY", + // "stopPrice": "0.0", + // "icebergQty": "0.0", + // "time": 1499827319559, + // "updateTime": 1499827319559, + // "isWorking": true + // } + // + // futures + // + // { + // "symbol": "BTCUSDT", + // "orderId": 1, + // "clientOrderId": "myOrder1", + // "price": "0.1", + // "origQty": "1.0", + // "executedQty": "1.0", + // "cumQuote": "10.0", + // "status": "NEW", + // "timeInForce": "GTC", + // "type": "LIMIT", + // "side": "BUY", + // "stopPrice": "0.0", + // "updateTime": 1499827319559 + // } + // const status = this.parseOrderStatus (this.safeString (order, 'status')); let symbol = undefined; const marketId = this.safeString (order, 'symbol'); @@ -1017,9 +1098,11 @@ module.exports = class binance extends Exchange { cost = parseFloat (this.costToPrecision (symbol, cost)); } } + const clientOrderId = this.safeString (order, 'clientOrderId'); return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -1062,10 +1145,12 @@ module.exports = class binance extends Exchange { }; if (uppercaseType === 'MARKET') { const quoteOrderQty = this.safeFloat (params, 'quoteOrderQty'); + const precision = market['precision']['price']; if (quoteOrderQty !== undefined) { - request['quoteOrderQty'] = this.costToPrecision (symbol, quoteOrderQty); + request['quoteOrderQty'] = this.decimalToPrecision (quoteOrderQty, TRUNCATE, precision, this.precisionMode); + params = this.omit (params, 'quoteOrderQty'); } else if (price !== undefined) { - request['quoteOrderQty'] = this.costToPrecision (symbol, amount * price); + request['quoteOrderQty'] = this.decimalToPrecision (amount * price, TRUNCATE, precision, this.precisionMode); } else { request['quantity'] = this.amountToPrecision (symbol, amount); } @@ -1083,6 +1168,9 @@ module.exports = class binance extends Exchange { timeInForceIsRequired = true; } else if ((uppercaseType === 'STOP_LOSS') || (uppercaseType === 'TAKE_PROFIT')) { stopPriceIsRequired = true; + if (market['future']) { + priceIsRequired = true; + } } else if ((uppercaseType === 'STOP_LOSS_LIMIT') || (uppercaseType === 'TAKE_PROFIT_LIMIT')) { stopPriceIsRequired = true; priceIsRequired = true; @@ -1234,11 +1322,18 @@ module.exports = class binance extends Exchange { } await this.loadMarkets (); const market = this.market (symbol); + // https://github.com/ccxt/ccxt/issues/6507 + const origClientOrderId = this.safeValue (params, 'origClientOrderId'); const request = { 'symbol': market['id'], - 'orderId': parseInt (id), + // 'orderId': parseInt (id), // 'origClientOrderId': id, }; + if (origClientOrderId === undefined) { + request['orderId'] = parseInt (id); + } else { + request['origClientOrderId'] = origClientOrderId; + } const method = market['spot'] ? 'privateDeleteOrder' : 'fapiPrivateDeleteOrder'; const response = await this[method] (this.extend (request, params)); return this.parseOrder (response); @@ -1418,6 +1513,8 @@ module.exports = class binance extends Exchange { } if (since !== undefined) { request['startTime'] = since; + // max 3 months range https://github.com/ccxt/ccxt/issues/6495 + request['endTime'] = this.sum (since, 7776000000); } const response = await this.wapiGetDepositHistory (this.extend (request, params)); // @@ -1443,6 +1540,8 @@ module.exports = class binance extends Exchange { } if (since !== undefined) { request['startTime'] = since; + // max 3 months range https://github.com/ccxt/ccxt/issues/6495 + request['endTime'] = this.sum (since, 7776000000); } const response = await this.wapiGetWithdrawHistory (this.extend (request, params)); // @@ -1726,7 +1825,7 @@ module.exports = class binance extends Exchange { if (api === 'wapi') { url += '.html'; } - const userDataStream = ((path === 'userDataStream') || (path === 'listenKey')); + const userDataStream = (path === 'userDataStream') || (path === 'listenKey'); if (path === 'historicalTrades') { if (this.apiKey) { headers = { @@ -1830,9 +1929,13 @@ module.exports = class binance extends Exchange { // checks against error codes const error = this.safeString (response, 'code'); if (error !== undefined) { + // https://github.com/ccxt/ccxt/issues/6501 + if (error === '200') { + return; + } // a workaround for {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."} // despite that their message is very confusing, it is raised by Binance - // on a temporary ban (the API key is valid, but disabled for a while) + // on a temporary ban, the API key is valid, but disabled for a while if ((error === '-2015') && this.options['hasAlreadyAuthenticatedSuccessfully']) { throw new DDoSProtection (this.id + ' temporary banned: ' + body); } diff --git a/TaskServer/node_modules/ccxt/js/binanceje.js b/TaskServer/node_modules/ccxt/js/binanceje.js index dc7e0026a..bf6d251a9 100644 --- a/TaskServer/node_modules/ccxt/js/binanceje.js +++ b/TaskServer/node_modules/ccxt/js/binanceje.js @@ -13,6 +13,7 @@ module.exports = class binanceje extends binance { 'name': 'Binance Jersey', 'countries': [ 'JE' ], // Jersey 'certified': false, + 'pro': true, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/54874009-d526eb00-4df3-11e9-928c-ce6a2b914cd1.jpg', 'api': { diff --git a/TaskServer/node_modules/ccxt/js/binanceus.js b/TaskServer/node_modules/ccxt/js/binanceus.js index 611306672..e8c600cfc 100644 --- a/TaskServer/node_modules/ccxt/js/binanceus.js +++ b/TaskServer/node_modules/ccxt/js/binanceus.js @@ -13,6 +13,7 @@ module.exports = class binanceus extends binance { 'name': 'Binance US', 'countries': [ 'US' ], // US 'certified': false, + 'pro': true, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/65177307-217b7c80-da5f-11e9-876e-0b748ba0a358.jpg', 'api': { diff --git a/TaskServer/node_modules/ccxt/js/bit2c.js b/TaskServer/node_modules/ccxt/js/bit2c.js index 42b1907aa..d6b41b0d3 100644 --- a/TaskServer/node_modules/ccxt/js/bit2c.js +++ b/TaskServer/node_modules/ccxt/js/bit2c.js @@ -279,6 +279,7 @@ module.exports = class bit2c extends Exchange { const status = this.safeString (order, 'status'); return { 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -294,6 +295,7 @@ module.exports = class bit2c extends Exchange { 'trades': undefined, 'fee': undefined, 'info': order, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/bitbank.js b/TaskServer/node_modules/ccxt/js/bitbank.js index cc8dda8d7..8b8f35684 100644 --- a/TaskServer/node_modules/ccxt/js/bitbank.js +++ b/TaskServer/node_modules/ccxt/js/bitbank.js @@ -313,6 +313,7 @@ module.exports = class bitbank extends Exchange { const side = this.safeStringLower (order, 'side'); return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, diff --git a/TaskServer/node_modules/ccxt/js/bitbay.js b/TaskServer/node_modules/ccxt/js/bitbay.js index ef6373182..c2180de6e 100644 --- a/TaskServer/node_modules/ccxt/js/bitbay.js +++ b/TaskServer/node_modules/ccxt/js/bitbay.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { InvalidNonce, InsufficientFunds, AuthenticationError, InvalidOrder, ExchangeError, OrderNotFound } = require ('./base/errors'); +const { InvalidNonce, InsufficientFunds, AuthenticationError, InvalidOrder, ExchangeError, OrderNotFound, AccountSuspended, BadSymbol, OrderImmediatelyFillable, RateLimitExceeded } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -19,6 +19,22 @@ module.exports = class bitbay extends Exchange { 'withdraw': true, 'fetchMyTrades': true, 'fetchOpenOrders': true, + 'fetchOHLCV': true, + }, + 'timeframes': { + '1m': '60', + '3m': '180', + '5m': '300', + '15m': '900', + '30m': '1800', + '1h': '3600', + '2h': '7200', + '4h': '14400', + '6h': '21600', + '12h': '43200', + '1d': '86400', + '3d': '259200', + '1w': '604800', }, 'urls': { 'referral': 'https://auth.bitbay.net/ref/jHlbB4mIkdS1', @@ -134,13 +150,15 @@ module.exports = class bitbay extends Exchange { '503': InvalidNonce, // Invalid moment parameter. Request time doesn't match current server time '504': ExchangeError, // Invalid method '505': AuthenticationError, // Key has no permission for this action - '506': AuthenticationError, // Account locked. Please contact with customer service + '506': AccountSuspended, // Account locked. Please contact with customer service // codes 507 and 508 are not specified in their docs '509': ExchangeError, // The BIC/SWIFT is required for this currency - '510': ExchangeError, // Invalid market name + '510': BadSymbol, // Invalid market name 'FUNDS_NOT_SUFFICIENT': InsufficientFunds, 'OFFER_FUNDS_NOT_EXCEEDING_MINIMUMS': InvalidOrder, 'OFFER_NOT_FOUND': OrderNotFound, + 'OFFER_WOULD_HAVE_BEEN_PARTIALLY_FILLED': OrderImmediatelyFillable, + 'ACTION_LIMIT_EXCEEDED': RateLimitExceeded, }, }); } @@ -272,6 +290,7 @@ module.exports = class bitbay extends Exchange { } return { 'id': this.safeString (order, 'id'), + 'clientOrderId': undefined, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -743,6 +762,55 @@ module.exports = class bitbay extends Exchange { return this.safeString (types, type, type); } + parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) { + // [ + // '1582399800000', + // { + // o: '0.0001428', + // c: '0.0001428', + // h: '0.0001428', + // l: '0.0001428', + // v: '4', + // co: '1' + // } + // ] + return [ + parseInt (ohlcv[0]), + this.safeFloat (ohlcv[1], 'o'), + this.safeFloat (ohlcv[1], 'h'), + this.safeFloat (ohlcv[1], 'l'), + this.safeFloat (ohlcv[1], 'c'), + this.safeFloat (ohlcv[1], 'v'), + ]; + } + + async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const tradingSymbol = market['baseId'] + '-' + market['quoteId']; + const request = { + 'symbol': tradingSymbol, + 'resolution': this.timeframes[timeframe], + // 'from': 1574709092000, // unix timestamp in milliseconds, required + // 'to': 1574709092000, // unix timestamp in milliseconds, required + }; + if (limit === undefined) { + limit = 100; + } + const duration = this.parseTimeframe (timeframe); + const timerange = limit * duration * 1000; + if (since === undefined) { + request['to'] = this.milliseconds (); + request['from'] = request['to'] - timerange; + } else { + request['from'] = parseInt (since); + request['to'] = this.sum (request['from'], timerange); + } + const response = await this.v1_01PublicGetTradingCandleHistorySymbolResolution (this.extend (request, params)); + const ohlcvs = this.safeValue (response, 'items', []); + return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit); + } + parseTrade (trade, market = undefined) { // // createOrder trades @@ -978,6 +1046,7 @@ module.exports = class bitbay extends Exchange { 'average': undefined, 'fee': undefined, 'trades': trades, + 'clientOrderId': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/bitfinex.js b/TaskServer/node_modules/ccxt/js/bitfinex.js index 3ff8ac32f..883301578 100644 --- a/TaskServer/node_modules/ccxt/js/bitfinex.js +++ b/TaskServer/node_modules/ccxt/js/bitfinex.js @@ -17,6 +17,7 @@ module.exports = class bitfinex extends Exchange { 'version': 'v1', 'rateLimit': 1500, 'certified': true, + 'pro': true, // new metainfo interface 'has': { 'CORS': false, @@ -274,6 +275,7 @@ module.exports = class bitfinex extends Exchange { }, }, }, + // todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method 'commonCurrencies': { 'ABS': 'ABYSS', 'AIO': 'AION', @@ -309,7 +311,9 @@ module.exports = class bitfinex extends Exchange { 'UST': 'USDT', 'UTN': 'UTNP', 'VSY': 'VSYS', + 'WAX': 'WAXP', 'XCH': 'XCHF', + 'ZBT': 'ZB', }, 'exceptions': { 'exact': { @@ -411,7 +415,7 @@ module.exports = class bitfinex extends Exchange { 'YOYOW': 'yoyow', 'ZEC': 'zcash', 'ZRX': 'zrx', - 'XTZ': 'tezos', + 'XTZ': 'xtz', }, 'orderTypes': { 'limit': 'exchange limit', @@ -626,6 +630,7 @@ module.exports = class bitfinex extends Exchange { if (timestamp !== undefined) { timestamp *= 1000; } + timestamp = parseInt (timestamp); let symbol = undefined; if (market !== undefined) { symbol = market['symbol']; @@ -840,6 +845,7 @@ module.exports = class bitfinex extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -853,6 +859,8 @@ module.exports = class bitfinex extends Exchange { 'filled': this.safeFloat (order, 'executed_amount'), 'status': status, 'fee': undefined, + 'cost': undefined, + 'trades': undefined, }; } @@ -927,6 +935,7 @@ module.exports = class bitfinex extends Exchange { } getCurrencyName (code) { + // todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method if (code in this.options['currencyNames']) { return this.options['currencyNames'][code]; } @@ -939,18 +948,12 @@ module.exports = class bitfinex extends Exchange { 'renew': 1, }; const response = await this.fetchDepositAddress (code, this.extend (request, params)); - const address = this.safeString (response, 'address'); - this.checkAddress (address); - return { - 'info': response['info'], - 'currency': code, - 'address': address, - 'tag': undefined, - }; + return response; } async fetchDepositAddress (code, params = {}) { await this.loadMarkets (); + // todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method const name = this.getCurrencyName (code); const request = { 'method': name, @@ -1092,11 +1095,13 @@ module.exports = class bitfinex extends Exchange { async withdraw (code, amount, address, tag = undefined, params = {}) { this.checkAddress (address); + await this.loadMarkets (); + // todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method const name = this.getCurrencyName (code); const request = { 'withdraw_type': name, 'walletselected': 'exchange', - 'amount': amount.toString (), + 'amount': this.numberToString (amount), 'address': address, }; if (tag !== undefined) { diff --git a/TaskServer/node_modules/ccxt/js/bitfinex2.js b/TaskServer/node_modules/ccxt/js/bitfinex2.js index 520ef0b8f..89beea91a 100644 --- a/TaskServer/node_modules/ccxt/js/bitfinex2.js +++ b/TaskServer/node_modules/ccxt/js/bitfinex2.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const bitfinex = require ('./bitfinex.js'); -const { ExchangeError, NotSupported, InsufficientFunds } = require ('./base/errors'); +const { ExchangeError, InvalidAddress, ArgumentsRequired, InsufficientFunds, AuthenticationError, OrderNotFound, InvalidOrder, BadRequest, InvalidNonce, BadSymbol, OnMaintenance } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -15,21 +15,29 @@ module.exports = class bitfinex2 extends bitfinex { 'countries': [ 'VG' ], 'version': 'v2', 'certified': false, + 'pro': false, // new metainfo interface 'has': { - 'CORS': true, - 'createLimitOrder': false, - 'createMarketOrder': false, - 'createOrder': false, + 'CORS': false, + 'cancelAllOrders': true, + 'createDepositAddress': true, + 'createLimitOrder': true, + 'createMarketOrder': true, + 'createOrder': true, + 'cancelOrder': true, 'deposit': false, 'editOrder': false, - 'fetchDepositAddress': false, + 'fetchDepositAddress': true, 'fetchClosedOrders': false, 'fetchFundingFees': false, 'fetchMyTrades': true, 'fetchOHLCV': true, - 'fetchOpenOrders': false, - 'fetchOrder': true, + 'fetchOpenOrders': true, + 'fetchOrder': false, + 'fetchOpenOrder': true, + 'fetchClosedOrder': true, + 'fetchOrderTrades': true, + 'fetchStatus': true, 'fetchTickers': true, 'fetchTradingFee': false, 'fetchTradingFees': false, @@ -74,7 +82,30 @@ module.exports = class bitfinex2 extends bitfinex { }, 'public': { 'get': [ - 'conf/pub:map:currency:label', + 'conf/{config}', + 'conf/pub:{action}:{object}', + 'conf/pub:{action}:{object}:{detail}', + 'conf/pub:map:{object}', + 'conf/pub:map:{object}:{detail}', + 'conf/pub:map:currency:{detail}', + 'conf/pub:map:currency:sym', // maps symbols to their API symbols, BAB > BCH + 'conf/pub:map:currency:label', // verbose friendly names, BNT > Bancor + 'conf/pub:map:currency:unit', // maps symbols to unit of measure where applicable + 'conf/pub:map:currency:undl', // maps derivatives symbols to their underlying currency + 'conf/pub:map:currency:pool', // maps symbols to underlying network/protocol they operate on + 'conf/pub:map:currency:explorer', // maps symbols to their recognised block explorer URLs + 'conf/pub:map:tx:method', + 'conf/pub:list:{object}', + 'conf/pub:list:{object}:{detail}', + 'conf/pub:list:currency', + 'conf/pub:list:pair:exchange', + 'conf/pub:list:pair:margin', + 'conf/pub:list:competitions', + 'conf/pub:info:{object}', + 'conf/pub:info:{object}:{detail}', + 'conf/pub:info:pair', + 'conf/pub:info:tx:status', // [ deposit, withdrawal ] statuses 1 = active, 0 = maintenance + 'conf/pub:fees', 'platform/status', 'tickers', 'ticker/{symbol}', @@ -86,7 +117,11 @@ module.exports = class bitfinex2 extends bitfinex { 'book/{symbol}/P3', 'book/{symbol}/R0', 'stats1/{key}:{size}:{symbol}:{side}/{section}', + 'stats1/{key}:{size}:{symbol}:{side}/last', + 'stats1/{key}:{size}:{symbol}:{side}/hist', 'stats1/{key}:{size}:{symbol}/{section}', + 'stats1/{key}:{size}:{symbol}/last', + 'stats1/{key}:{size}:{symbol}/hist', 'stats1/{key}:{size}:{symbol}:long/last', 'stats1/{key}:{size}:{symbol}:long/hist', 'stats1/{key}:{size}:{symbol}:short/last', @@ -94,6 +129,11 @@ module.exports = class bitfinex2 extends bitfinex { 'candles/trade:{timeframe}:{symbol}/{section}', 'candles/trade:{timeframe}:{symbol}/last', 'candles/trade:{timeframe}:{symbol}/hist', + 'status/{type}', + 'status/deriv', + 'liquidations/hist', + 'rankings/{key}:{timeframe}:{symbol}/{section}', + 'rankings/{key}:{timeframe}:{symbol}/hist', ], 'post': [ 'calc/trade/avg', @@ -102,39 +142,69 @@ module.exports = class bitfinex2 extends bitfinex { }, 'private': { 'post': [ + // 'auth/r/orders/{symbol}/new', // outdated + // 'auth/r/stats/perf:{timeframe}/hist', // outdated 'auth/r/wallets', + 'auth/r/wallets/hist', + 'auth/r/orders', 'auth/r/orders/{symbol}', - 'auth/r/orders/{symbol}/new', - 'auth/r/orders/{symbol}/hist', - 'auth/r/order/{symbol}:{id}/trades', 'auth/w/order/submit', - 'auth/r/trades/hist', + 'auth/w/order/update', + 'auth/w/order/cancel', + 'auth/w/order/multi', + 'auth/w/order/cancel/multi', + 'auth/r/orders/{symbol}/hist', + 'auth/r/orders/hist', + 'auth/r/order/{symbol}:{id}/trades', 'auth/r/trades/{symbol}/hist', + 'auth/r/trades/hist', + 'auth/r/ledgers/{currency}/hist', + 'auth/r/ledgers/hist', + 'auth/r/info/margin/{key}', + 'auth/r/info/margin/base', + 'auth/r/info/margin/sym_all', 'auth/r/positions', + 'auth/w/position/claim', 'auth/r/positions/hist', 'auth/r/positions/audit', + 'auth/w/deriv/collateral/set', + 'auth/r/funding/offers', 'auth/r/funding/offers/{symbol}', + 'auth/w/funding/offer/submit', + 'auth/w/funding/offer/cancel', + 'auth/w/funding/offer/cancel/all', + 'auth/w/funding/close', + 'auth/w/funding/auto', + 'auth/w/funding/keep', 'auth/r/funding/offers/{symbol}/hist', + 'auth/r/funding/offers/hist', + 'auth/r/funding/loans', + 'auth/r/funding/loans/hist', 'auth/r/funding/loans/{symbol}', 'auth/r/funding/loans/{symbol}/hist', + 'auth/r/funding/credits', + 'auth/r/funding/credits/hist', 'auth/r/funding/credits/{symbol}', 'auth/r/funding/credits/{symbol}/hist', 'auth/r/funding/trades/{symbol}/hist', - 'auth/r/info/margin/{key}', + 'auth/r/funding/trades/hist', 'auth/r/info/funding/{key}', - 'auth/r/ledgers/hist', - 'auth/r/movements/hist', + 'auth/r/info/user', + 'auth/r/logins/hist', + 'auth/w/transfer', + 'auth/w/deposit/address', + 'auth/w/deposit/invoice', + 'auth/w/withdraw', 'auth/r/movements/{currency}/hist', - 'auth/r/stats/perf:{timeframe}/hist', + 'auth/r/movements/hist', 'auth/r/alerts', 'auth/w/alert/set', + 'auth/w/alert/price:{symbol}:{price}/del', 'auth/w/alert/{type}:{symbol}:{price}/del', 'auth/calc/order/avail', - 'auth/r/ledgers/{symbol}/hist', - 'auth/r/settings', 'auth/w/settings/set', + 'auth/r/settings', 'auth/w/settings/del', - 'auth/r/info/user', ], }, }, @@ -177,21 +247,31 @@ module.exports = class bitfinex2 extends bitfinex { }, 'options': { 'precision': 'R0', // P0, P1, P2, P3, P4, R0 - 'orderTypes': { - 'MARKET': undefined, + // convert 'EXCHANGE MARKET' to lowercase 'market' + // convert 'EXCHANGE LIMIT' to lowercase 'limit' + // everything else remains uppercase + 'exchangeTypes': { + // 'MARKET': undefined, 'EXCHANGE MARKET': 'market', - 'LIMIT': undefined, + // 'LIMIT': undefined, 'EXCHANGE LIMIT': 'limit', - 'STOP': undefined, - 'EXCHANGE STOP': 'stopOrLoss', - 'TRAILING STOP': undefined, - 'EXCHANGE TRAILING STOP': undefined, - 'FOK': undefined, - 'EXCHANGE FOK': 'limit FOK', - 'STOP LIMIT': undefined, - 'EXCHANGE STOP LIMIT': 'limit stop', - 'IOC': undefined, - 'EXCHANGE IOC': 'limit ioc', + // 'STOP': undefined, + // 'EXCHANGE STOP': undefined, + // 'TRAILING STOP': undefined, + // 'EXCHANGE TRAILING STOP': undefined, + // 'FOK': undefined, + // 'EXCHANGE FOK': undefined, + // 'STOP LIMIT': undefined, + // 'EXCHANGE STOP LIMIT': undefined, + // 'IOC': undefined, + // 'EXCHANGE IOC': undefined, + }, + // convert 'market' to 'EXCHANGE MARKET' + // convert 'limit' 'EXCHANGE LIMIT' + // everything else remains as is + 'orderTypes': { + 'market': 'EXCHANGE MARKET', + 'limit': 'EXCHANGE LIMIT', }, 'fiat': { 'USD': 'USD', @@ -200,6 +280,22 @@ module.exports = class bitfinex2 extends bitfinex { 'GBP': 'GBP', }, }, + 'exceptions': { + 'exact': { + '10020': BadRequest, + '10100': AuthenticationError, + '10114': InvalidNonce, + '20060': OnMaintenance, + }, + 'broad': { + 'address': InvalidAddress, + 'available balance is only': InsufficientFunds, + 'not enough exchange balance': InsufficientFunds, + 'Order not found': OrderNotFound, + 'symbol: invalid': BadSymbol, + 'Invalid order': InvalidOrder, + }, + }, }); } @@ -211,13 +307,27 @@ module.exports = class bitfinex2 extends bitfinex { return 'f' + code; } + async fetchStatus (params = {}) { + // + // [1] // operative + // [0] // maintenance + // + const response = await this.publicGetPlatformStatus (params); + const status = this.safeValue (response, 0); + const formattedStatus = (status === 1) ? 'ok' : 'maintenance'; + this.status = this.extend (this.status, { + 'status': formattedStatus, + 'updated': this.milliseconds (), + }); + return this.status; + } + async fetchMarkets (params = {}) { const response = await this.v1GetSymbolsDetails (params); const result = []; for (let i = 0; i < response.length; i++) { const market = response[i]; - let id = this.safeString (market, 'pair'); - id = id.toUpperCase (); + let id = this.safeStringUpper (market, 'pair'); let baseId = undefined; let quoteId = undefined; if (id.indexOf (':') >= 0) { @@ -407,6 +517,26 @@ module.exports = class bitfinex2 extends bitfinex { return this.parseTicker (ticker, market); } + parseSymbol (marketId) { + if (marketId === undefined) { + return marketId; + } + marketId = marketId.replace ('t', ''); + let baseId = undefined; + let quoteId = undefined; + if (marketId.indexOf (':') >= 0) { + const parts = marketId.split (':'); + baseId = parts[0]; + quoteId = parts[1]; + } else { + baseId = marketId.slice (0, 3); + quoteId = marketId.slice (3, 6); + } + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + return base + '/' + quote; + } + parseTrade (trade, market = undefined) { // // fetchTrades (public) @@ -453,26 +583,34 @@ module.exports = class bitfinex2 extends bitfinex { const timestamp = trade[timestampIndex]; if (isPrivate) { const marketId = trade[1]; - if (marketId !== undefined) { - if (marketId in this.markets_by_id) { - market = this.markets_by_id[marketId]; - symbol = market['symbol']; - } else { - symbol = marketId; - } + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + symbol = this.parseSymbol (marketId); } orderId = trade[3].toString (); takerOrMaker = (trade[8] === 1) ? 'maker' : 'taker'; - const feeCost = trade[9]; + let feeCost = trade[9]; const feeCurrency = this.safeCurrencyCode (trade[10]); if (feeCost !== undefined) { + feeCost = -feeCost; + if (symbol in this.markets) { + feeCost = this.feeToPrecision (symbol, feeCost); + } else { + const currencyId = 'f' + feeCurrency; + if (currencyId in this.currencies_by_id) { + const currency = this.currencies_by_id[currencyId]; + feeCost = this.currencyToPrecision (currency['code'], feeCost); + } + } fee = { - 'cost': Math.abs (feeCost), + 'cost': parseFloat (feeCost), 'currency': feeCurrency, }; } const orderType = trade[6]; - type = this.safeString (this.options['orderTypes'], orderType); + type = this.safeString (this.options['exchangeTypes'], orderType); } if (symbol === undefined) { if (market !== undefined) { @@ -555,24 +693,252 @@ module.exports = class bitfinex2 extends bitfinex { return this.parseOHLCVs (response, market, timeframe, since, limit); } + parseOrderStatus (status) { + const statuses = { + 'ACTIVE': 'open', + 'PARTIALLY FILLED': 'open', + 'EXECUTED': 'closed', + 'CANCELED': 'canceled', + 'INSUFFICIENT MARGIN': 'canceled', + 'INSUFFICIENT BALANCE (G1) was: PARTIALLY FILLED': 'canceled', + 'RSN_DUST': 'rejected', + 'RSN_PAUSE': 'rejected', + }; + return this.safeString (statuses, status, status); + } + + parseOrder (order, market = undefined) { + const id = this.safeString (order, 0); + let symbol = undefined; + const marketId = this.safeString (order, 3); + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } else { + symbol = this.parseSymbol (marketId); + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + // https://github.com/ccxt/ccxt/issues/6686 + // const timestamp = this.safeTimestamp (order, 5); + const timestamp = this.safeInteger (order, 5); + const remaining = Math.abs (this.safeFloat (order, 6)); + const amount = Math.abs (this.safeFloat (order, 7)); + const filled = amount - remaining; + const side = (order[7] < 0) ? 'sell' : 'buy'; + const orderType = this.safeString (order, 8); + const type = this.safeString (this.safeValue (this.options, 'exchangeTypes'), orderType); + let status = undefined; + const statusString = this.safeString (order, 13); + if (statusString !== undefined) { + const parts = statusString.split (' @ '); + status = this.parseOrderStatus (this.safeString (parts, 0)); + } + const price = this.safeFloat (order, 16); + const average = this.safeFloat (order, 17); + const cost = price * filled; + const clientOrderId = this.safeString (order, 2); + return { + 'info': order, + 'id': id, + 'clientOrderId': clientOrderId, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': undefined, + 'symbol': symbol, + 'type': type, + 'side': side, + 'price': price, + 'amount': amount, + 'cost': cost, + 'average': average, + 'filled': filled, + 'remaining': remaining, + 'status': status, + 'fee': undefined, + 'trades': undefined, + }; + } + async createOrder (symbol, type, side, amount, price = undefined, params = {}) { - throw new NotSupported (this.id + ' createOrder not implemented yet'); + await this.loadMarkets (); + const market = this.market (symbol); + const orderTypes = this.safeValue (this.options, 'orderTypes', {}); + const orderType = this.safeString (orderTypes, type, type); + amount = (side === 'sell') ? -amount : amount; + const request = { + 'symbol': market['id'], + 'type': orderType, + 'amount': this.numberToString (amount), + }; + if (type !== 'market') { + request['price'] = this.numberToString (price); + } + const response = await this.privatePostAuthWOrderSubmit (this.extend (request, params)); + // + // [ + // 1578784364.748, // Millisecond Time Stamp of the update + // "on-req", // Purpose of notification ('on-req', 'oc-req', 'uca', 'fon-req', 'foc-req') + // null, // Unique ID of the message + // null, // Ignore + // [ + // [ + // 37271830598, // Order ID + // null, // Group ID + // 1578784364748, // Client Order ID + // "tBTCUST", // Pair + // 1578784364748, // Millisecond timestamp of creation + // 1578784364748, // Millisecond timestamp of update + // -0.005, // Positive means buy, negative means sell + // -0.005, // Original amount + // "EXCHANGE LIMIT", // Order type (LIMIT, MARKET, STOP, TRAILING STOP, EXCHANGE MARKET, EXCHANGE LIMIT, EXCHANGE STOP, EXCHANGE TRAILING STOP, FOK, EXCHANGE FOK, IOC, EXCHANGE IOC) + // null, // Previous order type + // null, // Millisecond timestamp of Time-In-Force: automatic order cancellation + // null, // Ignore + // 0, // Flags (see https://docs.bitfinex.com/docs/flag-values) + // "ACTIVE", // Order Status + // null, // Ignore + // null, // Ignore + // 20000, // Price + // 0, // Average price + // 0, // The trailing price + // 0, // Auxiliary Limit price (for STOP LIMIT) + // null, // Ignore + // null, // Ignore + // null, // Ignore + // 0, // 1 - hidden order + // null, // If another order caused this order to be placed (OCO) this will be that other order's ID + // null, // Ignore + // null, // Ignore + // null, // Ignore + // "API>BFX", // Origin of action: BFX, ETHFX, API>BFX, API>ETHFX + // null, // Ignore + // null, // Ignore + // null // Meta + // ] + // ], + // null, // Error code + // "SUCCESS", // Status (SUCCESS, ERROR, FAILURE, ...) + // "Submitting 1 orders." // Text of the notification + // ] + // + const status = this.safeString (response, 6); + if (status !== 'SUCCESS') { + const errorCode = response[5]; + const errorText = response[7]; + throw new ExchangeError (this.id + ' ' + response[6] + ': ' + errorText + ' (#' + errorCode + ')'); + } + const orders = this.safeValue (response, 4, []); + const order = this.safeValue (orders, 0); + return this.parseOrder (order, market); } - cancelOrder (id, symbol = undefined, params = {}) { - throw new NotSupported (this.id + ' cancelOrder not implemented yet'); + async cancelAllOrders (symbol = undefined, params = {}) { + const request = { + 'all': 1, + }; + const response = await this.privatePostAuthWOrderCancelMulti (this.extend (request, params)); + const orders = this.safeValue (response, 4, []); + return this.parseOrders (orders); } - async fetchOrder (id, symbol = undefined, params = {}) { - throw new NotSupported (this.id + ' fetchOrder not implemented yet'); + async cancelOrder (id, symbol = undefined, params = {}) { + const cid = this.safeValue (params, 'cid'); // client order id + let request = undefined; + if (cid !== undefined) { + const cidDate = this.safeValue (params, 'cidDate'); // client order id date + if (cidDate === undefined) { + throw new InvalidOrder (this.id + " canceling an order by client order id ('cid') requires both 'cid' and 'cid_date' ('YYYY-MM-DD')"); + } + request = { + 'cid': cid, + 'cid_date': cidDate, + }; + } else { + request = { + 'id': parseInt (id), + }; + } + const response = await this.privatePostAuthWOrderCancel (this.extend (request, params)); + const order = this.safeValue (response, 4); + return this.parseOrder (order); } - async fetchDepositAddress (currency, params = {}) { - throw new NotSupported (this.id + ' fetchDepositAddress() not implemented yet.'); + async fetchOpenOrder (id, symbol = undefined, params = {}) { + const request = { + 'id': [ parseInt (id) ], + }; + const orders = await this.fetchOpenOrders (symbol, undefined, undefined, this.extend (request, params)); + const order = this.safeValue (orders, 0); + if (order === undefined) { + throw new OrderNotFound (this.id + ' order ' + id + ' not found'); + } + return order; } - async withdraw (code, amount, address, tag = undefined, params = {}) { - throw new NotSupported (this.id + ' withdraw not implemented yet'); + async fetchClosedOrder (id, symbol = undefined, params = {}) { + const request = { + 'id': [ parseInt (id) ], + }; + const orders = await this.fetchClosedOrders (symbol, undefined, undefined, this.extend (request, params)); + const order = this.safeValue (orders, 0); + if (order === undefined) { + throw new OrderNotFound (this.id + ' order ' + id + ' not found'); + } + return order; + } + + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = {}; + let market = undefined; + let response = undefined; + if (symbol === undefined) { + response = await this.privatePostAuthROrders (this.extend (request, params)); + } else { + market = this.market (symbol); + request['symbol'] = market['id']; + response = await this.privatePostAuthROrdersSymbol (this.extend (request, params)); + } + return this.parseOrders (response, market, since, limit); + } + + async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + // returns the most recent closed or canceled orders up to circa two weeks ago + await this.loadMarkets (); + const request = {}; + let market = undefined; + let response = undefined; + if (symbol === undefined) { + response = await this.privatePostAuthROrdersHist (this.extend (request, params)); + } else { + market = this.market (symbol); + request['symbol'] = market['id']; + response = await this.privatePostAuthROrdersSymbolHist (this.extend (request, params)); + } + if (since !== undefined) { + request['start'] = since; + } + if (limit !== undefined) { + request['limit'] = limit; // default 25, max 2500 + } + return this.parseOrders (response, market, since, limit); + } + + async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOrderTrades() requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const orderId = parseInt (id); + const request = { + 'id': orderId, + 'symbol': market['id'], + }; + // valid for trades upto 10 days old + const response = await this.privatePostAuthROrderSymbolIdTrades (this.extend (request, params)); + return this.parseTrades (response, market, since, limit); } async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { @@ -597,6 +963,170 @@ module.exports = class bitfinex2 extends bitfinex { return this.parseTrades (response, market, since, limit); } + async createDepositAddress (code, params = {}) { + await this.loadMarkets (); + const request = { + 'op_renew': 1, + }; + const response = await this.fetchDepositAddress (code, this.extend (request, params)); + return response; + } + + async fetchDepositAddress (code, params = {}) { + await this.loadMarkets (); + // todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method + const name = this.getCurrencyName (code); + const request = { + 'method': name, + 'wallet': 'exchange', // 'exchange', 'margin', 'funding' and also old labels 'exchange', 'trading', 'deposit', respectively + 'op_renew': 0, // a value of 1 will generate a new address + }; + const response = await this.privatePostAuthWDepositAddress (this.extend (request, params)); + // + // [ + // 1582269616687, // MTS Millisecond Time Stamp of the update + // 'acc_dep', // TYPE Purpose of notification 'acc_dep' for account deposit + // null, // MESSAGE_ID unique ID of the message + // null, // not documented + // [ + // null, // PLACEHOLDER + // 'BITCOIN', // METHOD Method of deposit + // 'BTC', // CURRENCY_CODE Currency code of new address + // null, // PLACEHOLDER + // '1BC9PZqpUmjyEB54uggn8TFKj49zSDYzqG', // ADDRESS + // null, // POOL_ADDRESS + // ], + // null, // CODE null or integer work in progress + // 'SUCCESS', // STATUS Status of the notification, SUCCESS, ERROR, FAILURE + // 'success', // TEXT Text of the notification + // ] + // + const result = this.safeValue (response, 4, []); + const poolAddress = this.safeString (result, 5); + const address = (poolAddress === undefined) ? this.safeString (result, 4) : poolAddress; + const tag = (poolAddress === undefined) ? undefined : this.safeString (result, 4); + this.checkAddress (address); + return { + 'currency': code, + 'address': address, + 'tag': tag, + 'info': response, + }; + } + + parseTransaction (transaction, currency = undefined) { + // + // withdraw + // + // [ + // 1582271520931, // MTS Millisecond Time Stamp of the update + // "acc_wd-req", // TYPE Purpose of notification 'acc_wd-req' account withdrawal request + // null, // MESSAGE_ID unique ID of the message + // null, // not documented + // [ + // 0, // WITHDRAWAL_ID Unique Withdrawal ID + // null, // PLACEHOLDER + // "bitcoin", // METHOD Method of withdrawal + // null, // PAYMENT_ID Payment ID if relevant + // "exchange", // WALLET Sending wallet + // 1, // AMOUNT Amount of Withdrawal less fee + // null, // PLACEHOLDER + // null, // PLACEHOLDER + // 0.0004, // WITHDRAWAL_FEE Fee on withdrawal + // ], + // null, // CODE null or integer Work in progress + // "SUCCESS", // STATUS Status of the notification, it may vary over time SUCCESS, ERROR, FAILURE + // "Invalid bitcoin address (abcdef)", // TEXT Text of the notification + // ] + // + // todo add support for all movements, deposits and withdrawals + // + const data = this.safeValue (transaction, 4, []); + const timestamp = this.safeInteger (transaction, 0); + let code = undefined; + if (currency !== undefined) { + code = currency['code']; + } + let feeCost = this.safeFloat (data, 8); + if (feeCost !== undefined) { + feeCost = Math.abs (feeCost); + } + const amount = this.safeFloat (data, 5); + let id = this.safeValue (data, 0); + let status = 'ok'; + if (id === 0) { + id = undefined; + status = 'failed'; + } + return { + 'info': transaction, + 'id': id, + 'txid': undefined, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'address': undefined, // this is actually the tag for XRP transfers (the address is missing) + 'tag': this.safeString (data, 3), // refix it properly for the tag from description + 'type': 'withdrawal', + 'amount': amount, + 'currency': code, + 'status': status, + 'updated': undefined, + 'fee': { + 'currency': code, + 'cost': feeCost, + 'rate': undefined, + }, + }; + } + + async withdraw (code, amount, address, tag = undefined, params = {}) { + this.checkAddress (address); + await this.loadMarkets (); + const currency = this.currency (code); + // todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method + const name = this.getCurrencyName (code); + const request = { + 'method': name, + 'wallet': 'exchange', // 'exchange', 'margin', 'funding' and also old labels 'exchange', 'trading', 'deposit', respectively + 'amount': this.numberToString (amount), + 'address': address, + }; + if (tag !== undefined) { + request['payment_id'] = tag; + } + const response = await this.privatePostAuthWWithdraw (this.extend (request, params)); + // + // [ + // 1582271520931, // MTS Millisecond Time Stamp of the update + // "acc_wd-req", // TYPE Purpose of notification 'acc_wd-req' account withdrawal request + // null, // MESSAGE_ID unique ID of the message + // null, // not documented + // [ + // 0, // WITHDRAWAL_ID Unique Withdrawal ID + // null, // PLACEHOLDER + // "bitcoin", // METHOD Method of withdrawal + // null, // PAYMENT_ID Payment ID if relevant + // "exchange", // WALLET Sending wallet + // 1, // AMOUNT Amount of Withdrawal less fee + // null, // PLACEHOLDER + // null, // PLACEHOLDER + // 0.0004, // WITHDRAWAL_FEE Fee on withdrawal + // ], + // null, // CODE null or integer Work in progress + // "SUCCESS", // STATUS Status of the notification, it may vary over time SUCCESS, ERROR, FAILURE + // "Invalid bitcoin address (abcdef)", // TEXT Text of the notification + // ] + // + const text = this.safeString (response, 7); + if (text !== 'success') { + this.throwBroadlyMatchedException (this.exceptions['broad'], text, text); + } + const transaction = this.parseTransaction (response, currency); + return this.extend (transaction, { + 'address': address, + }); + } + nonce () { return this.milliseconds (); } @@ -646,4 +1176,17 @@ module.exports = class bitfinex2 extends bitfinex { } return response; } + + handleErrors (statusCode, statusText, url, method, responseHeaders, responseBody, response, requestHeaders, requestBody) { + if (statusCode === 500) { + // See https://docs.bitfinex.com/docs/abbreviations-glossary#section-errorinfo-codes + const errorCode = this.numberToString (response[1]); + const errorText = response[2]; + const feedback = this.id + ' ' + errorText; + this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback); + this.throwExactlyMatchedException (this.exceptions['exact'], errorText, feedback); + this.throwBroadlyMatchedException (this.exceptions['broad'], errorText, feedback); + throw new ExchangeError (this.id + ' ' + errorText + ' (#' + errorCode + ')'); + } + } }; diff --git a/TaskServer/node_modules/ccxt/js/bitflyer.js b/TaskServer/node_modules/ccxt/js/bitflyer.js index 6d740fd3d..a9c5e99dc 100644 --- a/TaskServer/node_modules/ccxt/js/bitflyer.js +++ b/TaskServer/node_modules/ccxt/js/bitflyer.js @@ -356,6 +356,7 @@ module.exports = class bitflyer extends Exchange { const id = this.safeString (order, 'child_order_acceptance_id'); return { 'id': id, + 'clientOrderId': undefined, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -370,6 +371,8 @@ module.exports = class bitflyer extends Exchange { 'filled': filled, 'remaining': remaining, 'fee': fee, + 'average': undefined, + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/bitforex.js b/TaskServer/node_modules/ccxt/js/bitforex.js index a3c1724d7..4cb110431 100644 --- a/TaskServer/node_modules/ccxt/js/bitforex.js +++ b/TaskServer/node_modules/ccxt/js/bitforex.js @@ -220,6 +220,9 @@ module.exports = class bitforex extends Exchange { }, }, }, + 'commonCurrencies': { + 'UOS': 'UOS Network', + }, 'exceptions': { '4004': OrderNotFound, '1013': AuthenticationError, @@ -309,6 +312,7 @@ module.exports = class bitforex extends Exchange { 'cost': cost, 'order': orderId, 'fee': undefined, + 'takerOrMaker': undefined, }; } @@ -462,6 +466,7 @@ module.exports = class bitforex extends Exchange { const result = { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -476,6 +481,7 @@ module.exports = class bitforex extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; return result; } diff --git a/TaskServer/node_modules/ccxt/js/bithumb.js b/TaskServer/node_modules/ccxt/js/bithumb.js index 7a37629b4..057ea9b0a 100644 --- a/TaskServer/node_modules/ccxt/js/bithumb.js +++ b/TaskServer/node_modules/ccxt/js/bithumb.js @@ -129,6 +129,8 @@ module.exports = class bithumb extends Exchange { 'max': undefined, }, }, + 'baseId': undefined, + 'quoteId': undefined, }); } return result; diff --git a/TaskServer/node_modules/ccxt/js/bitlish.js b/TaskServer/node_modules/ccxt/js/bitlish.js deleted file mode 100644 index e45e529fc..000000000 --- a/TaskServer/node_modules/ccxt/js/bitlish.js +++ /dev/null @@ -1,378 +0,0 @@ -'use strict'; - -// --------------------------------------------------------------------------- - -const Exchange = require ('./base/Exchange'); -const { NotSupported } = require ('./base/errors'); - -// --------------------------------------------------------------------------- - -module.exports = class bitlish extends Exchange { - describe () { - return this.deepExtend (super.describe (), { - 'id': 'bitlish', - 'name': 'Bitlish', - 'countries': [ 'GB', 'EU', 'RU' ], - 'rateLimit': 1500, - 'version': 'v1', - 'has': { - 'CORS': false, - 'fetchTickers': true, - 'fetchOHLCV': true, - 'withdraw': true, - }, - 'timeframes': { - '1h': 3600, - }, - 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/27766275-dcfc6c30-5ed3-11e7-839d-00a846385d0b.jpg', - 'api': 'https://bitlish.com/api', - 'www': 'https://bitlish.com', - 'doc': 'https://bitlish.com/api', - 'fees': 'https://bitlish.com/fees', - }, - 'requiredCredentials': { - 'apiKey': true, - 'secret': false, - }, - 'fees': { - 'trading': { - 'tierBased': false, - 'percentage': true, - 'taker': 0.3 / 100, // anonymous 0.3%, verified 0.2% - 'maker': 0.2 / 100, // anonymous 0.2%, verified 0.1% - }, - 'funding': { - 'tierBased': false, - 'percentage': false, - 'withdraw': { - 'BTC': 0.001, - 'LTC': 0.001, - 'DOGE': 0.001, - 'ETH': 0.001, - 'XMR': 0, - 'ZEC': 0.001, - 'DASH': 0.0001, - 'EUR': 50, - }, - 'deposit': { - 'BTC': 0, - 'LTC': 0, - 'DOGE': 0, - 'ETH': 0, - 'XMR': 0, - 'ZEC': 0, - 'DASH': 0, - 'EUR': 0, - }, - }, - }, - 'api': { - 'public': { - 'get': [ - 'instruments', - 'ohlcv', - 'pairs', - 'tickers', - 'trades_depth', - 'trades_history', - ], - 'post': [ - 'instruments', - 'ohlcv', - 'pairs', - 'tickers', - 'trades_depth', - 'trades_history', - ], - }, - 'private': { - 'post': [ - 'accounts_operations', - 'balance', - 'cancel_trade', - 'cancel_trades_by_ids', - 'cancel_all_trades', - 'create_bcode', - 'create_template_wallet', - 'create_trade', - 'deposit', - 'list_accounts_operations_from_ts', - 'list_active_trades', - 'list_bcodes', - 'list_my_matches_from_ts', - 'list_my_trades', - 'list_my_trads_from_ts', - 'list_payment_methods', - 'list_payments', - 'redeem_code', - 'resign', - 'signin', - 'signout', - 'trade_details', - 'trade_options', - 'withdraw', - 'withdraw_by_id', - ], - }, - }, - 'commonCurrencies': { - 'DSH': 'DASH', - 'XDG': 'DOGE', - }, - }); - } - - async fetchMarkets (params = {}) { - const response = await this.publicGetPairs (params); - const result = []; - const keys = Object.keys (response); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - const market = response[key]; - const id = this.safeString (market, 'id'); - const name = this.safeString (market, 'name'); - const [ baseId, quoteId ] = name.split ('/'); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - const symbol = base + '/' + quote; - result.push ({ - 'id': id, - 'symbol': symbol, - 'base': base, - 'quote': quote, - 'baseId': baseId, - 'quoteId': quoteId, - 'info': market, - }); - } - return result; - } - - parseTicker (ticker, market) { - const timestamp = this.milliseconds (); - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; - } - const last = this.safeFloat (ticker, 'last'); - return { - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': symbol, - 'high': this.safeFloat (ticker, 'max'), - 'low': this.safeFloat (ticker, 'min'), - 'bid': this.safeFloat (ticker, 'bid'), - 'bidVolume': undefined, - 'ask': this.safeFloat (ticker, 'ask'), - 'askVolume': undefined, - 'vwap': undefined, - 'open': this.safeFloat (ticker, 'first'), - 'close': last, - 'last': last, - 'previousClose': undefined, - 'change': undefined, - 'percentage': this.safeFloat (ticker, 'prc') * 100, - 'average': undefined, - 'baseVolume': this.safeFloat (ticker, 'sum'), - 'quoteVolume': undefined, - 'info': ticker, - }; - } - - async fetchTickers (symbols = undefined, params = {}) { - await this.loadMarkets (); - const tickers = await this.publicGetTickers (params); - const ids = Object.keys (tickers); - const result = {}; - for (let i = 0; i < ids.length; i++) { - const id = ids[i]; - const market = this.safeValue (this.markets_by_id, id); - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; - } else { - const baseId = id.slice (0, 3); - const quoteId = id.slice (3, 6); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - symbol = base + '/' + quote; - } - const ticker = tickers[id]; - result[symbol] = this.parseTicker (ticker, market); - } - return result; - } - - async fetchTicker (symbol, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const response = await this.publicGetTickers (params); - const marketId = market['id']; - return this.parseTicker (response[marketId], market); - } - - async fetchOHLCV (symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - // let market = this.market (symbol); - const now = this.seconds (); - let start = now - 86400 * 30; // last 30 days - if (since !== undefined) { - start = parseInt (since / 1000); - } - const interval = [ start.toString (), undefined ]; - const request = { - 'time_range': interval, - }; - return await this.publicPostOhlcv (this.extend (request, params)); - } - - async fetchOrderBook (symbol, limit = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'pair_id': this.marketId (symbol), - }; - const response = await this.publicGetTradesDepth (this.extend (request, params)); - let timestamp = undefined; - const last = this.safeInteger (response, 'last'); - if (last !== undefined) { - timestamp = parseInt (last / 1000); - } - return this.parseOrderBook (response, timestamp, 'bid', 'ask', 'price', 'volume'); - } - - parseTrade (trade, market = undefined) { - const side = (trade['dir'] === 'bid') ? 'buy' : 'sell'; - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; - } - let timestamp = this.safeInteger (trade, 'created'); - if (timestamp !== undefined) { - timestamp = parseInt (timestamp / 1000); - } - const price = this.safeFloat (trade, 'price'); - const amount = this.safeFloat (trade, 'amount'); - let cost = undefined; - if (amount !== undefined) { - if (price !== undefined) { - cost = price * amount; - } - } - return { - 'id': undefined, - 'info': trade, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': symbol, - 'order': undefined, - 'type': undefined, - 'side': side, - 'takerOrMaker': undefined, - 'price': price, - 'amount': amount, - 'cost': cost, - 'fee': undefined, - }; - } - - async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const response = await this.publicGetTradesHistory (this.extend ({ - 'pair_id': market['id'], - }, params)); - return this.parseTrades (response['list'], market, since, limit); - } - - async fetchBalance (params = {}) { - await this.loadMarkets (); - const response = await this.privatePostBalance (params); - const result = { 'info': response }; - const currencyIds = Object.keys (response); - for (let i = 0; i < currencyIds.length; i++) { - const currencyId = currencyIds[i]; - const code = this.safeCurrencyCode (currencyId); - const account = this.account (); - const balance = this.safeValue (response, currencyId, {}); - account['free'] = this.safeFloat (balance, 'funds'); - account['used'] = this.safeFloat (balance, 'holded'); - result[code] = account; - } - return this.parseBalance (result); - } - - async signIn (params = {}) { - const request = { - 'login': this.login, - 'passwd': this.password, - }; - return await this.privatePostSignin (this.extend (request, params)); - } - - async createOrder (symbol, type, side, amount, price = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'pair_id': this.marketId (symbol), - 'dir': (side === 'buy') ? 'bid' : 'ask', - 'amount': amount, - }; - if (type === 'limit') { - request['price'] = price; - } - const response = await this.privatePostCreateTrade (this.extend (request, params)); - const id = this.safeString (response, 'id'); - return { - 'info': response, - 'id': id, - }; - } - - async cancelOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'id': id, - }; - return await this.privatePostCancelTrade (this.extend (request, params)); - } - - async withdraw (code, amount, address, tag = undefined, params = {}) { - if (code !== 'BTC') { - // they did not document other types... - throw new NotSupported (this.id + ' currently supports BTC withdrawals only, until they document other currencies...'); - } - this.checkAddress (address); - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'currency': currency['id'], - 'amount': parseFloat (amount), - 'account': address, - 'payment_method': 'bitcoin', // they did not document other types... - }; - const response = await this.privatePostWithdraw (this.extend (request, params)); - return { - 'info': response, - 'id': response['message_id'], - }; - } - - sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = this.urls['api'] + '/' + this.version + '/' + path; - if (api === 'public') { - if (method === 'GET') { - if (Object.keys (params).length) { - url += '?' + this.urlencode (params); - } - } else { - body = this.json (params); - headers = { 'Content-Type': 'application/json' }; - } - } else { - this.checkRequiredCredentials (); - body = this.json (this.extend ({ 'token': this.apiKey }, params)); - headers = { 'Content-Type': 'application/json' }; - } - return { 'url': url, 'method': method, 'body': body, 'headers': headers }; - } -}; diff --git a/TaskServer/node_modules/ccxt/js/bitmart.js b/TaskServer/node_modules/ccxt/js/bitmart.js index 3773ece77..c9a3a9bb3 100644 --- a/TaskServer/node_modules/ccxt/js/bitmart.js +++ b/TaskServer/node_modules/ccxt/js/bitmart.js @@ -150,6 +150,7 @@ module.exports = class bitmart extends Exchange { }, 'commonCurrencies': { 'ONE': 'Menlo One', + 'PLA': 'Plair', }, }); } @@ -248,6 +249,7 @@ module.exports = class bitmart extends Exchange { 'precision': precision, 'limits': limits, 'info': market, + 'active': undefined, }); } return result; @@ -681,6 +683,7 @@ module.exports = class bitmart extends Exchange { const type = undefined; return { 'id': id, + 'clientOrderId': undefined, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), diff --git a/TaskServer/node_modules/ccxt/js/bitmax.js b/TaskServer/node_modules/ccxt/js/bitmax.js index ec9754c07..cb3620f82 100644 --- a/TaskServer/node_modules/ccxt/js/bitmax.js +++ b/TaskServer/node_modules/ccxt/js/bitmax.js @@ -52,7 +52,7 @@ module.exports = class bitmax extends Exchange { 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/66820319-19710880-ef49-11e9-8fbe-16be62a11992.jpg', 'api': 'https://bitmax.io', - 'test': 'https://bitmax-test.io/api', + 'test': 'https://bitmax-test.io', 'www': 'https://bitmax.io', 'doc': [ 'https://github.com/bitmax-exchange/api-doc/blob/master/bitmax-api-doc-v1.2.md', @@ -121,12 +121,17 @@ module.exports = class bitmax extends Exchange { 'exact': { '2100': AuthenticationError, // {"code":2100,"message":"ApiKeyFailure"} '5002': BadSymbol, // {"code":5002,"message":"Invalid Symbol"} + '6001': BadSymbol, // {"code":6001,"message":"Trading is disabled on symbol."} '6010': InsufficientFunds, // {'code': 6010, 'message': 'Not enough balance.'} '60060': InvalidOrder, // { 'code': 60060, 'message': 'The order is already filled or canceled.' } '600503': InvalidOrder, // {"code":600503,"message":"Notional is too small."} }, 'broad': {}, }, + 'commonCurrencies': { + 'BTCBEAR': 'BEAR', + 'BTCBULL': 'BULL', + }, }); } @@ -722,9 +727,11 @@ module.exports = class bitmax extends Exchange { 'currency': this.safeString (order, 'feeAsset'), }; const average = this.safeFloat (order, 'avgPrice'); + const clientOrderId = id; return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -1145,7 +1152,7 @@ module.exports = class bitmax extends Exchange { headers['x-auth-coid'] = coid; } const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256', 'base64'); - headers['x-auth-signature'] = signature; + headers['x-auth-signature'] = this.decode (signature); if (method === 'GET') { if (Object.keys (query).length) { url += '?' + this.urlencode (query); diff --git a/TaskServer/node_modules/ccxt/js/bitmex.js b/TaskServer/node_modules/ccxt/js/bitmex.js index 43aed90cd..9cea5dbcc 100644 --- a/TaskServer/node_modules/ccxt/js/bitmex.js +++ b/TaskServer/node_modules/ccxt/js/bitmex.js @@ -17,6 +17,7 @@ module.exports = class bitmex extends Exchange { 'version': 'v1', 'userAgent': undefined, 'rateLimit': 2000, + 'pro': true, 'has': { 'CORS': false, 'fetchOHLCV': true, @@ -52,7 +53,7 @@ module.exports = class bitmex extends Exchange { 'https://github.com/BitMEX/api-connectors/tree/master/official-http', ], 'fees': 'https://www.bitmex.com/app/fees', - 'referral': 'https://www.bitmex.com/register/rm3C16', + 'referral': 'https://www.bitmex.com/register/upZpOX', }, 'api': { 'public': { @@ -1110,9 +1111,11 @@ module.exports = class bitmex extends Exchange { const id = this.safeString (order, 'orderID'); const type = this.safeStringLower (order, 'ordType'); const side = this.safeStringLower (order, 'side'); + const clientOrderId = this.safeString (order, 'clOrdID'); return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -1127,6 +1130,7 @@ module.exports = class bitmex extends Exchange { 'remaining': remaining, 'status': status, 'fee': undefined, + 'trades': undefined, }; } @@ -1211,7 +1215,15 @@ module.exports = class bitmex extends Exchange { async cancelOrder (id, symbol = undefined, params = {}) { await this.loadMarkets (); - const response = await this.privateDeleteOrder (this.extend ({ 'orderID': id }, params)); + // https://github.com/ccxt/ccxt/issues/6507 + const clOrdID = this.safeValue (params, 'clOrdID'); + const request = {}; + if (clOrdID === undefined) { + request['orderID'] = id; + } else { + request['clOrdID'] = clOrdID; + } + const response = await this.privateDeleteOrder (this.extend (request, params)); let order = response[0]; const error = this.safeString (order, 'error'); if (error !== undefined) { diff --git a/TaskServer/node_modules/ccxt/js/bitso.js b/TaskServer/node_modules/ccxt/js/bitso.js index 0ebc5ca39..b5f853005 100644 --- a/TaskServer/node_modules/ccxt/js/bitso.js +++ b/TaskServer/node_modules/ccxt/js/bitso.js @@ -16,7 +16,7 @@ module.exports = class bitso extends Exchange { 'rateLimit': 2000, // 30 requests per minute 'version': 'v3', 'has': { - 'CORS': true, + 'CORS': false, 'fetchMyTrades': true, 'fetchOpenOrders': true, 'fetchOrder': true, @@ -139,6 +139,7 @@ module.exports = class bitso extends Exchange { 'info': market, 'limits': limits, 'precision': precision, + 'active': undefined, }); } return result; @@ -369,9 +370,11 @@ module.exports = class bitso extends Exchange { filled = amount - remaining; } } + const clientOrderId = this.safeString (order, 'client_id'); return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -385,6 +388,8 @@ module.exports = class bitso extends Exchange { 'filled': filled, 'status': status, 'fee': undefined, + 'average': undefined, + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/bitstamp.js b/TaskServer/node_modules/ccxt/js/bitstamp.js index e2d0c6d5e..124d385fc 100644 --- a/TaskServer/node_modules/ccxt/js/bitstamp.js +++ b/TaskServer/node_modules/ccxt/js/bitstamp.js @@ -16,6 +16,7 @@ module.exports = class bitstamp extends Exchange { 'rateLimit': 1000, 'version': 'v2', 'userAgent': this.userAgents['chrome'], + 'pro': true, 'has': { 'CORS': true, 'fetchDepositAddress': true, @@ -31,6 +32,7 @@ module.exports = class bitstamp extends Exchange { 'api': { 'public': 'https://www.bitstamp.net/api', 'private': 'https://www.bitstamp.net/api', + 'v1': 'https://www.bitstamp.net/api', }, 'www': 'https://www.bitstamp.net', 'doc': 'https://www.bitstamp.net/api', @@ -233,8 +235,27 @@ module.exports = class bitstamp extends Exchange { 'pair': this.marketId (symbol), }; const response = await this.publicGetOrderBookPair (this.extend (request, params)); - const timestamp = this.safeTimestamp (response, 'timestamp'); - return this.parseOrderBook (response, timestamp); + // + // { + // "timestamp": "1583652948", + // "microtimestamp": "1583652948955826", + // "bids": [ + // [ "8750.00", "1.33685271" ], + // [ "8749.39", "0.07700000" ], + // [ "8746.98", "0.07400000" ], + // ] + // "asks": [ + // [ "8754.10", "1.51995636" ], + // [ "8754.71", "1.40000000" ], + // [ "8754.72", "2.50000000" ], + // ] + // } + // + const microtimestamp = this.safeInteger (response, 'microtimestamp'); + const timestamp = parseInt (microtimestamp / 1000); + const orderbook = this.parseOrderBook (response, timestamp); + orderbook['nonce'] = microtimestamp; + return orderbook; } async fetchTicker (symbol, params = {}) { @@ -946,6 +967,7 @@ module.exports = class bitstamp extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': lastTradeTimestamp, @@ -961,6 +983,7 @@ module.exports = class bitstamp extends Exchange { 'trades': trades, 'fee': fee, 'info': order, + 'average': undefined, }; } @@ -1023,7 +1046,10 @@ module.exports = class bitstamp extends Exchange { method += 'Post' + this.capitalize (name); method += v1 ? 'Deposit' : ''; method += 'Address'; - const response = await this[method] (params); + let response = await this[method] (params); + if (v1) { + response = JSON.parse (response); + } const address = v1 ? response : this.safeString (response, 'address'); const tag = v1 ? undefined : this.safeString (response, 'destination_tag'); this.checkAddress (address); @@ -1077,18 +1103,44 @@ module.exports = class bitstamp extends Exchange { } } else { this.checkRequiredCredentials (); - const nonce = this.nonce ().toString (); - const auth = nonce + this.uid + this.apiKey; - const signature = this.encode (this.hmac (this.encode (auth), this.encode (this.secret))); - query = this.extend ({ - 'key': this.apiKey, - 'signature': signature.toUpperCase (), - 'nonce': nonce, - }, query); - body = this.urlencode (query); - headers = { - 'Content-Type': 'application/x-www-form-urlencoded', - }; + const authVersion = this.safeValue (this.options, 'auth', 'v2'); + if ((authVersion === 'v1') || (api === 'v1')) { + const nonce = this.nonce ().toString (); + const auth = nonce + this.uid + this.apiKey; + const signature = this.encode (this.hmac (this.encode (auth), this.encode (this.secret))); + query = this.extend ({ + 'key': this.apiKey, + 'signature': signature.toUpperCase (), + 'nonce': nonce, + }, query); + body = this.urlencode (query); + headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + }; + } else { + const xAuth = 'BITSTAMP ' + this.apiKey; + const xAuthNonce = this.uuid (); + const xAuthTimestamp = this.milliseconds ().toString (); + const xAuthVersion = 'v2'; + let contentType = ''; + headers = { + 'X-Auth': xAuth, + 'X-Auth-Nonce': xAuthNonce, + 'X-Auth-Timestamp': xAuthTimestamp, + 'X-Auth-Version': xAuthVersion, + }; + if (method === 'POST') { + if (Object.keys (query).length) { + body = this.urlencode (query); + contentType = 'application/x-www-form-urlencoded'; + headers['Content-Type'] = contentType; + } + } + const authBody = body ? body : ''; + const auth = xAuth + method + url.replace ('https://', '') + contentType + xAuthNonce + xAuthTimestamp + xAuthVersion + authBody; + const signature = this.encode (this.hmac (this.encode (auth), this.encode (this.secret))); + headers['X-Auth-Signature'] = signature; + } } return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } diff --git a/TaskServer/node_modules/ccxt/js/bittrex.js b/TaskServer/node_modules/ccxt/js/bittrex.js index 19a8b2961..1510a6c0b 100644 --- a/TaskServer/node_modules/ccxt/js/bittrex.js +++ b/TaskServer/node_modules/ccxt/js/bittrex.js @@ -17,10 +17,11 @@ module.exports = class bittrex extends Exchange { 'version': 'v1.1', 'rateLimit': 1500, 'certified': true, + 'pro': true, // new metainfo interface 'has': { - 'CORS': true, - 'createMarketOrder': false, + 'CORS': false, + 'createMarketOrder': true, 'fetchDepositAddress': true, 'fetchClosedOrders': true, 'fetchCurrencies': true, @@ -62,6 +63,7 @@ module.exports = class bittrex extends Exchange { 'https://bittrex.zendesk.com/hc/en-us/articles/115003684371-BITTREX-SERVICE-FEES-AND-WITHDRAWAL-LIMITATIONS', 'https://bittrex.zendesk.com/hc/en-us/articles/115000199651-What-fees-does-Bittrex-charge-', ], + 'referral': 'https://bittrex.com/Account/Register?referralCode=1ZE-G0G-M3B', }, 'api': { 'v3': { @@ -214,6 +216,9 @@ module.exports = class bittrex extends Exchange { 'INVALID_CURRENCY': ExchangeError, 'INVALID_PERMISSION': AuthenticationError, 'INSUFFICIENT_FUNDS': InsufficientFunds, + 'INVALID_CEILING_MARKET_BUY': InvalidOrder, + 'INVALID_FIAT_ACCOUNT': InvalidOrder, + 'INVALID_ORDER_TYPE': InvalidOrder, 'QUANTITY_NOT_PROVIDED': InvalidOrder, 'MIN_TRADE_REQUIREMENT_NOT_MET': InvalidOrder, 'ORDER_NOT_OPEN': OrderNotFound, @@ -258,10 +263,10 @@ module.exports = class bittrex extends Exchange { // see the implementation of fetchClosedOrdersV3 below 'fetchClosedOrdersMethod': 'fetch_closed_orders_v3', 'fetchClosedOrdersFilterBySince': true, + // 'createOrderMethod': 'create_order_v1', }, 'commonCurrencies': { 'BITS': 'SWIFT', - 'CPC': 'Capricoin', }, }); } @@ -416,9 +421,6 @@ module.exports = class bittrex extends Exchange { for (let i = 0; i < currencies.length; i++) { const currency = currencies[i]; const id = this.safeString (currency, 'Currency'); - // todo: will need to rethink the fees - // to add support for multiple withdrawal/deposit methods and - // differentiated fees for each particular method const code = this.safeCurrencyCode (id); const precision = 8; // default precision, todo: fix "magic constants" const address = this.safeValue (currency, 'BaseAddress'); @@ -428,9 +430,9 @@ module.exports = class bittrex extends Exchange { 'code': code, 'address': address, 'info': currency, - 'type': currency['CoinType'], - 'name': currency['CurrencyLong'], - 'active': currency['IsActive'], + 'type': this.safeString (currency, 'CoinType'), + 'name': this.safeString (currency, 'CurrencyLong'), + 'active': this.safeValue (currency, 'IsActive'), 'fee': fee, 'precision': precision, 'limits': { @@ -664,6 +666,74 @@ module.exports = class bittrex extends Exchange { } async createOrder (symbol, type, side, amount, price = undefined, params = {}) { + const uppercaseType = type.toUpperCase (); + const isMarket = (uppercaseType === 'MARKET'); + const isCeilingLimit = (uppercaseType === 'CEILING_LIMIT'); + const isCeilingMarket = (uppercaseType === 'CEILING_MARKET'); + const isV3 = isMarket || isCeilingLimit || isCeilingMarket; + const defaultMethod = isV3 ? 'create_order_v3' : 'create_order_v1'; + const method = this.safeValue (this.options, 'createOrderMethod', defaultMethod); + return await this[method] (symbol, type, side, amount, price, params); + } + + async createOrderV3 (symbol, type, side, amount, price = undefined, params = {}) { + // A ceiling order is a market or limit order that allows you to specify + // the amount of quote currency you want to spend (or receive, if selling) + // instead of the quantity of the market currency (e.g. buy $100 USD of BTC + // at the current market BTC price) + await this.loadMarkets (); + const market = this.market (symbol); + const uppercaseType = type.toUpperCase (); + const reverseId = market['baseId'] + '-' + market['quoteId']; + const request = { + 'marketSymbol': reverseId, + 'direction': side.toUpperCase (), + 'type': uppercaseType, // LIMIT, MARKET, CEILING_LIMIT, CEILING_MARKET + // 'quantity': this.amountToPrecision (symbol, amount), // required for limit orders, excluded for ceiling orders + // 'ceiling': this.priceToPrecision (symbol, price), // required for ceiling orders, excluded for non-ceiling orders + // 'limit': this.priceToPrecision (symbol, price), // required for limit orders, excluded for market orders + // 'timeInForce': 'GOOD_TIL_CANCELLED', // IMMEDIATE_OR_CANCEL, FILL_OR_KILL, POST_ONLY_GOOD_TIL_CANCELLED + // 'useAwards': false, // optional + }; + const isCeilingLimit = (uppercaseType === 'CEILING_LIMIT'); + const isCeilingMarket = (uppercaseType === 'CEILING_MARKET'); + const isCeilingOrder = isCeilingLimit || isCeilingMarket; + if (isCeilingOrder) { + request['ceiling'] = this.priceToPrecision (symbol, price); + // bittrex only accepts IMMEDIATE_OR_CANCEL or FILL_OR_KILL for ceiling orders + request['timeInForce'] = 'IMMEDIATE_OR_CANCEL'; + } else { + request['quantity'] = this.amountToPrecision (symbol, amount); + if (uppercaseType === 'LIMIT') { + request['limit'] = this.priceToPrecision (symbol, price); + request['timeInForce'] = 'GOOD_TIL_CANCELLED'; + } else { + // bittrex does not allow GOOD_TIL_CANCELLED for market orders + request['timeInForce'] = 'IMMEDIATE_OR_CANCEL'; + } + } + const response = await this.v3PostOrders (this.extend (request, params)); + // + // { + // id: 'f03d5e98-b5ac-48fb-8647-dd4db828a297', + // marketSymbol: 'BTC-USDT', + // direction: 'SELL', + // type: 'LIMIT', + // quantity: '0.01', + // limit: '6000', + // timeInForce: 'GOOD_TIL_CANCELLED', + // fillQuantity: '0.00000000', + // commission: '0.00000000', + // proceeds: '0.00000000', + // status: 'OPEN', + // createdAt: '2020-03-18T02:37:33.42Z', + // updatedAt: '2020-03-18T02:37:33.42Z' + // } + // + return this.parseOrderV3 (response, market); + } + + async createOrderV1 (symbol, type, side, amount, price = undefined, params = {}) { if (type !== 'limit') { throw new ExchangeError (this.id + ' allows limit orders only'); } @@ -709,7 +779,10 @@ module.exports = class bittrex extends Exchange { // } // } // - return this.extend (this.parseOrder (response), { + const result = this.safeValue (response, 'result', {}); + return this.extend (this.parseOrder (result), { + 'id': id, + 'info': response, 'status': 'canceled', }); } @@ -977,6 +1050,7 @@ module.exports = class bittrex extends Exchange { } return { 'id': this.safeString (order, 'id'), + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -995,6 +1069,7 @@ module.exports = class bittrex extends Exchange { 'currency': feeCurrency, }, 'info': order, + 'trades': undefined, }; } @@ -1119,6 +1194,7 @@ module.exports = class bittrex extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -1133,6 +1209,7 @@ module.exports = class bittrex extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; } @@ -1175,6 +1252,7 @@ module.exports = class bittrex extends Exchange { 'datetime': this.iso8601 (timestamp), 'fee': this.safeValue (order, 'fee'), 'info': order, + 'takerOrMaker': undefined, }; } @@ -1322,10 +1400,16 @@ module.exports = class bittrex extends Exchange { } } else if (api === 'v3') { url += path; - if (Object.keys (params).length) { - url += '?' + this.rawencode (params); + let hashString = ''; + if (method === 'POST') { + body = this.json (params); + hashString = body; + } else { + if (Object.keys (params).length) { + url += '?' + this.rawencode (params); + } } - const contentHash = this.hash (this.encode (''), 'sha512', 'hex'); + const contentHash = this.hash (this.encode (hashString), 'sha512', 'hex'); const timestamp = this.milliseconds ().toString (); let auth = timestamp + url + method + contentHash; const subaccountId = this.safeValue (this.options, 'subaccountId'); @@ -1342,6 +1426,9 @@ module.exports = class bittrex extends Exchange { if (subaccountId !== undefined) { headers['Api-Subaccount-Id'] = subaccountId; } + if (method === 'POST') { + headers['Content-Type'] = 'application/json'; + } } else { this.checkRequiredCredentials (); url += api + '/'; @@ -1370,8 +1457,16 @@ module.exports = class bittrex extends Exchange { // { success: false, message: "message" } // if (body[0] === '{') { + const feedback = this.id + ' ' + body; let success = this.safeValue (response, 'success'); if (success === undefined) { + const code = this.safeString (response, 'code'); + if (code !== undefined) { + this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback); + if (code !== undefined) { + this.throwBroadlyMatchedException (this.exceptions['broad'], code, feedback); + } + } // throw new ExchangeError (this.id + ' malformed response ' + this.json (response)); return; } @@ -1381,7 +1476,6 @@ module.exports = class bittrex extends Exchange { } if (!success) { const message = this.safeString (response, 'message'); - const feedback = this.id + ' ' + body; if (message === 'APIKEY_INVALID') { if (this.options['hasAlreadyAuthenticatedSuccessfully']) { throw new DDoSProtection (feedback); diff --git a/TaskServer/node_modules/ccxt/js/bitz.js b/TaskServer/node_modules/ccxt/js/bitz.js index 7b6da7c50..0bf24b0ee 100644 --- a/TaskServer/node_modules/ccxt/js/bitz.js +++ b/TaskServer/node_modules/ccxt/js/bitz.js @@ -160,6 +160,7 @@ module.exports = class bitz extends Exchange { // https://github.com/ccxt/ccxt/issues/3881 // https://support.bit-z.pro/hc/en-us/articles/360007500654-BOX-BOX-Token- 'BOX': 'BOX Token', + 'LEO': 'LeoCoin', 'XRB': 'NANO', 'PXC': 'Pixiecoin', 'VTC': 'VoteCoin', @@ -753,6 +754,7 @@ module.exports = class bitz extends Exchange { const status = this.parseOrderStatus (this.safeString (order, 'status')); return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -768,6 +770,7 @@ module.exports = class bitz extends Exchange { 'trades': undefined, 'fee': undefined, 'info': order, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/bleutrade.js b/TaskServer/node_modules/ccxt/js/bleutrade.js index a75351e38..3bfdc13e9 100644 --- a/TaskServer/node_modules/ccxt/js/bleutrade.js +++ b/TaskServer/node_modules/ccxt/js/bleutrade.js @@ -1,99 +1,79 @@ 'use strict'; // --------------------------------------------------------------------------- - -const bittrex = require ('./bittrex.js'); -const { ExchangeError, AuthenticationError, InvalidOrder, InsufficientFunds } = require ('./base/errors'); +const Exchange = require ('./base/Exchange'); +const { ExchangeError, InvalidOrder, AuthenticationError, InsufficientFunds, BadRequest } = require ('./base/errors'); // --------------------------------------------------------------------------- -module.exports = class bleutrade extends bittrex { +module.exports = class bleutrade extends Exchange { describe () { - const timeframes = { - '15m': '15m', - '20m': '20m', - '30m': '30m', - '1h': '1h', - '2h': '2h', - '3h': '3h', - '4h': '4h', - '6h': '6h', - '8h': '8h', - '12h': '12h', - '1d': '1d', - }; - const result = this.deepExtend (super.describe (), { + return this.deepExtend (super.describe (), { 'id': 'bleutrade', 'name': 'Bleutrade', - 'countries': [ 'BR' ], // Brazil + 'countries': ['BR'], // Brazil 'rateLimit': 1000, - 'version': 'v2', 'certified': false, 'has': { 'CORS': true, + 'cancelOrder': false, // todo + 'createLimitOrder': false, // todo + 'createMarketOrder': false, // todo + 'createOrder': false, // todo + 'editOrder': false, // todo + 'withdraw': false, // todo + 'fetchTrades': false, 'fetchTickers': true, - 'fetchOrders': true, + 'fetchTicker': true, + 'fetchOrders': false, 'fetchClosedOrders': true, - 'fetchOrderTrades': true, + 'fetchOpenOrders': true, + 'fetchWithdrawals': true, + 'fetchOrderTrades': false, 'fetchLedger': true, + 'fetchDepositAddress': true, + }, + 'timeframes': { + '15m': '15m', + '20m': '20m', + '30m': '30m', + '1h': '1h', + '2h': '2h', + '3h': '3h', + '4h': '4h', + '6h': '6h', + '8h': '8h', + '12h': '12h', + '1d': '1d', }, - 'timeframes': timeframes, 'hostname': 'bleutrade.com', 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/30303000-b602dbe6-976d-11e7-956d-36c5049c01e7.jpg', 'api': { - 'public': 'https://{hostname}/api/v2', - 'account': 'https://{hostname}/api/v2', - 'market': 'https://{hostname}/api/v2', 'v3Private': 'https://{hostname}/api/v3/private', 'v3Public': 'https://{hostname}/api/v3/public', }, - 'www': 'https://bleutrade.com', + 'www': ['https://bleutrade.com'], 'doc': [ 'https://app.swaggerhub.com/apis-docs/bleu/white-label/3.0.0', ], - 'fees': 'https://bleutrade.com/help/fees_and_deadlines', + 'fees': 'https://bleutrade.com/fees/', }, 'api': { - 'account': { - 'get': [ - 'balance', - 'balances', - 'depositaddress', - 'deposithistory', - 'order', - 'orders', - 'orderhistory', - 'withdrawhistory', - 'withdraw', - ], - }, - 'public': { - 'get': [ - 'candles', - 'currencies', - 'markethistory', - 'markets', - 'marketsummaries', - 'marketsummary', - 'orderbook', - 'ticker', - ], - }, 'v3Public': { 'get': [ - 'assets', - 'markets', - 'ticker', - 'marketsummary', - 'marketsummaries', - 'orderbook', - 'markethistory', - 'candles', + 'getassets', + 'getmarkets', + 'getticker', + 'getmarketsummary', + 'getmarketsummaries', + 'getorderbook', + 'getmarkethistory', + 'getcandles', ], }, 'v3Private': { - 'get': [ + 'post': [ 'getbalance', 'getbalances', 'buylimit', @@ -104,6 +84,7 @@ module.exports = class bleutrade extends bittrex { 'sellstoplimit', 'ordercancel', 'getopenorders', + 'getcloseorders', 'getdeposithistory', 'getdepositaddress', 'getmytransactions', @@ -114,111 +95,110 @@ module.exports = class bleutrade extends bittrex { ], }, }, - 'fees': { - 'funding': { - 'withdraw': { - 'ADC': 0.1, - 'BTA': 0.1, - 'BITB': 0.1, - 'BTC': 0.001, - 'BCC': 0.001, - 'BTCD': 0.001, - 'BTG': 0.001, - 'BLK': 0.1, - 'CDN': 0.1, - 'CLAM': 0.01, - 'DASH': 0.001, - 'DCR': 0.05, - 'DGC': 0.1, - 'DP': 0.1, - 'DPC': 0.1, - 'DOGE': 10.0, - 'EFL': 0.1, - 'ETH': 0.01, - 'EXP': 0.1, - 'FJC': 0.1, - 'BSTY': 0.001, - 'GB': 0.1, - 'NLG': 0.1, - 'HTML': 1.0, - 'LTC': 0.001, - 'MONA': 0.01, - 'MOON': 1.0, - 'NMC': 0.015, - 'NEOS': 0.1, - 'NVC': 0.05, - 'OK': 0.1, - 'PPC': 0.1, - 'POT': 0.1, - 'XPM': 0.001, - 'QTUM': 0.1, - 'RDD': 0.1, - 'SLR': 0.1, - 'START': 0.1, - 'SLG': 0.1, - 'TROLL': 0.1, - 'UNO': 0.01, - 'VRC': 0.1, - 'VTC': 0.1, - 'XVP': 0.1, - 'WDC': 0.001, - 'ZET': 0.1, - }, - }, - }, 'commonCurrencies': { 'EPC': 'Epacoin', }, 'exceptions': { 'exact': { - 'Insufficient funds!': InsufficientFunds, - 'Invalid Order ID': InvalidOrder, - 'Invalid apikey or apisecret': AuthenticationError, + 'ERR_INSUFICIENT_BALANCE': InsufficientFunds, + 'ERR_LOW_VOLUME': BadRequest, + }, + 'broad': { + 'Order is not open': InvalidOrder, + 'Invalid Account / Api KEY / Api Secret': AuthenticationError, // also happens when an invalid nonce is used + }, + }, + 'fees': { + 'trading': { + 'tierBased': false, + 'percentage': true, + 'taker': 0.25 / 100, + 'maker': 0.25 / 100, }, }, 'options': { - // price precision by quote currency code - 'pricePrecisionByCode': { - 'USD': 3, - }, 'parseOrderStatus': true, - 'disableNonce': false, 'symbolSeparator': '_', }, }); - // bittrex inheritance override - result['timeframes'] = timeframes; + // undocumented api calls + // https://bleutrade.com/api/v3/public/tradingview/symbols?symbol=ETH_BTC + // https://bleutrade.com/api/v3/public/tradingview/config + // https://bleutrade.com/api/v3/public/tradingview/time + // https://bleutrade.com/api/v3/private/getcloseorders?market=ETH_BTC + // https://bleutrade.com/config contains the fees + } + + async fetchCurrencies (params = {}) { + const response = await this.v3PublicGetGetassets (params); + const items = response['result']; + const result = {}; + for (let i = 0; i < items.length; i++) { + // { Asset: 'USDT', + // AssetLong: 'Tether', + // MinConfirmation: 4, + // WithdrawTxFee: 1, + // WithdrawTxFeePercent: 0, + // SystemProtocol: 'ETHERC20', + // IsActive: true, + // InfoMessage: '', + // MaintenanceMode: false, + // MaintenanceMessage: '', + // FormatPrefix: '', + // FormatSufix: '', + // DecimalSeparator: '.', + // ThousandSeparator: ',', + // DecimalPlaces: 8, + // Currency: 'USDT', + // CurrencyLong: 'Tether', + // CoinType: 'ETHERC20' } + const item = items[i]; + const id = this.safeString (item, 'Asset'); + const code = this.safeCurrencyCode (id); + result[code] = { + 'id': id, + 'code': code, + 'name': this.safeString (item, 'AssetLong'), + 'active': this.safeValue (item, 'IsActive') && !this.safeValue (item, 'MaintenanceMode'), + 'fee': this.safeFloat (item, 'WithdrawTxFee'), + 'precision': this.safeFloat (item, 'DecimalPlaces'), + 'info': item, + 'limits': this.limits, + }; + } return result; } async fetchMarkets (params = {}) { // https://github.com/ccxt/ccxt/issues/5668 - const response = await this.publicGetMarkets (params); + const response = await this.v3PublicGetGetmarkets (params); const result = []; const markets = this.safeValue (response, 'result'); for (let i = 0; i < markets.length; i++) { const market = markets[i]; + // { MarketName: 'LTC_USDT', + // MarketAsset: 'LTC', + // BaseAsset: 'USDT', + // MarketAssetLong: 'Litecoin', + // BaseAssetLong: 'Tether', + // IsActive: true, + // MinTradeSize: 0.0001, + // InfoMessage: '', + // MarketCurrency: 'LTC', + // BaseCurrency: 'USDT', + // MarketCurrencyLong: 'Litecoin', + // BaseCurrencyLong: 'Tether' } const id = this.safeString (market, 'MarketName'); const baseId = this.safeString (market, 'MarketCurrency'); const quoteId = this.safeString (market, 'BaseCurrency'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const symbol = base + '/' + quote; - let pricePrecision = 8; - if (quote in this.options['pricePrecisionByCode']) { - pricePrecision = this.options['pricePrecisionByCode'][quote]; - } const precision = { 'amount': 8, - 'price': pricePrecision, + 'price': 8, }; - // bittrex uses boolean values, bleutrade uses strings - let active = this.safeValue (market, 'IsActive', false); - if ((active !== 'false') && active) { - active = true; - } else { - active = false; - } + const active = this.safeValue (market, 'IsActive', false); result.push ({ 'id': id, 'symbol': symbol, @@ -229,6 +209,8 @@ module.exports = class bleutrade extends bittrex { 'active': active, 'info': market, 'precision': precision, + 'maker': this.fees['trading']['maker'], + 'taker': this.fees['trading']['taker'], 'limits': { 'amount': { 'min': this.safeFloat (market, 'MinTradeSize'), @@ -244,51 +226,6 @@ module.exports = class bleutrade extends bittrex { return result; } - parseOrderStatus (status) { - const statuses = { - 'OK': 'closed', - 'OPEN': 'open', - 'CANCELED': 'canceled', - }; - return this.safeString (statuses, status, status); - } - - async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - // Possible params - // orderstatus (ALL, OK, OPEN, CANCELED) - // ordertype (ALL, BUY, SELL) - // depth (optional, default is 500, max is 20000) - await this.loadMarkets (); - let market = undefined; - let marketId = 'ALL'; - if (symbol !== undefined) { - market = this.market (symbol); - marketId = market['id']; - } - const request = { - 'market': marketId, - 'orderstatus': 'ALL', - }; - const response = await this.accountGetOrders (this.extend (request, params)); - return this.parseOrders (response['result'], market, since, limit); - } - - async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - const response = await this.fetchOrders (symbol, since, limit, params); - return this.filterBy (response, 'status', 'closed'); - } - - getOrderIdField () { - return 'orderid'; - } - - parseSymbol (id) { - let [ base, quote ] = id.split (this.options['symbolSeparator']); - base = this.safeCurrencyCode (base); - quote = this.safeCurrencyCode (quote); - return base + '/' + quote; - } - async fetchOrderBook (symbol, limit = undefined, params = {}) { await this.loadMarkets (); const request = { @@ -298,43 +235,104 @@ module.exports = class bleutrade extends bittrex { if (limit !== undefined) { request['depth'] = limit; // 50 } - const response = await this.publicGetOrderbook (this.extend (request, params)); + const response = await this.v3PublicGetGetorderbook (this.extend (request, params)); const orderbook = this.safeValue (response, 'result'); if (!orderbook) { - throw new ExchangeError (this.id + ' publicGetOrderbook() returneded no result ' + this.json (response)); + throw new ExchangeError (this.id + ' no orderbook data in ' + this.json (response)); } return this.parseOrderBook (orderbook, undefined, 'buy', 'sell', 'Rate', 'Quantity'); } - async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { - // Currently we can't set the makerOrTaker field, but if the user knows the order side then it can be - // determined (if the side of the trade is different to the side of the order, then the trade is maker). - // Similarly, the correct 'side' for the trade is that of the order. - // The trade fee can be set by the user, it is always 0.25% and is taken in the quote currency. + async fetchTicker (symbol, params = {}) { await this.loadMarkets (); + const market = this.market (symbol); const request = { - 'orderid': id, + 'market': market['id'], }; - const response = await this.accountGetOrderhistory (this.extend (request, params)); - return this.parseTrades (response['result'], undefined, since, limit, { - 'order': id, - }); + const response = await this.v3PublicGetGetmarketsummary (this.extend (request, params)); + const ticker = response['result'][0]; + return this.parseTicker (ticker, market); } - async fetchTransactionsByType (type, code = undefined, since = undefined, limit = undefined, params = {}) { + async fetchTickers (symbols = undefined, params = {}) { await this.loadMarkets (); - const method = (type === 'deposit') ? 'accountGetDeposithistory' : 'accountGetWithdrawhistory'; - const response = await this[method] (params); - const result = this.parseTransactions (response['result']); - return this.filterByCurrencySinceLimit (result, code, since, limit); + const response = await this.v3PublicGetGetmarketsummaries (params); + const result = this.safeValue (response, 'result'); + const tickers = []; + for (let i = 0; i < result.length; i++) { + const ticker = this.parseTicker (result[i]); + tickers.push (ticker); + } + return this.filterByArray (tickers, 'symbol', symbols); } - async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { - return await this.fetchTransactionsByType ('deposit', code, since, limit, params); - } - - async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { - return await this.fetchTransactionsByType ('withdrawal', code, since, limit, params); + parseTicker (ticker, market = undefined) { + // { TimeStamp: '2020-01-14 14:32:28', + // MarketName: 'LTC_USDT', + // MarketAsset: 'LTC', + // BaseAsset: 'USDT', + // MarketAssetName: 'Litecoin', + // BaseAssetName: 'Tether', + // PrevDay: 49.2867503, + // High: 56.78622664, + // Low: 49.27384025, + // Last: 53.94, + // Average: 51.37509368, + // Volume: 1.51282404, + // BaseVolume: 77.72147677, + // Bid: 53.62070218, + // Ask: 53.94, + // IsActive: 'true', + // InfoMessage: '', + // MarketCurrency: 'Litecoin', + // BaseCurrency: 'Tether' } + const timestamp = this.parse8601 (this.safeString (ticker, 'TimeStamp')); + let symbol = undefined; + const marketId = this.safeString (ticker, 'MarketName'); + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } else { + symbol = this.parseSymbol (marketId); + } + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const previous = this.safeFloat (ticker, 'PrevDay'); + const last = this.safeFloat (ticker, 'Last'); + let change = undefined; + let percentage = undefined; + if (last !== undefined) { + if (previous !== undefined) { + change = last - previous; + if (previous > 0) { + percentage = (change / previous) * 100; + } + } + } + return { + 'symbol': symbol, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'high': this.safeFloat (ticker, 'High'), + 'low': this.safeFloat (ticker, 'Low'), + 'bid': this.safeFloat (ticker, 'Bid'), + 'bidVolume': undefined, + 'ask': this.safeFloat (ticker, 'Ask'), + 'askVolume': undefined, + 'vwap': undefined, + 'open': previous, + 'close': last, + 'last': last, + 'previousClose': undefined, + 'change': change, + 'percentage': percentage, + 'average': undefined, + 'baseVolume': this.safeFloat (ticker, 'Volume'), + 'quoteVolume': this.safeFloat (ticker, 'BaseVolume'), + 'info': ticker, + }; } parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) { @@ -357,49 +355,133 @@ module.exports = class bleutrade extends bittrex { 'market': market['id'], 'count': limit, }; - const response = await this.publicGetCandles (this.extend (request, params)); - if ('result' in response) { - if (response['result']) { - return this.parseOHLCVs (response['result'], market, timeframe, since, limit); - } - } + const response = await this.v3PublicGetGetcandles (this.extend (request, params)); + return this.parseOHLCVs (response['result'], market, timeframe, since, limit); } - parseTrade (trade, market = undefined) { - const timestamp = this.parse8601 (trade['TimeStamp'] + '+00:00'); - let side = undefined; - if (trade['OrderType'] === 'BUY') { - side = 'buy'; - } else if (trade['OrderType'] === 'SELL') { - side = 'sell'; + async createOrder (symbol, type, side, amount, price = undefined, params = {}) { + if (type !== 'limit') { + // todo: STOP-LIMIT and AMI order types are supported + throw new InvalidOrder (this.id + ' allows limit orders only'); } - const id = this.safeString2 (trade, 'TradeID', 'ID'); - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; - } - let cost = undefined; - const price = this.safeFloat (trade, 'Price'); - const amount = this.safeFloat (trade, 'Quantity'); - if (amount !== undefined) { - if (price !== undefined) { - cost = price * amount; - } + await this.loadMarkets (); + const request = { + 'rate': this.priceToPrecision (symbol, price), + 'quantity': this.amountToPrecision (symbol, amount), + 'tradeType': (side === 'buy') ? '1' : '0', + 'market': this.marketId (symbol), + }; + let response = undefined; + if (side === 'buy') { + response = await this.v3PrivatePostBuylimit (this.extend (request, params)); + } else { + response = await this.v3PrivatePostSelllimit (this.extend (request, params)); } + // { success: true, + // message: "", + // result: "161105236" }, return { - 'id': id, - 'info': trade, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': symbol, - 'type': 'limit', - 'side': side, - 'order': undefined, - 'takerOrMaker': undefined, - 'price': price, - 'amount': amount, - 'cost': cost, - 'fee': undefined, + 'info': response, + 'id': this.safeString (response, 'result'), + }; + } + + async cancelOrder (id, symbol = undefined, params = {}) { + const request = { + 'orderid': id, + }; + const response = await this.v3PrivatePostOrdercancel (this.extend (request, params)); + // { success: true, message: '', result: '' } + return response; + } + + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let market = undefined; + const request = {}; + if (symbol !== undefined) { + market = this.market (symbol); + request['market'] = market['id']; + } + const response = await this.v3PrivatePostGetopenorders (this.extend (request, params)); + const items = this.safeValue (response, 'result', []); + return this.parseOrders (items, market, since, limit); + } + + parseSymbol (id) { + let [ base, quote ] = id.split (this.options['symbolSeparator']); + base = this.safeCurrencyCode (base); + quote = this.safeCurrencyCode (quote); + return base + '/' + quote; + } + + async fetchBalance (params = {}) { + await this.loadMarkets (); + const response = await this.v3PrivatePostGetbalances (params); + const result = { 'info': response }; + const items = response['result']; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + const currencyId = this.safeString (item, 'Asset'); + const code = this.safeCurrencyCode (currencyId); + const account = this.account (); + account['free'] = this.safeFloat (item, 'Available'); + account['total'] = this.safeFloat (item, 'Balance'); + result[code] = account; + } + return this.parseBalance (result); + } + + async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = {}; + let market = undefined; + if (symbol !== undefined) { + market = this.market (symbol); + request['market'] = market['id']; + } + const response = await this.v3PrivatePostGetcloseorders (this.extend (request, params)); + const orders = this.safeValue (response, 'result', []); + return this.parseOrders (orders, market, since, limit); + } + + async fetchTransactionsWithMethod (method, code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const response = await this[method] (params); + const transactions = this.safeValue (response, 'result', []); + return this.parseTransactions (transactions, code, since, limit); + } + + async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { + return await this.fetchTransactionsWithMethod ('v3PrivatePostGetdeposithistory', code, since, limit, params); + } + + async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { + return await this.fetchTransactionsWithMethod ('v3PrivatePostGetwithdrawhistory', code, since, limit, params); + } + + async fetchDepositAddress (code, params = {}) { + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'asset': currency['id'], + }; + const response = await this.v3PrivatePostGetdepositaddress (this.extend (request, params)); + // { success: true, + // message: '', + // result: + // { Asset: 'ETH', + // AssetName: 'Ethereum', + // DepositAddress: '0x748c5c8jhksjdfhd507d3aa9', + // Currency: 'ETH', + // CurrencyName: 'Ethereum' } } + const item = response['result']; + const address = this.safeString (item, 'DepositAddress'); + return { + 'currency': code, + 'address': this.checkAddress (address), + // 'tag': tag, + 'info': item, }; } @@ -477,7 +559,7 @@ module.exports = class bleutrade extends bittrex { 'currency': code, }; } else if (part.indexOf ('order id') === 0) { - referenceId = part.replace ('order id', ''); + referenceId = part.replace ('order id ', ''); } // // does not belong to Ledger, related to parseTransaction @@ -520,64 +602,44 @@ module.exports = class bleutrade extends bittrex { } async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) { - // - // if (code === undefined) { - // throw new ExchangeError (this.id + ' fetchClosedOrders requires a `symbol` argument'); - // } - // await this.loadMarkets (); - const request = {}; - // - // if (code !== undefined) { - // const currency = this.market (code); - // request['asset'] = currency['id']; - // } - // - const response = await this.v3PrivateGetGetmytransactions (this.extend (request, params)); - return this.parseLedger (response['result'], code, since, limit); + // only seems to return 100 items and there is no documented way to change page size or offset + const request = { + }; + const response = await this.v3PrivatePostGetmytransactions (this.extend (request, params)); + const items = response['result']; + return this.parseLedger (items, code, since, limit); } parseOrder (order, market = undefined) { // - // fetchOrders + // fetchClosedOrders // - // { - // OrderId: '107220258', - // Exchange: 'LTC_BTC', - // Type: 'SELL', - // Quantity: '2.13040000', - // QuantityRemaining: '0.00000000', - // Price: '0.01332672', - // Status: 'OK', - // Created: '2018-06-30 04:55:50', - // QuantityBaseTraded: '0.02839125', - // Comments: '' - // } + // { OrderID: 89742658, + // Exchange: 'DOGE_BTC', + // Type: 'BUY', + // Quantity: 10000, + // QuantityRemaining: 0, + // QuantityBaseTraded: 0, + // Price: 6.6e-7, + // Status: 'OK', + // Created: '2018-02-16 08:55:36', + // Comments: '' } // - let side = this.safeString2 (order, 'OrderType', 'Type'); - const isBuyOrder = (side === 'LIMIT_BUY') || (side === 'BUY'); - const isSellOrder = (side === 'LIMIT_SELL') || (side === 'SELL'); - if (isBuyOrder) { - side = 'buy'; - } - if (isSellOrder) { - side = 'sell'; - } - // We parse different fields in a very specific order. - // Order might well be closed and then canceled. - let status = undefined; - if (('Opened' in order) && order['Opened']) { - status = 'open'; - } - if (('Closed' in order) && order['Closed']) { - status = 'closed'; - } - if (('CancelInitiated' in order) && order['CancelInitiated']) { - status = 'canceled'; - } - if (('Status' in order) && this.options['parseOrderStatus']) { - status = this.parseOrderStatus (this.safeString (order, 'Status')); - } + // fetchOpenOrders + // + // { OrderID: 161105302, + // Exchange: 'ETH_BTC', + // Type: 'SELL', + // Quantity: 0.4, + // QuantityRemaining: 0.4, + // QuantityBaseTraded: 0, + // Price: 0.04, + // Status: 'OPEN', + // Created: '2020-01-22 09:21:27', + // Comments: { String: '', Valid: true } + const side = this.safeString (order, 'Type').toLowerCase (); + const status = this.parseOrderStatus (this.safeString (order, 'Status')); let symbol = undefined; const marketId = this.safeString (order, 'Exchange'); if (marketId === undefined) { @@ -593,41 +655,9 @@ module.exports = class bleutrade extends bittrex { } } let timestamp = undefined; - if ('Opened' in order) { - timestamp = this.parse8601 (order['Opened'] + '+00:00'); - } if ('Created' in order) { timestamp = this.parse8601 (order['Created'] + '+00:00'); } - let lastTradeTimestamp = undefined; - if (('TimeStamp' in order) && (order['TimeStamp'] !== undefined)) { - lastTradeTimestamp = this.parse8601 (order['TimeStamp'] + '+00:00'); - } - if (('Closed' in order) && (order['Closed'] !== undefined)) { - lastTradeTimestamp = this.parse8601 (order['Closed'] + '+00:00'); - } - if (timestamp === undefined) { - timestamp = lastTradeTimestamp; - } - let fee = undefined; - let commission = undefined; - if ('Commission' in order) { - commission = 'Commission'; - } else if ('CommissionPaid' in order) { - commission = 'CommissionPaid'; - } - if (commission) { - fee = { - 'cost': this.safeFloat (order, commission), - }; - if (market !== undefined) { - fee['currency'] = market['quote']; - } else if (symbol !== undefined) { - const currencyIds = symbol.split ('/'); - const quoteCurrencyId = currencyIds[1]; - fee['currency'] = this.safeCurrencyCode (quoteCurrencyId); - } - } let price = this.safeFloat (order, 'Price'); let cost = undefined; const amount = this.safeFloat (order, 'Quantity'); @@ -647,13 +677,14 @@ module.exports = class bleutrade extends bittrex { } } const average = this.safeFloat (order, 'PricePerUnit'); - const id = this.safeString2 (order, 'OrderUuid', 'OrderId'); + const id = this.safeString (order, 'OrderID'); return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), - 'lastTradeTimestamp': lastTradeTimestamp, + 'lastTradeTimestamp': undefined, 'symbol': symbol, 'type': 'limit', 'side': side, @@ -664,54 +695,56 @@ module.exports = class bleutrade extends bittrex { 'filled': filled, 'remaining': remaining, 'status': status, - 'fee': fee, + 'fee': undefined, + 'trades': undefined, }; } + parseOrderStatus (status) { + const statuses = { + 'OK': 'closed', + 'OPEN': 'open', + 'CANCELED': 'canceled', + }; + return this.safeString (statuses, status, status); + } + parseTransaction (transaction, currency = undefined) { // // deposit: // - // { - // Id: '96974373', - // Coin: 'DOGE', - // Amount: '12.05752192', - // TimeStamp: '2017-09-29 08:10:09', - // Label: 'DQqSjjhzCm3ozT4vAevMUHgv4vsi9LBkoE', - // } + // { ID: 118698752, + // Timestamp: '2020-01-21 11:16:09', + // Asset: 'ETH', + // Amount: 1, + // TransactionID: '', + // Status: 'CONFIRMED', + // Label: '0x748c5c8228d0c596f4d07f338blah', + // Symbol: 'ETH' } // // withdrawal: // - // { - // Id: '98009125', - // Coin: 'DOGE', - // Amount: '-483858.64312050', - // TimeStamp: '2017-11-22 22:29:05', - // Label: '483848.64312050;DJVJZ58tJC8UeUv9Tqcdtn6uhWobouxFLT;10.00000000', - // TransactionId: '8563105276cf798385fee7e5a563c620fea639ab132b089ea880d4d1f4309432', - // } + // { ID: 689281, + // Timestamp: '2019-07-05 13:14:43', + // Asset: 'BTC', + // Amount: -0.108959, + // TransactionID: 'da48d6901fslfjsdjflsdjfls852b87e362cad1', + // Status: 'CONFIRMED', + // Label: '0.1089590;35wztHPMgrebFvvblah;0.00100000', + // Symbol: 'BTC' } // - // { - // "Id": "95820181", - // "Coin": "BTC", - // "Amount": "-0.71300000", - // "TimeStamp": "2017-07-19 17:14:24", - // "Label": "0.71200000;PER9VM2txt4BTdfyWgvv3GziECRdVEPN63;0.00100000", - // "TransactionId": "CANCELED" - // } - // - const id = this.safeString (transaction, 'Id'); + const id = this.safeString (transaction, 'ID'); let amount = this.safeFloat (transaction, 'Amount'); let type = 'deposit'; if (amount < 0) { amount = Math.abs (amount); type = 'withdrawal'; } - const currencyId = this.safeString (transaction, 'Coin'); + const currencyId = this.safeString (transaction, 'Asset'); const code = this.safeCurrencyCode (currencyId, currency); const label = this.safeString (transaction, 'Label'); - const timestamp = this.parse8601 (this.safeString (transaction, 'TimeStamp')); - let txid = this.safeString (transaction, 'TransactionId'); + const timestamp = this.parse8601 (this.safeString (transaction, 'Timestamp')); + let txid = this.safeString (transaction, 'TransactionID'); let address = undefined; let feeCost = undefined; const labelParts = label.split (';'); @@ -751,31 +784,53 @@ module.exports = class bleutrade extends bittrex { }; } + nonce () { + return this.milliseconds (); + } + sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { let url = this.implodeParams (this.urls['api'][api], { 'hostname': this.hostname, }) + '/'; - if (api === 'v3Private' || api === 'account') { + if (api === 'v3Private') { this.checkRequiredCredentials (); - if (api === 'account') { - url += api + '/'; - } - if (((api === 'account') && (path !== 'withdraw')) || (path === 'openorders')) { - url += method.toLowerCase (); - } const request = { 'apikey': this.apiKey, + 'nonce': this.nonce (), }; - request['nonce'] = this.nonce (); url += path + '?' + this.urlencode (this.extend (request, params)); const signature = this.hmac (this.encode (url), this.encode (this.secret), 'sha512'); headers = { 'apisign': signature }; } else { - url += api + '/' + method.toLowerCase () + path; - if (Object.keys (params).length) { - url += '?' + this.urlencode (params); - } + url += path + '?' + this.urlencode (params); } return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } + + handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (response === undefined) { + return; // fallback to default error handler + } + // examples... + // {"success":false,"message":"Erro: Order is not open.","result":""} <-- 'error' is spelt wrong + // {"success":false,"message":"Error: Very low volume.","result":"ERR_LOW_VOLUME"} + // {"success":false,"message":"Error: Insuficient Balance","result":"ERR_INSUFICIENT_BALANCE"} + // + if (body[0] === '{') { + const success = this.safeValue (response, 'success'); + if (success === undefined) { + throw new ExchangeError (this.id + ': malformed response: ' + this.json (response)); + } + if (!success) { + const feedback = this.id + ' ' + body; + const errorCode = this.safeString (response, 'result'); + this.throwBroadlyMatchedException (this.exceptions['broad'], errorCode, feedback); + this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback); + const errorMessage = this.safeString (response, 'message'); + this.throwBroadlyMatchedException (this.exceptions['broad'], errorMessage, feedback); + this.throwExactlyMatchedException (this.exceptions['exact'], errorMessage, feedback); + throw new ExchangeError (feedback); + } + } + } }; diff --git a/TaskServer/node_modules/ccxt/js/braziliex.js b/TaskServer/node_modules/ccxt/js/braziliex.js index e3ef518ea..b082d1534 100644 --- a/TaskServer/node_modules/ccxt/js/braziliex.js +++ b/TaskServer/node_modules/ccxt/js/braziliex.js @@ -452,6 +452,7 @@ module.exports = class braziliex extends Exchange { const status = (filledPercentage === 1.0) ? 'closed' : 'open'; return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -467,6 +468,7 @@ module.exports = class braziliex extends Exchange { 'trades': undefined, 'fee': fee, 'info': info, + 'average': undefined, }; } @@ -590,7 +592,7 @@ module.exports = class braziliex extends Exchange { headers = { 'Content-type': 'application/x-www-form-urlencoded', 'Key': this.apiKey, - 'Sign': this.decode (signature), + 'Sign': signature, }; } return { 'url': url, 'method': method, 'body': body, 'headers': headers }; diff --git a/TaskServer/node_modules/ccxt/js/btcalpha.js b/TaskServer/node_modules/ccxt/js/btcalpha.js index 990ca8b69..4cdc5da22 100644 --- a/TaskServer/node_modules/ccxt/js/btcalpha.js +++ b/TaskServer/node_modules/ccxt/js/btcalpha.js @@ -151,6 +151,8 @@ module.exports = class btcalpha extends Exchange { }, }, 'info': market, + 'baseId': undefined, + 'quoteId': undefined, }); } return result; @@ -315,6 +317,7 @@ module.exports = class btcalpha extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'status': status, @@ -329,6 +332,8 @@ module.exports = class btcalpha extends Exchange { 'trades': trades, 'fee': undefined, 'info': order, + 'lastTradeTimestamp': undefined, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/btcbox.js b/TaskServer/node_modules/ccxt/js/btcbox.js index e9fa45401..87d6af7fa 100644 --- a/TaskServer/node_modules/ccxt/js/btcbox.js +++ b/TaskServer/node_modules/ccxt/js/btcbox.js @@ -242,7 +242,16 @@ module.exports = class btcbox extends Exchange { parseOrder (order, market = undefined) { // - // {"id":11,"datetime":"2014-10-21 10:47:20","type":"sell","price":42000,"amount_original":1.2,"amount_outstanding":1.2,"status":"closed","trades":[]} + // { + // "id":11, + // "datetime":"2014-10-21 10:47:20", + // "type":"sell", + // "price":42000, + // "amount_original":1.2, + // "amount_outstanding":1.2, + // "status":"closed", + // "trades":[] + // } // const id = this.safeString (order, 'id'); const datetimeString = this.safeString (order, 'datetime'); @@ -281,6 +290,7 @@ module.exports = class btcbox extends Exchange { const side = this.safeString (order, 'type'); return { 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -296,6 +306,7 @@ module.exports = class btcbox extends Exchange { 'trades': trades, 'fee': undefined, 'info': order, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/btcchina.js b/TaskServer/node_modules/ccxt/js/btcchina.js deleted file mode 100644 index b68b2e7b2..000000000 --- a/TaskServer/node_modules/ccxt/js/btcchina.js +++ /dev/null @@ -1,368 +0,0 @@ -'use strict'; - -// --------------------------------------------------------------------------- - -const Exchange = require ('./base/Exchange'); - -// --------------------------------------------------------------------------- - -module.exports = class btcchina extends Exchange { - describe () { - return this.deepExtend (super.describe (), { - 'id': 'btcchina', - 'name': 'BTCChina', - 'countries': [ 'CN' ], - 'rateLimit': 1500, - 'version': 'v1', - 'has': { - 'CORS': true, - }, - 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/27766368-465b3286-5ed6-11e7-9a11-0f6467e1d82b.jpg', - 'api': { - 'plus': 'https://plus-api.btcchina.com/market', - 'public': 'https://data.btcchina.com/data', - 'private': 'https://api.btcchina.com/api_trade_v1.php', - }, - 'www': 'https://www.btcchina.com', - 'doc': 'https://www.btcchina.com/apidocs', - }, - 'api': { - 'plus': { - 'get': [ - 'orderbook', - 'ticker', - 'trade', - ], - }, - 'public': { - 'get': [ - 'historydata', - 'orderbook', - 'ticker', - 'trades', - ], - }, - 'private': { - 'post': [ - 'BuyIcebergOrder', - 'BuyOrder', - 'BuyOrder2', - 'BuyStopOrder', - 'CancelIcebergOrder', - 'CancelOrder', - 'CancelStopOrder', - 'GetAccountInfo', - 'getArchivedOrder', - 'getArchivedOrders', - 'GetDeposits', - 'GetIcebergOrder', - 'GetIcebergOrders', - 'GetMarketDepth', - 'GetMarketDepth2', - 'GetOrder', - 'GetOrders', - 'GetStopOrder', - 'GetStopOrders', - 'GetTransactions', - 'GetWithdrawal', - 'GetWithdrawals', - 'RequestWithdrawal', - 'SellIcebergOrder', - 'SellOrder', - 'SellOrder2', - 'SellStopOrder', - ], - }, - }, - 'markets': { - 'BTC/CNY': { 'id': 'btccny', 'symbol': 'BTC/CNY', 'base': 'BTC', 'quote': 'CNY', 'api': 'public', 'plus': false }, - 'LTC/CNY': { 'id': 'ltccny', 'symbol': 'LTC/CNY', 'base': 'LTC', 'quote': 'CNY', 'api': 'public', 'plus': false }, - 'LTC/BTC': { 'id': 'ltcbtc', 'symbol': 'LTC/BTC', 'base': 'LTC', 'quote': 'BTC', 'api': 'public', 'plus': false }, - 'BCH/CNY': { 'id': 'bcccny', 'symbol': 'BCH/CNY', 'base': 'BCH', 'quote': 'CNY', 'api': 'plus', 'plus': true }, - 'ETH/CNY': { 'id': 'ethcny', 'symbol': 'ETH/CNY', 'base': 'ETH', 'quote': 'CNY', 'api': 'plus', 'plus': true }, - }, - }); - } - - async fetchMarkets (params = {}) { - const request = { - 'market': 'all', - }; - const markets = await this.publicGetTicker (this.extend (request, params)); - const result = []; - const keys = Object.keys (markets); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - const market = markets[key]; - const parts = key.split ('_'); - const id = parts[1]; - const baseId = id.slice (0, 3); - const quoteId = id.slice (3, 6); - let base = baseId.toUpperCase (); - let quote = quoteId.toUpperCase (); - base = this.safeCurrencyCode (base); - quote = this.safeCurrencyCode (quote); - const symbol = base + '/' + quote; - result.push ({ - 'id': id, - 'symbol': symbol, - 'base': base, - 'quote': quote, - 'baseId': baseId, - 'quoteId': quoteId, - 'info': market, - }); - } - return result; - } - - async fetchBalance (params = {}) { - await this.loadMarkets (); - const response = await this.privatePostGetAccountInfo (params); - const balances = this.safeValue (response, 'result'); - const result = { 'info': balances }; - const codes = Object.keys (this.currencies); - for (let i = 0; i < codes.length; i++) { - const code = codes[i]; - const currency = this.currency (code); - const account = this.account (); - const currencyId = currency['id']; - if (currencyId in balances['balance']) { - account['total'] = parseFloat (balances['balance'][currencyId]['amount']); - } - if (currencyId in balances['frozen']) { - account['used'] = parseFloat (balances['frozen'][currencyId]['amount']); - } - result[code] = account; - } - return this.parseBalance (result); - } - - createMarketRequest (market) { - const request = {}; - const field = (market['plus']) ? 'symbol' : 'market'; - request[field] = market['id']; - return request; - } - - async fetchOrderBook (symbol, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['api'] + 'GetOrderbook'; - const request = this.createMarketRequest (market); - const response = await this[method] (this.extend (request, params)); - const timestamp = this.safeTimestamp (response, 'date'); - return this.parseOrderBook (response, timestamp); - } - - parseTicker (ticker, market) { - const timestamp = this.safeTimestamp (ticker, 'date'); - const last = this.safeFloat (ticker, 'last'); - return { - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'high': this.safeFloat (ticker, 'high'), - 'low': this.safeFloat (ticker, 'low'), - 'bid': this.safeFloat (ticker, 'buy'), - 'ask': this.safeFloat (ticker, 'sell'), - 'vwap': this.safeFloat (ticker, 'vwap'), - 'open': this.safeFloat (ticker, 'open'), - 'close': last, - 'last': last, - 'previousClose': undefined, - 'change': undefined, - 'percentage': undefined, - 'average': undefined, - 'baseVolume': this.safeFloat (ticker, 'vol'), - 'quoteVolume': undefined, - 'info': ticker, - }; - } - - parseTickerPlus (ticker, market) { - const timestamp = this.safeInteger (ticker, 'Timestamp'); - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; - } - return { - 'symbol': symbol, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'high': this.safeFloat (ticker, 'High'), - 'low': this.safeFloat (ticker, 'Low'), - 'bid': this.safeFloat (ticker, 'BidPrice'), - 'ask': this.safeFloat (ticker, 'AskPrice'), - 'vwap': undefined, - 'open': this.safeFloat (ticker, 'Open'), - 'last': this.safeFloat (ticker, 'Last'), - 'change': undefined, - 'percentage': undefined, - 'average': undefined, - 'baseVolume': this.safeFloat (ticker, 'Volume24H'), - 'quoteVolume': undefined, - 'info': ticker, - }; - } - - async fetchTicker (symbol, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['api'] + 'GetTicker'; - const request = this.createMarketRequest (market); - const response = await this[method] (this.extend (request, params)); - const ticker = this.safeValue (response, 'ticker'); - if (market['plus']) { - return this.parseTickerPlus (ticker, market); - } - return this.parseTicker (ticker, market); - } - - parseTrade (trade, market) { - const timestamp = this.safeTimestamp (trade, 'date'); - const price = this.safeFloat (trade, 'price'); - const amount = this.safeFloat (trade, 'amount'); - let cost = undefined; - if (amount !== undefined) { - if (price !== undefined) { - cost = amount * price; - } - } - const id = this.safeString (trade, 'tid'); - return { - 'id': id, - 'info': trade, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': market['symbol'], - 'type': undefined, - 'side': undefined, - 'price': price, - 'amount': amount, - 'cost': cost, - }; - } - - parseTradePlus (trade, market) { - const timestamp = this.parse8601 (this.safeString (trade, 'timestamp')); - const price = this.safeFloat (trade, 'price'); - const amount = this.safeFloat (trade, 'size'); - let cost = undefined; - if (amount !== undefined) { - if (price !== undefined) { - cost = amount * price; - } - } - const side = this.safeStringLower (trade, 'side'); - return { - 'id': undefined, - 'info': trade, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': market['symbol'], - 'type': undefined, - 'side': side, - 'price': price, - 'amount': amount, - 'cost': cost, - }; - } - - parseTradesPlus (trades, market = undefined) { - const result = []; - for (let i = 0; i < trades.length; i++) { - result.push (this.parseTradePlus (trades[i], market)); - } - return result; - } - - async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - let method = market['api'] + 'GetTrade'; - const request = this.createMarketRequest (market); - if (market['plus']) { - const now = this.milliseconds (); - request['start_time'] = now - 86400000; - request['end_time'] = now; - } else { - method += 's'; // trades vs trade - } - const response = await this[method] (this.extend (request, params)); - if (market['plus']) { - return this.parseTradesPlus (response['trades'], market); - } - return this.parseTrades (response, market, since, limit); - } - - async createOrder (symbol, type, side, amount, price = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = 'privatePost' + this.capitalize (side) + 'Order2'; - const request = {}; - const id = market['id'].toUpperCase (); - if (type === 'market') { - request['params'] = [ undefined, amount, id ]; - } else { - request['params'] = [ price, amount, id ]; - } - const response = await this[method] (this.extend (request, params)); - const orderId = this.safeString (response, 'id'); - return { - 'info': response, - 'id': orderId, - }; - } - - async cancelOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - const market = params['market']; // TODO fixme - const request = { - 'params': [ id, market ], - }; - return await this.privatePostCancelOrder (this.extend (request, params)); - } - - nonce () { - return this.microseconds (); - } - - sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = this.urls['api'][api] + '/' + path; - if (api === 'private') { - this.checkRequiredCredentials (); - let p = []; - if ('params' in params) { - p = params['params']; - } - const nonce = this.nonce (); - const request = { - 'method': path, - 'id': nonce, - 'params': p, - }; - p = p.join (','); - body = this.json (request); - const query = [ - 'tonce=' + nonce, - 'accesskey=' + this.apiKey, - 'requestmethod=' + method.toLowerCase (), - 'id=' + nonce, - 'method=' + path, - 'params=' + p, - ].join ('&'); - const signature = this.hmac (this.encode (query), this.encode (this.secret), 'sha1'); - const auth = this.encode (this.apiKey + ':' + signature); - headers = { - 'Authorization': 'Basic ' + this.stringToBase64 (auth), - 'Json-Rpc-Tonce': nonce, - }; - } else { - if (Object.keys (params).length) { - url += '?' + this.urlencode (params); - } - } - return { 'url': url, 'method': method, 'body': body, 'headers': headers }; - } -}; diff --git a/TaskServer/node_modules/ccxt/js/btcmarkets.js b/TaskServer/node_modules/ccxt/js/btcmarkets.js index 4211000c7..f52cc450e 100644 --- a/TaskServer/node_modules/ccxt/js/btcmarkets.js +++ b/TaskServer/node_modules/ccxt/js/btcmarkets.js @@ -4,6 +4,7 @@ const Exchange = require ('./base/Exchange'); const { ExchangeError, OrderNotFound, ArgumentsRequired, InvalidOrder, DDoSProtection } = require ('./base/errors'); +const { ROUND } = require ('./base/functions/number'); // --------------------------------------------------------------------------- @@ -415,7 +416,7 @@ module.exports = class btcmarkets extends Exchange { } parseTrade (trade, market = undefined) { - const timestamp = this.safeTimestamp (trade, 'timestamp'); + const timestamp = this.safeTimestamp (trade, 'date'); let symbol = undefined; if (market !== undefined) { symbol = market['symbol']; @@ -467,8 +468,8 @@ module.exports = class btcmarkets extends Exchange { }); request['currency'] = market['quote']; request['instrument'] = market['base']; - request['price'] = parseInt (price * multiplier); - request['volume'] = parseInt (amount * multiplier); + request['price'] = parseInt (this.decimalToPrecision (price * multiplier, ROUND, 0)); + request['volume'] = parseInt (this.decimalToPrecision (amount * multiplier, ROUND, 0)); request['orderSide'] = orderSide; request['ordertype'] = this.capitalize (type); request['clientRequestId'] = this.nonce ().toString (); @@ -564,6 +565,7 @@ module.exports = class btcmarkets extends Exchange { 'currency': feeCurrencyCode, 'cost': feeCost, }, + 'takerOrMaker': undefined, }; } @@ -611,9 +613,11 @@ module.exports = class btcmarkets extends Exchange { lastTradeTimestamp = trades[numTrades - 1]['timestamp']; } const id = this.safeString (order, 'id'); + const clientOrderId = this.safeString (order, 'clientRequestId'); return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, diff --git a/TaskServer/node_modules/ccxt/js/btctradeua.js b/TaskServer/node_modules/ccxt/js/btctradeua.js index c232d1bb0..8c056885c 100644 --- a/TaskServer/node_modules/ccxt/js/btctradeua.js +++ b/TaskServer/node_modules/ccxt/js/btctradeua.js @@ -15,7 +15,7 @@ module.exports = class btctradeua extends Exchange { 'countries': [ 'UA' ], // Ukraine, 'rateLimit': 3000, 'has': { - 'CORS': true, + 'CORS': false, 'createMarketOrder': false, 'fetchOpenOrders': true, }, @@ -320,6 +320,7 @@ module.exports = class btctradeua extends Exchange { } return { 'id': this.safeString (order, 'id'), + 'clientOrderId': undefined, 'timestamp': timestamp, // until they fix their timestamp 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -333,6 +334,9 @@ module.exports = class btctradeua extends Exchange { 'remaining': this.safeFloat (order, 'amnt_trade'), 'trades': undefined, 'info': order, + 'cost': undefined, + 'average': undefined, + 'fee': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/buda.js b/TaskServer/node_modules/ccxt/js/buda.js index fff477ca0..3416ad8c4 100644 --- a/TaskServer/node_modules/ccxt/js/buda.js +++ b/TaskServer/node_modules/ccxt/js/buda.js @@ -563,6 +563,7 @@ module.exports = class buda extends Exchange { }; return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -578,6 +579,7 @@ module.exports = class buda extends Exchange { 'trades': undefined, 'fee': fee, 'info': order, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/bw.js b/TaskServer/node_modules/ccxt/js/bw.js index fcc3b1629..dbd22c523 100644 --- a/TaskServer/node_modules/ccxt/js/bw.js +++ b/TaskServer/node_modules/ccxt/js/bw.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { BadSymbol, ExchangeError, AuthenticationError, ArgumentsRequired, ExchangeNotAvailable } = require ('./base/errors'); +const { RateLimitExceeded, BadSymbol, OrderNotFound, ExchangeError, AuthenticationError, ArgumentsRequired, ExchangeNotAvailable } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -77,18 +77,10 @@ module.exports = class bw extends Exchange { }, 'fees': { 'trading': { - 'tierBased': true, + 'tierBased': false, 'percentage': true, 'taker': 0.2 / 100, 'maker': 0.2 / 100, - 'tiers': { - 'taker': [ - [ 0, 0.2 / 100 ], - ], - 'maker': [ - [ 0, 0.2 / 100 ], - ], - }, }, 'funding': { }, @@ -97,7 +89,9 @@ module.exports = class bw extends Exchange { 'exact': { '999': AuthenticationError, '1000': ExchangeNotAvailable, // {"datas":null,"resMsg":{"message":"getKlines error:data not exitsts\uff0cplease wait ,dataType=4002_KLINE_1M","method":null,"code":"1000"}} + '2012': OrderNotFound, // {"datas":null,"resMsg":{"message":"entrust not exists or on dealing with system","method":null,"code":"2012"}} '5017': BadSymbol, // {"datas":null,"resMsg":{"message":"market not exist","method":null,"code":"5017"}} + '10001': RateLimitExceeded, // {"resMsg":{"code":"10001","message":"API frequency limit"}} }, }, 'api': { @@ -314,7 +308,7 @@ module.exports = class bw extends Exchange { }, 'withdraw': { 'min': undefined, - 'max': parseFloat (this.safeInteger (currency, 'onceDrawLimit')), + 'max': this.safeFloat (currency, 'onceDrawLimit'), }, }, }; @@ -343,8 +337,10 @@ module.exports = class bw extends Exchange { if (marketId in this.markets_by_id) { market = this.markets_by_id[marketId]; } - if ((symbol === undefined) && (market !== undefined)) { + if (market !== undefined) { symbol = market['symbol']; + } else { + symbol = marketId; } const timestamp = this.milliseconds (); const close = parseFloat (this.safeValue (ticker, 1)); @@ -614,7 +610,7 @@ module.exports = class bw extends Exchange { const result = { 'info': response }; for (let i = 0; i < balances.length; i++) { const balance = balances[i]; - const currencyId = this.safeInteger (balance, 'currencyTypeId'); + const currencyId = this.safeString (balance, 'currencyTypeId'); const code = this.safeCurrencyCode (currencyId); const account = this.account (); account['free'] = this.safeFloat (balance, 'amount'); @@ -670,6 +666,7 @@ module.exports = class bw extends Exchange { 'status': 'open', 'fee': undefined, 'trades': undefined, + 'clientOrderId': undefined, }; } @@ -739,6 +736,7 @@ module.exports = class bw extends Exchange { return { 'info': order, 'id': this.safeString (order, 'entrustId'), + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, diff --git a/TaskServer/node_modules/ccxt/js/bybit.js b/TaskServer/node_modules/ccxt/js/bybit.js new file mode 100644 index 000000000..a27c9eec5 --- /dev/null +++ b/TaskServer/node_modules/ccxt/js/bybit.js @@ -0,0 +1,1925 @@ +'use strict'; + +// --------------------------------------------------------------------------- + +const Exchange = require ('./base/Exchange'); +const { TICK_SIZE } = require ('./base/functions/number'); +const { AuthenticationError, ExchangeError, ArgumentsRequired, PermissionDenied, InvalidOrder, OrderNotFound, InsufficientFunds, BadRequest, RateLimitExceeded, InvalidNonce } = require ('./base/errors'); + +// --------------------------------------------------------------------------- + +module.exports = class bybit extends Exchange { + describe () { + return this.deepExtend (super.describe (), { + 'id': 'bybit', + 'name': 'Bybit', + 'countries': [ 'VG' ], // British Virgin Islands + 'version': 'v2', + 'userAgent': undefined, + 'rateLimit': 100, + 'has': { + 'CORS': true, + 'fetchMarkets': true, + 'fetchBalance': true, + 'fetchOHLCV': true, + 'editOrder': true, + 'fetchOrder': true, + 'fetchOrders': true, + 'fetchOpenOrders': true, + 'fetchClosedOrders': true, + 'fetchMyTrades': true, + 'fetchTicker': true, + 'fetchTickers': true, + 'fetchOrderTrades': true, + 'createOrder': true, + 'cancelOrder': true, + 'cancelAllOrders': true, + 'fetchTime': true, + 'fetchWithdrawals': true, + 'fetchDeposits': false, + 'fetchTransactions': false, + 'fetchLedger': true, + }, + 'timeframes': { + '1m': '1', + '3m': '3', + '5m': '5', + '15m': '15', + '30m': '30', + '1h': '60', + '2h': '120', + '3h': '180', + '6h': '360', + '12h': '720', + '1d': 'D', + '1w': 'W', + '1M': 'M', + '1y': 'Y', + }, + 'urls': { + 'test': 'https://api-testnet.bybit.com', + 'logo': 'https://user-images.githubusercontent.com/51840849/76547799-daff5b80-649e-11ea-87fb-3be9bac08954.jpg', + 'api': 'https://api.bybit.com', + 'www': 'https://www.bybit.com/', + 'doc': [ + 'https://bybit-exchange.github.io/docs/inverse/', + 'https://github.com/bybit-exchange', + ], + 'fees': 'https://help.bybit.com/hc/en-us/articles/360039261154', + 'referral': 'https://www.bybit.com/app/register?ref=X7Prm', + }, + 'api': { + 'public': { + 'get': [ + 'orderBook/L2', + 'kline/list', + 'tickers', + 'trading-records', + 'symbols', + 'time', + 'announcement', + ], + }, + 'private': { + 'get': [ + 'order', + 'stop-order', + 'position/list', + 'wallet/balance', + 'execution/list', + ], + 'post': [ + 'order/create', + 'order/cancel', + 'order/cancelAll', + 'stop-order/cancelAll', + ], + }, + 'openapi': { + 'get': [ + 'order/list', + 'stop-order/list', + 'wallet/risk-limit/list', + 'wallet/risk-limit', + 'funding/prev-funding-rate', + 'funding/prev-funding', + 'funding/predicted-funding', + 'api-key', + 'wallet/fund/records', + 'wallet/withdraw/list', + ], + 'post': [ + 'order/replace', + 'stop-order/create', + 'stop-order/cancel', + 'stop-order/replace', + 'position/trading-stop', + ], + }, + 'position': { + 'post': [ + 'change-position-margin', + ], + }, + 'user': { + 'get': [ + 'leverage', + ], + 'post': [ + 'leverage/save', + ], + }, + }, + 'httpExceptions': { + '403': RateLimitExceeded, // Forbidden -- You request too many times + }, + 'exceptions': { + 'exact': { + '10001': BadRequest, // parameter error + '10002': InvalidNonce, // request expired, check your timestamp and recv_window + '10003': AuthenticationError, // Invalid apikey + '10004': AuthenticationError, // invalid sign + '10005': PermissionDenied, // permission denied for current apikey + '10006': RateLimitExceeded, // too many requests + '10007': AuthenticationError, // api_key not found in your request parameters + '10010': PermissionDenied, // request ip mismatch + '10017': BadRequest, // request path not found or request method is invalid + '20001': OrderNotFound, // Order not exists + '20003': InvalidOrder, // missing parameter side + '20004': InvalidOrder, // invalid parameter side + '20005': InvalidOrder, // missing parameter symbol + '20006': InvalidOrder, // invalid parameter symbol + '20007': InvalidOrder, // missing parameter order_type + '20008': InvalidOrder, // invalid parameter order_type + '20009': InvalidOrder, // missing parameter qty + '20010': InvalidOrder, // qty must be greater than 0 + '20011': InvalidOrder, // qty must be an integer + '20012': InvalidOrder, // qty must be greater than zero and less than 1 million + '20013': InvalidOrder, // missing parameter price + '20014': InvalidOrder, // price must be greater than 0 + '20015': InvalidOrder, // missing parameter time_in_force + '20016': InvalidOrder, // invalid value for parameter time_in_force + '20017': InvalidOrder, // missing parameter order_id + '20018': InvalidOrder, // invalid date format + '20019': InvalidOrder, // missing parameter stop_px + '20020': InvalidOrder, // missing parameter base_price + '20021': InvalidOrder, // missing parameter stop_order_id + '20022': BadRequest, // missing parameter leverage + '20023': BadRequest, // leverage must be a number + '20031': BadRequest, // leverage must be greater than zero + '20070': BadRequest, // missing parameter margin + '20071': BadRequest, // margin must be greater than zero + '20084': BadRequest, // order_id or order_link_id is required + '30001': BadRequest, // order_link_id is repeated + '30003': InvalidOrder, // qty must be more than the minimum allowed + '30004': InvalidOrder, // qty must be less than the maximum allowed + '30005': InvalidOrder, // price exceeds maximum allowed + '30007': InvalidOrder, // price exceeds minimum allowed + '30008': InvalidOrder, // invalid order_type + '30009': ExchangeError, // no position found + '30010': InsufficientFunds, // insufficient wallet balance + '30011': PermissionDenied, // operation not allowed as position is undergoing liquidation + '30012': PermissionDenied, // operation not allowed as position is undergoing ADL + '30013': PermissionDenied, // position is in liq or adl status + '30014': InvalidOrder, // invalid closing order, qty should not greater than size + '30015': InvalidOrder, // invalid closing order, side should be opposite + '30016': ExchangeError, // TS and SL must be cancelled first while closing position + '30017': InvalidOrder, // estimated fill price cannot be lower than current Buy liq_price + '30018': InvalidOrder, // estimated fill price cannot be higher than current Sell liq_price + '30019': InvalidOrder, // cannot attach TP/SL params for non-zero position when placing non-opening position order + '30020': InvalidOrder, // position already has TP/SL params + '30021': InvalidOrder, // cannot afford estimated position_margin + '30022': InvalidOrder, // estimated buy liq_price cannot be higher than current mark_price + '30023': InvalidOrder, // estimated sell liq_price cannot be lower than current mark_price + '30024': InvalidOrder, // cannot set TP/SL/TS for zero-position + '30025': InvalidOrder, // trigger price should bigger than 10% of last price + '30026': InvalidOrder, // price too high + '30027': InvalidOrder, // price set for Take profit should be higher than Last Traded Price + '30028': InvalidOrder, // price set for Stop loss should be between Liquidation price and Last Traded Price + '30029': InvalidOrder, // price set for Stop loss should be between Last Traded Price and Liquidation price + '30030': InvalidOrder, // price set for Take profit should be lower than Last Traded Price + '30031': InsufficientFunds, // insufficient available balance for order cost + '30032': InvalidOrder, // order has been filled or cancelled + '30033': RateLimitExceeded, // The number of stop orders exceeds maximum limit allowed + '30034': OrderNotFound, // no order found + '30035': RateLimitExceeded, // too fast to cancel + '30036': ExchangeError, // the expected position value after order execution exceeds the current risk limit + '30037': InvalidOrder, // order already cancelled + '30041': ExchangeError, // no position found + '30042': InsufficientFunds, // insufficient wallet balance + '30043': PermissionDenied, // operation not allowed as position is undergoing liquidation + '30044': PermissionDenied, // operation not allowed as position is undergoing AD + '30045': PermissionDenied, // operation not allowed as position is not normal status + '30049': InsufficientFunds, // insufficient available balance + '30050': ExchangeError, // any adjustments made will trigger immediate liquidation + '30051': ExchangeError, // due to risk limit, cannot adjust leverage + '30052': ExchangeError, // leverage can not less than 1 + '30054': ExchangeError, // position margin is invalid + '30057': ExchangeError, // requested quantity of contracts exceeds risk limit + '30063': ExchangeError, // reduce-only rule not satisfied + '30067': InsufficientFunds, // insufficient available balance + '30068': ExchangeError, // exit value must be positive + '34026': ExchangeError, // the limit is no change + }, + 'broad': { + 'unknown orderInfo': OrderNotFound, // {"ret_code":-1,"ret_msg":"unknown orderInfo","ext_code":"","ext_info":"","result":null,"time_now":"1584030414.005545","rate_limit_status":99,"rate_limit_reset_ms":1584030414003,"rate_limit":100} + }, + }, + 'precisionMode': TICK_SIZE, + 'options': { + 'code': 'BTC', + 'fetchBalance': { + 'code': 'BTC', + }, + 'cancelAllOrders': { + 'method': 'privatePostOrderCancelAll', // privatePostStopOrderCancelAll + }, + 'recvWindow': 5 * 1000, // 5 sec default + 'timeDifference': 0, // the difference between system clock and Binance clock + 'adjustForTimeDifference': false, // controls the adjustment logic upon instantiation + }, + 'fees': { + 'trading': { + 'tierBased': false, + 'percentage': true, + 'taker': 0.00075, + 'maker': -0.00025, + }, + 'funding': { + 'tierBased': false, + 'percentage': false, + 'withdraw': {}, + 'deposit': {}, + }, + }, + }); + } + + nonce () { + return this.milliseconds () - this.options['timeDifference']; + } + + async loadTimeDifference () { + const serverTime = await this.fetchTime (); + const after = this.milliseconds (); + this.options['timeDifference'] = after - serverTime; + return this.options['timeDifference']; + } + + async fetchTime (params = {}) { + const response = await this.publicGetTime (params); + // + // { + // ret_code: 0, + // ret_msg: 'OK', + // ext_code: '', + // ext_info: '', + // result: {}, + // time_now: '1583933682.448826' + // } + // + return this.safeTimestamp (response, 'time_now'); + } + + async fetchMarkets (params = {}) { + if (this.options['adjustForTimeDifference']) { + await this.loadTimeDifference (); + } + const response = await this.publicGetSymbols (params); + // + // { + // ret_code: 0, + // ret_msg: 'OK', + // ext_code: '', + // ext_info: '', + // result: [ + // { + // name: 'BTCUSD', + // base_currency: 'BTC', + // quote_currency: 'USD', + // price_scale: 2, + // taker_fee: '0.00075', + // maker_fee: '-0.00025', + // leverage_filter: { min_leverage: 1, max_leverage: 100, leverage_step: '0.01' }, + // price_filter: { min_price: '0.5', max_price: '999999.5', tick_size: '0.5' }, + // lot_size_filter: { max_trading_qty: 1000000, min_trading_qty: 1, qty_step: 1 } + // }, + // ], + // time_now: '1583930495.454196' + // } + // + const markets = this.safeValue (response, 'result', []); + const result = []; + for (let i = 0; i < markets.length; i++) { + const market = markets[i]; + const id = this.safeString (market, 'name'); + const baseId = this.safeString (market, 'base_currency'); + const quoteId = this.safeString (market, 'quote_currency'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + const symbol = base + '/' + quote; + const lotSizeFilter = this.safeValue (market, 'lot_size_filter', {}); + const priceFilter = this.safeValue (market, 'price_filter', {}); + const precision = { + 'amount': this.safeFloat (lotSizeFilter, 'qty_step'), + 'price': this.safeFloat (priceFilter, 'tick_size'), + }; + result.push ({ + 'id': id, + 'symbol': symbol, + 'base': base, + 'quote': quote, + 'active': undefined, + 'precision': precision, + 'taker': this.safeFloat (market, 'taker_fee'), + 'maker': this.safeFloat (market, 'maker_fee'), + 'limits': { + 'amount': { + 'min': this.safeFloat (lotSizeFilter, 'min_trading_qty'), + 'max': this.safeFloat (lotSizeFilter, 'max_trading_qty'), + }, + 'price': { + 'min': this.safeFloat (priceFilter, 'min_price'), + 'max': this.safeFloat (priceFilter, 'max_price'), + }, + 'cost': { + 'min': undefined, + 'max': undefined, + }, + }, + 'type': 'future', + 'spot': false, + 'future': true, + 'option': false, + 'info': market, + }); + } + return result; + } + + async fetchBalance (params = {}) { + await this.loadMarkets (); + const defaultCode = this.safeValue (this.options, 'code', 'BTC'); + const options = this.safeValue (this.options, 'fetchBalance', {}); + const code = this.safeValue (options, 'code', defaultCode); + const currency = this.currency (code); + const request = { + 'coin': currency['id'], + }; + const response = await this.privateGetWalletBalance (this.extend (request, params)); + // + // { + // ret_code: 0, + // ret_msg: 'OK', + // ext_code: '', + // ext_info: '', + // result: { + // BTC: { + // equity: 0, + // available_balance: 0, + // used_margin: 0, + // order_margin: 0, + // position_margin: 0, + // occ_closing_fee: 0, + // occ_funding_fee: 0, + // wallet_balance: 0, + // realised_pnl: 0, + // unrealised_pnl: 0, + // cum_realised_pnl: 0, + // given_cash: 0, + // service_cash: 0 + // } + // }, + // time_now: '1583937810.370020', + // rate_limit_status: 119, + // rate_limit_reset_ms: 1583937810367, + // rate_limit: 120 + // } + // + const result = { + 'info': response, + }; + const balances = this.safeValue (response, 'result', {}); + const currencyIds = Object.keys (balances); + for (let i = 0; i < currencyIds.length; i++) { + const currencyId = currencyIds[i]; + const balance = balances[currencyId]; + const code = this.safeCurrencyCode (currencyId); + const account = this.account (); + account['free'] = this.safeFloat (balance, 'available_balance'); + account['used'] = this.safeFloat (balance, 'used_margin'); + account['total'] = this.safeFloat (balance, 'equity'); + result[code] = account; + } + return this.parseBalance (result); + } + + parseTicker (ticker, market = undefined) { + // + // fetchTicker + // + // { + // symbol: 'BTCUSD', + // bid_price: '7680', + // ask_price: '7680.5', + // last_price: '7680.00', + // last_tick_direction: 'MinusTick', + // prev_price_24h: '7870.50', + // price_24h_pcnt: '-0.024204', + // high_price_24h: '8035.00', + // low_price_24h: '7671.00', + // prev_price_1h: '7780.00', + // price_1h_pcnt: '-0.012853', + // mark_price: '7683.27', + // index_price: '7682.74', + // open_interest: 188829147, + // open_value: '23670.06', + // total_turnover: '25744224.90', + // turnover_24h: '102997.83', + // total_volume: 225448878806, + // volume_24h: 809919408, + // funding_rate: '0.0001', + // predicted_funding_rate: '0.0001', + // next_funding_time: '2020-03-12T00:00:00Z', + // countdown_hour: 7 + // } + // + const timestamp = undefined; + const marketId = this.safeString (ticker, 'symbol'); + let symbol = marketId; + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const last = this.safeFloat (ticker, 'last_price'); + const open = this.safeFloat (ticker, 'prev_price_24h'); + let percentage = this.safeFloat (ticker, 'price_24h_pcnt'); + if (percentage !== undefined) { + percentage *= 100; + } + let change = undefined; + let average = undefined; + if ((last !== undefined) && (open !== undefined)) { + change = last - open; + average = this.sum (open, last) / 2; + } + const baseVolume = this.safeFloat (ticker, 'turnover_24h'); + const quoteVolume = this.safeFloat (ticker, 'volume_24h'); + let vwap = undefined; + if (quoteVolume !== undefined && baseVolume !== undefined) { + vwap = quoteVolume / baseVolume; + } + return { + 'symbol': symbol, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'high': this.safeFloat (ticker, 'high_price_24h'), + 'low': this.safeFloat (ticker, 'low_price_24h'), + 'bid': this.safeFloat (ticker, 'bid_price'), + 'bidVolume': undefined, + 'ask': this.safeFloat (ticker, 'ask_price'), + 'askVolume': undefined, + 'vwap': vwap, + 'open': open, + 'close': last, + 'last': last, + 'previousClose': undefined, + 'change': change, + 'percentage': percentage, + 'average': average, + 'baseVolume': baseVolume, + 'quoteVolume': quoteVolume, + 'info': ticker, + }; + } + + async fetchTicker (symbol, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.publicGetTickers (this.extend (request, params)); + // + // { + // ret_code: 0, + // ret_msg: 'OK', + // ext_code: '', + // ext_info: '', + // result: [ + // { + // symbol: 'BTCUSD', + // bid_price: '7680', + // ask_price: '7680.5', + // last_price: '7680.00', + // last_tick_direction: 'MinusTick', + // prev_price_24h: '7870.50', + // price_24h_pcnt: '-0.024204', + // high_price_24h: '8035.00', + // low_price_24h: '7671.00', + // prev_price_1h: '7780.00', + // price_1h_pcnt: '-0.012853', + // mark_price: '7683.27', + // index_price: '7682.74', + // open_interest: 188829147, + // open_value: '23670.06', + // total_turnover: '25744224.90', + // turnover_24h: '102997.83', + // total_volume: 225448878806, + // volume_24h: 809919408, + // funding_rate: '0.0001', + // predicted_funding_rate: '0.0001', + // next_funding_time: '2020-03-12T00:00:00Z', + // countdown_hour: 7 + // } + // ], + // time_now: '1583948195.818255' + // } + // + const result = this.safeValue (response, 'result', []); + const first = this.safeValue (result, 0); + const timestamp = this.safeTimestamp (response, 'time_now'); + const ticker = this.parseTicker (first, market); + ticker['timestamp'] = timestamp; + ticker['datetime'] = this.iso8601 (timestamp); + return ticker; + } + + async fetchTickers (symbols = undefined, params = {}) { + await this.loadMarkets (); + const response = await this.publicGetTickers (params); + // + // { + // ret_code: 0, + // ret_msg: 'OK', + // ext_code: '', + // ext_info: '', + // result: [ + // { + // symbol: 'BTCUSD', + // bid_price: '7680', + // ask_price: '7680.5', + // last_price: '7680.00', + // last_tick_direction: 'MinusTick', + // prev_price_24h: '7870.50', + // price_24h_pcnt: '-0.024204', + // high_price_24h: '8035.00', + // low_price_24h: '7671.00', + // prev_price_1h: '7780.00', + // price_1h_pcnt: '-0.012853', + // mark_price: '7683.27', + // index_price: '7682.74', + // open_interest: 188829147, + // open_value: '23670.06', + // total_turnover: '25744224.90', + // turnover_24h: '102997.83', + // total_volume: 225448878806, + // volume_24h: 809919408, + // funding_rate: '0.0001', + // predicted_funding_rate: '0.0001', + // next_funding_time: '2020-03-12T00:00:00Z', + // countdown_hour: 7 + // } + // ], + // time_now: '1583948195.818255' + // } + // + const result = this.safeValue (response, 'result', []); + const tickers = {}; + for (let i = 0; i < result.length; i++) { + const ticker = this.parseTicker (result[i]); + const symbol = ticker['symbol']; + tickers[symbol] = ticker; + } + return this.filterByArray (tickers, 'symbol', symbols); + } + + parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) { + // + // { + // symbol: 'BTCUSD', + // interval: '1', + // open_time: 1583952540, + // open: '7760.5', + // high: '7764', + // low: '7757', + // close: '7763.5', + // volume: '1259766', + // turnover: '162.32773718999994' + // }, + // + return [ + this.safeTimestamp (ohlcv, 'open_time'), + this.safeFloat (ohlcv, 'open'), + this.safeFloat (ohlcv, 'high'), + this.safeFloat (ohlcv, 'low'), + this.safeFloat (ohlcv, 'close'), + this.safeFloat (ohlcv, 'turnover'), + ]; + } + + async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + 'interval': this.timeframes[timeframe], + }; + const duration = this.parseTimeframe (timeframe); + const now = this.seconds (); + if (since === undefined) { + if (limit === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument or a limit argument'); + } else { + request['from'] = now - limit * duration; + } + } else { + request['from'] = parseInt (since / 1000); + } + if (limit !== undefined) { + request['limit'] = limit; // max 200, default 200 + } + const response = await this.publicGetKlineList (this.extend (request, params)); + // { + // ret_code: 0, + // ret_msg: 'OK', + // ext_code: '', + // ext_info: '', + // result: [ + // { + // symbol: 'BTCUSD', + // interval: '1', + // open_time: 1583952540, + // open: '7760.5', + // high: '7764', + // low: '7757', + // close: '7763.5', + // volume: '1259766', + // turnover: '162.32773718999994' + // }, + // ], + // time_now: '1583953082.397330' + // } + const result = this.safeValue (response, 'result', {}); + return this.parseOHLCVs (result, market, timeframe, since, limit); + } + + parseTrade (trade, market = undefined) { + // + // fetchTrades (public) + // + // { + // id: 43785688, + // symbol: 'BTCUSD', + // price: 7786, + // qty: 67, + // side: 'Sell', + // time: '2020-03-11T19:18:30.123Z' + // } + // + // fetchMyTrades, fetchOrderTrades (private) + // + // { + // "closed_size": 0, + // "cross_seq": 277136382, + // "exec_fee": "0.0000001", + // "exec_id": "256e5ef8-abfe-5772-971b-f944e15e0d68", + // "exec_price": "8178.5", + // "exec_qty": 1, + // "exec_time": "1571676941.70682", + // "exec_type": "Trade", //Exec Type Enum + // "exec_value": "0.00012227", + // "fee_rate": "0.00075", + // "last_liquidity_ind": "RemovedLiquidity", //Liquidity Enum + // "leaves_qty": 0, + // "nth_fill": 2, + // "order_id": "7ad50cb1-9ad0-4f74-804b-d82a516e1029", + // "order_link_id": "", + // "order_price": "8178", + // "order_qty": 1, + // "order_type": "Market", //Order Type Enum + // "side": "Buy", //Side Enum + // "symbol": "BTCUSD", //Symbol Enum + // "user_id": 1 + // } + // + const id = this.safeString2 (trade, 'id', 'exec_id'); + let symbol = undefined; + let base = undefined; + const marketId = this.safeString (trade, 'symbol'); + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + base = market['base']; + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + base = market['base']; + } + let timestamp = this.parse8601 (this.safeString (trade, 'time')); + if (timestamp === undefined) { + timestamp = this.safeTimestamp (trade, 'exec_time'); + } + const side = this.safeStringLower (trade, 'side'); + const price = this.safeFloat2 (trade, 'price', 'exec_price'); + const amount = this.safeFloat2 (trade, 'qty', 'exec_qty'); + let cost = this.safeFloat (trade, 'exec_value'); + if (cost === undefined) { + if (amount !== undefined) { + if (price !== undefined) { + cost = amount * price; + } + } + } + const lastLiquidityInd = this.safeString (trade, 'last_liquidity_ind'); + const takerOrMaker = (lastLiquidityInd === 'AddedLiquidity') ? 'maker' : 'taker'; + const feeCost = this.safeFloat (trade, 'exec_fee'); + let fee = undefined; + if (feeCost !== undefined) { + fee = { + 'cost': feeCost, + 'currency': base, + 'rate': this.safeFloat (trade, 'fee_rate'), + }; + } + return { + 'id': id, + 'info': trade, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'symbol': symbol, + 'order': this.safeString (trade, 'order_id'), + 'type': this.safeStringLower (trade, 'order_type'), + 'side': side, + 'takerOrMaker': takerOrMaker, + 'price': price, + 'amount': amount, + 'cost': cost, + 'fee': fee, + }; + } + + async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + // 'from': 123, // from id + }; + if (limit !== undefined) { + request['count'] = limit; // default 500, max 1000 + } + const response = await this.publicGetTradingRecords (this.extend (request, params)); + // + // { + // ret_code: 0, + // ret_msg: 'OK', + // ext_code: '', + // ext_info: '', + // result: [ + // { + // id: 43785688, + // symbol: 'BTCUSD', + // price: 7786, + // qty: 67, + // side: 'Sell', + // time: '2020-03-11T19:18:30.123Z' + // }, + // ], + // time_now: '1583954313.393362' + // } + // + const result = this.safeValue (response, 'result', {}); + return this.parseTrades (result, market, since, limit); + } + + parseOrderBook (orderbook, timestamp = undefined, bidsKey = 'Buy', asksKey = 'Sell', priceKey = 'price', amountKey = 'size') { + const bids = []; + const asks = []; + for (let i = 0; i < orderbook.length; i++) { + const bidask = orderbook[i]; + const side = this.safeString (bidask, 'side'); + if (side === 'Buy') { + bids.push (this.parseBidAsk (bidask, priceKey, amountKey)); + } else if (side === 'Sell') { + asks.push (this.parseBidAsk (bidask, priceKey, amountKey)); + } else { + throw new ExchangeError (this.id + ' parseOrderBook encountered an unrecognized bidask format: ' + this.json (bidask)); + } + } + return { + 'bids': this.sortBy (bids, 0, true), + 'asks': this.sortBy (asks, 0), + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'nonce': undefined, + }; + } + + async fetchOrderBook (symbol, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.publicGetOrderBookL2 (this.extend (request, params)); + // + // { + // ret_code: 0, + // ret_msg: 'OK', + // ext_code: '', + // ext_info: '', + // result: [ + // { symbol: 'BTCUSD', price: '7767.5', size: 677956, side: 'Buy' }, + // { symbol: 'BTCUSD', price: '7767', size: 580690, side: 'Buy' }, + // { symbol: 'BTCUSD', price: '7766.5', size: 475252, side: 'Buy' }, + // { symbol: 'BTCUSD', price: '7768', size: 330847, side: 'Sell' }, + // { symbol: 'BTCUSD', price: '7768.5', size: 97159, side: 'Sell' }, + // { symbol: 'BTCUSD', price: '7769', size: 6508, side: 'Sell' }, + // ], + // time_now: '1583954829.874823' + // } + // + const result = this.safeValue (response, 'result', []); + const timestamp = this.safeTimestamp (response, 'time_now'); + return this.parseOrderBook (result, timestamp, 'Buy', 'Sell', 'price', 'size'); + } + + parseOrderStatus (status) { + const statuses = { + // basic orders + 'Created': 'open', + 'Rejected': 'rejected', // order is triggered but failed upon being placed + 'New': 'open', + 'PartiallyFilled': 'open', + 'Filled': 'filled', + 'Cancelled': 'canceled', + 'PendingCancel': 'canceling', // the engine has received the cancellation but there is no guarantee that it will be successful + // conditional orders + 'Active': 'closed', // order is triggered and placed successfully + 'Untriggered': 'open', // order waits to be triggered + 'Triggered': 'closed', // order is triggered + // 'Cancelled': 'canceled', // order is cancelled + // 'Rejected': 'rejected', // order is triggered but fail to be placed + 'Deactivated': 'canceled', // conditional order was cancelled before triggering + }; + return this.safeString (statuses, status, status); + } + + parseOrder (order, market = undefined) { + // + // createOrder + // + // { + // "user_id": 1, + // "order_id": "335fd977-e5a5-4781-b6d0-c772d5bfb95b", + // "symbol": "BTCUSD", + // "side": "Buy", + // "order_type": "Limit", + // "price": 8800, + // "qty": 1, + // "time_in_force": "GoodTillCancel", + // "order_status": "Created", + // "last_exec_time": 0, + // "last_exec_price": 0, + // "leaves_qty": 1, + // "cum_exec_qty": 0, + // "cum_exec_value": 0, + // "cum_exec_fee": 0, + // "reject_reason": "", + // "order_link_id": "", + // "created_at": "2019-11-30T11:03:43.452Z", + // "updated_at": "2019-11-30T11:03:43.455Z" + // } + // + const timestamp = this.parse8601 (this.safeString (order, 'created_at')); + const id = this.safeString (order, 'order_id'); + const price = this.safeFloat (order, 'price'); + const average = this.safeFloat (order, 'average_price'); + const amount = this.safeFloat (order, 'qty'); + let filled = this.safeFloat (order, 'cum_exec_qty'); + let remaining = this.safeFloat (order, 'leaves_qty'); + let lastTradeTimestamp = this.safeTimestamp (order, 'last_exec_time'); + if (lastTradeTimestamp === 0) { + lastTradeTimestamp = undefined; + } + let cost = this.safeFloat (order, 'cum_exec_value'); + if ((filled === undefined) && (amount !== undefined) && (remaining !== undefined)) { + filled = amount - remaining; + } + if (filled !== undefined) { + if ((remaining === undefined) && (amount !== undefined)) { + remaining = amount - filled; + } + if (cost === undefined) { + if (price !== undefined) { + cost = price * filled; + } + } + } + const status = this.parseOrderStatus (this.safeString (order, 'order_status')); + const marketId = this.safeString (order, 'symbol'); + let symbol = undefined; + let base = undefined; + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + base = market['base']; + } + if (market !== undefined) { + if (symbol === undefined) { + symbol = market['symbol']; + } + if (base === undefined) { + base = market['base']; + } + } + const side = this.safeStringLower (order, 'side'); + let feeCost = this.safeFloat (order, 'cum_exec_fee'); + let fee = undefined; + if (feeCost !== undefined) { + feeCost = Math.abs (feeCost); + fee = { + 'cost': feeCost, + 'currency': base, + }; + } + const type = this.safeStringLower (order, 'order_type'); + let clientOrderId = this.safeString (order, 'order_link_id'); + if ((clientOrderId !== undefined) && (clientOrderId.length < 1)) { + clientOrderId = undefined; + } + return { + 'info': order, + 'id': id, + 'clientOrderId': clientOrderId, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': lastTradeTimestamp, + 'symbol': symbol, + 'type': type, + 'side': side, + 'price': price, + 'amount': amount, + 'cost': cost, + 'average': average, + 'filled': filled, + 'remaining': remaining, + 'status': status, + 'fee': fee, + 'trades': undefined, + }; + } + + async fetchOrder (id, symbol = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + // 'order_link_id': 'string', // one of order_id, stop_order_id or order_link_id is required + // regular orders --------------------------------------------- + // 'order_id': id, // one of order_id or order_link_id is required for regular orders + // conditional orders --------------------------------------------- + // 'stop_order_id': id, // one of stop_order_id or order_link_id is required for conditional orders + }; + let method = 'privateGetOrder'; + const stopOrderId = this.safeString (params, 'stop_order_id'); + if (stopOrderId === undefined) { + const orderLinkId = this.safeString (params, 'order_link_id'); + if (orderLinkId === undefined) { + request['order_id'] = id; + } + } else { + method = 'privateGetStopOrder'; + } + const response = await this[method] (this.extend (request, params)); + // + // { + // "ret_code": 0, + // "ret_msg": "OK", + // "ext_code": "", + // "ext_info": "", + // "result": { + // "user_id": 1, + // "symbol": "BTCUSD", + // "side": "Sell", + // "order_type": "Limit", + // "price": "8083", + // "qty": 10, + // "time_in_force": "GoodTillCancel", + // "order_status": "New", + // "ext_fields": { "o_req_num": -308787, "xreq_type": "x_create", "xreq_offset": 4154640 }, + // "leaves_qty": 10, + // "leaves_value": "0.00123716", + // "cum_exec_qty": 0, + // "reject_reason": "", + // "order_link_id": "", + // "created_at": "2019-10-21T07:28:19.396246Z", + // "updated_at": "2019-10-21T07:28:19.396246Z", + // "order_id": "efa44157-c355-4a98-b6d6-1d846a936b93" + // }, + // "time_now": "1571651135.291930", + // "rate_limit_status": 99, // The remaining number of accesses in one minute + // "rate_limit_reset_ms": 1580885703683, + // "rate_limit": 100 + // } + // + // conditional orders + // + // { + // "ret_code": 0, + // "ret_msg": "OK", + // "ext_code": "", + // "ext_info": "", + // "result": { + // "user_id": 1, + // "symbol": "BTCUSD", + // "side": "Buy", + // "order_type": "Limit", + // "price": "8000", + // "qty": 1, + // "time_in_force": "GoodTillCancel", + // "order_status": "Untriggered", + // "ext_fields": {}, + // "leaves_qty": 1, + // "leaves_value": "0.00013333", + // "cum_exec_qty": 0, + // "cum_exec_value": null, + // "cum_exec_fee": null, + // "reject_reason": "", + // "order_link_id": "", + // "created_at": "2019-12-27T19:56:24.052194Z", + // "updated_at": "2019-12-27T19:56:24.052194Z", + // "order_id": "378a1bbc-a93a-4e75-87f4-502ea754ba36" + // }, + // "time_now": "1577476584.386958", + // "rate_limit_status": 99, + // "rate_limit_reset_ms": 1580885703683, + // "rate_limit": 100 + // } + // + const result = this.safeValue (response, 'result'); + return this.parseOrder (result, market); + } + + async createOrder (symbol, type, side, amount, price = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + // orders --------------------------------------------------------- + 'side': this.capitalize (side), + 'symbol': market['id'], + 'order_type': this.capitalize (type), + 'qty': this.amountToPrecision (symbol, amount), // order quantity in USD, integer only + // 'price': this.priceToPrecision (symbol, price), // required for limit orders + 'time_in_force': 'GoodTillCancel', // ImmediateOrCancel, FillOrKill, PostOnly + // 'take_profit': 123.45, // take profit price, only take effect upon opening the position + // 'stop_loss': 123.45, // stop loss price, only take effect upon opening the position + // 'reduce_only': false, // reduce only + // when creating a closing order, bybit recommends a True value for + // close_on_trigger to avoid failing due to insufficient available margin + // 'close_on_trigger': false, + // 'order_link_id': 'string', // unique client order id, max 36 characters + // conditional orders --------------------------------------------- + // base_price is used to compare with the value of stop_px, to decide + // whether your conditional order will be triggered by crossing trigger + // price from upper side or lower side, mainly used to identify the + // expected direction of the current conditional order + // 'base_price': 123.45, // required for conditional orders + // 'stop_px': 123.45, // trigger price, required for conditional orders + // 'trigger_by': 'LastPrice', // IndexPrice, MarkPrice + }; + let priceIsRequired = false; + if (type === 'limit') { + priceIsRequired = true; + } + if (priceIsRequired) { + if (price !== undefined) { + request['price'] = this.priceToPrecision (symbol, price); + } else { + throw new ArgumentsRequired (this.id + ' createOrder requires a price argument for a ' + type + ' order'); + } + } + const stopPx = this.safeValue (params, 'stop_px'); + const basePrice = this.safeValue (params, 'base_price'); + let method = 'privatePostOrderCreate'; + if (stopPx !== undefined) { + if (basePrice === undefined) { + throw new ArgumentsRequired (this.id + ' createOrder requires both the stop_px and base_price params for a conditional ' + type + ' order'); + } else { + method = 'openapiPostStopOrderCreate'; + request['stop_px'] = this.priceToPrecision (symbol, stopPx); + request['base_price'] = this.priceToPrecision (symbol, basePrice); + params = this.omit (params, [ 'stop_px', 'base_price' ]); + } + } else if (basePrice !== undefined) { + throw new ArgumentsRequired (this.id + ' createOrder requires both the stop_px and base_price params for a conditional ' + type + ' order'); + } + const response = await this[method] (this.extend (request, params)); + // + // { + // "ret_code": 0, + // "ret_msg": "OK", + // "ext_code": "", + // "ext_info": "", + // "result": { + // "user_id": 1, + // "order_id": "335fd977-e5a5-4781-b6d0-c772d5bfb95b", + // "symbol": "BTCUSD", + // "side": "Buy", + // "order_type": "Limit", + // "price": 8800, + // "qty": 1, + // "time_in_force": "GoodTillCancel", + // "order_status": "Created", + // "last_exec_time": 0, + // "last_exec_price": 0, + // "leaves_qty": 1, + // "cum_exec_qty": 0, + // "cum_exec_value": 0, + // "cum_exec_fee": 0, + // "reject_reason": "", + // "order_link_id": "", + // "created_at": "2019-11-30T11:03:43.452Z", + // "updated_at": "2019-11-30T11:03:43.455Z" + // }, + // "time_now": "1575111823.458705", + // "rate_limit_status": 98, + // "rate_limit_reset_ms": 1580885703683, + // "rate_limit": 100 + // } + // + // conditional orders + // + // { + // "ret_code": 0, + // "ret_msg": "ok", + // "ext_code": "", + // "result": { + // "user_id": 1, + // "symbol": "BTCUSD", + // "side": "Buy", + // "order_type": "Limit", + // "price": 8000, + // "qty": 1, + // "time_in_force": "GoodTillCancel", + // "stop_order_type": "Stop", + // "trigger_by": "LastPrice", + // "base_price": 7000, + // "order_status": "Untriggered", + // "ext_fields": { + // "stop_order_type": "Stop", + // "trigger_by": "LastPrice", + // "base_price": 7000, + // "expected_direction": "Rising", + // "trigger_price": 7500, + // "op_from": "api", + // "remark": "127.0.01", + // "o_req_num": 0 + // }, + // "leaves_qty": 1, + // "leaves_value": 0.00013333, + // "reject_reason": null, + // "cross_seq": -1, + // "created_at": "2019-12-27T12:48:24.000Z", + // "updated_at": "2019-12-27T12:48:24.000Z", + // "stop_px": 7500, + // "stop_order_id": "a85cd1c0-a9a4-49d3-a1bd-bab5ebe946d5" + // }, + // "ext_info": null, + // "time_now": "1577450904.327654", + // "rate_limit_status": 99, + // "rate_limit_reset_ms": 1577450904335, + // "rate_limit": "100" + // } + // + const result = this.safeValue (response, 'result'); + return this.parseOrder (result, market); + } + + async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' editOrder requires an symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + // 'order_id': id, // only for non-conditional orders + 'symbol': market['id'], + // 'p_r_qty': this.amountToPrecision (symbol, amount), // new order quantity, optional + // 'p_r_price' this.priceToprecision (symbol, price), // new order price, optional + // ---------------------------------------------------------------- + // conditional orders + // 'stop_order_id': id, // only for conditional orders + // 'p_r_trigger_price': 123.45, // new trigger price also known as stop_px + }; + const stopOrderId = this.safeString (params, 'stop_order_id'); + let method = 'openapiPostOrderReplace'; + if (stopOrderId !== undefined) { + method = 'openapiPostStopOrderReplace'; + request['stop_order_id'] = stopOrderId; + params = this.omit (params, [ 'stop_order_id' ]); + } else { + request['order_id'] = id; + } + if (amount !== undefined) { + request['p_r_qty'] = this.amountToPrecision (symbol, amount); + } + if (price !== undefined) { + request['p_r_price'] = this.priceToPrecision (symbol, price); + } + const response = await this[method] (this.extend (request, params)); + // + // { + // "ret_code": 0, + // "ret_msg": "ok", + // "ext_code": "", + // "result": { "order_id": "efa44157-c355-4a98-b6d6-1d846a936b93" }, + // "time_now": "1539778407.210858", + // "rate_limit_status": 99, // remaining number of accesses in one minute + // "rate_limit_reset_ms": 1580885703683, + // "rate_limit": 100 + // } + // + // conditional orders + // + // { + // "ret_code": 0, + // "ret_msg": "ok", + // "ext_code": "", + // "result": { "stop_order_id": "378a1bbc-a93a-4e75-87f4-502ea754ba36" }, + // "ext_info": null, + // "time_now": "1577475760.604942", + // "rate_limit_status": 96, + // "rate_limit_reset_ms": 1577475760612, + // "rate_limit": "100" + // } + // + const result = this.safeValue (response, 'result', {}); + return { + 'info': response, + 'id': this.safeString2 (result, 'order_id', 'stop_order_id'), + 'order_id': this.safeString (result, 'order_id'), + 'stop_order_id': this.safeString (result, 'stop_order_id'), + }; + } + + async cancelOrder (id, symbol = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + // 'order_link_id': 'string', // one of order_id, stop_order_id or order_link_id is required + // regular orders --------------------------------------------- + // 'order_id': id, // one of order_id or order_link_id is required for regular orders + // conditional orders --------------------------------------------- + // 'stop_order_id': id, // one of stop_order_id or order_link_id is required for conditional orders + }; + let method = 'privatePostOrderCancel'; + const stopOrderId = this.safeString (params, 'stop_order_id'); + if (stopOrderId === undefined) { + const orderLinkId = this.safeString (params, 'order_link_id'); + if (orderLinkId === undefined) { + request['order_id'] = id; + } + } else { + method = 'openapiPostStopOrderCancel'; + } + const response = await this[method] (this.extend (request, params)); + const result = this.safeValue (response, 'result', {}); + return this.parseOrder (result, market); + } + + async cancelAllOrders (symbol = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' cancelAllOrders requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const options = this.safeValue (this.options, 'cancelAllOrders'); + const method = this.safeString (options, 'method', 'privatePostOrderCancelAll'); + const response = await this[method] (this.extend (request, params)); + const result = this.safeValue (response, 'result', []); + return this.parseOrders (result, market); + } + + async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'order_id': 'string' + // 'order_link_id': 'string', // unique client order id, max 36 characters + // 'symbol': market['id'], // default BTCUSD + // 'order': 'desc', // asc + // 'page': 1, + // 'limit': 20, // max 50 + // 'order_status': 'Created,New' + // conditional orders --------------------------------------------- + // 'stop_order_id': 'string', + // 'stop_order_status': 'Untriggered', + }; + let market = undefined; + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + } + if (limit !== undefined) { + request['limit'] = limit; + } + const options = this.safeValue (this.options, 'fetchOrders', {}); + let defaultMethod = 'openapiGetOrderList'; + let query = params; + if (('stop_order_id' in params) || ('stop_order_status' in params)) { + let stopOrderStatus = this.safeValue (params, 'stopOrderStatus'); + if (stopOrderStatus !== undefined) { + if (Array.isArray (stopOrderStatus)) { + stopOrderStatus = stopOrderStatus.join (','); + } + request['stop_order_status'] = stopOrderStatus; + query = this.omit (params, 'stop_order_status'); + } + defaultMethod = 'openapiGetStopOrderList'; + } + const method = this.safeString (options, 'method', defaultMethod); + const response = await this[method] (this.extend (request, query)); + // + // { + // "ret_code": 0, + // "ret_msg": "ok", + // "ext_code": "", + // "result": { + // "current_page": 1, + // "last_page": 6, + // "data": [ + // { + // "user_id": 1, + // "symbol": "BTCUSD", + // "side": "Sell", + // "order_type": "Market", + // "price": 7074, + // "qty": 2, + // "time_in_force": "ImmediateOrCancel", + // "order_status": "Filled", + // "ext_fields": { + // "close_on_trigger": true, + // "orig_order_type": "BLimit", + // "prior_x_req_price": 5898.5, + // "op_from": "pc", + // "remark": "127.0.0.1", + // "o_req_num": -34799032763, + // "xreq_type": "x_create" + // }, + // "last_exec_time": "1577448481.696421", + // "last_exec_price": 7070.5, + // "leaves_qty": 0, + // "leaves_value": 0, + // "cum_exec_qty": 2, + // "cum_exec_value": 0.00028283, + // "cum_exec_fee": 0.00002, + // "reject_reason": "NoError", + // "order_link_id": "", + // "created_at": "2019-12-27T12:08:01.000Z", + // "updated_at": "2019-12-27T12:08:01.000Z", + // "order_id": "f185806b-b801-40ff-adec-52289370ed62" + // } + // ] + // }, + // "ext_info": null, + // "time_now": "1577448922.437871", + // "rate_limit_status": 98, + // "rate_limit_reset_ms": 1580885703683, + // "rate_limit": 100 + // } + // + // conditional orders + // + // { + // "ret_code": 0, + // "ret_msg": "ok", + // "ext_code": "", + // "result": { + // "current_page": 1, + // "last_page": 1, + // "data": [ + // { + // "user_id": 1, + // "stop_order_status": "Untriggered", + // "symbol": "BTCUSD", + // "side": "Buy", + // "order_type": "Limit", + // "price": 8000, + // "qty": 1, + // "time_in_force": "GoodTillCancel", + // "stop_order_type": "Stop", + // "trigger_by": "LastPrice", + // "base_price": 7000, + // "order_link_id": "", + // "created_at": "2019-12-27T12:48:24.000Z", + // "updated_at": "2019-12-27T12:48:24.000Z", + // "stop_px": 7500, + // "stop_order_id": "a85cd1c0-a9a4-49d3-a1bd-bab5ebe946d5" + // }, + // ] + // }, + // "ext_info": null, + // "time_now": "1577451658.755468", + // "rate_limit_status": 599, + // "rate_limit_reset_ms": 1577451658762, + // "rate_limit": 600 + // } + // + const result = this.safeValue (response, 'result', {}); + const data = this.safeValue (result, 'data', []); + return this.parseOrders (data, market, since, limit); + } + + async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + const defaultStatuses = [ + 'Rejected', + 'Filled', + 'Cancelled', + // conditional orders + // 'Active', + // 'Triggered', + // 'Cancelled', + // 'Rejected', + // 'Deactivated', + ]; + const options = this.safeValue (this.options, 'fetchClosedOrders', {}); + let status = this.safeValue (options, 'order_status', defaultStatuses); + if (Array.isArray (status)) { + status = status.join (','); + } + const request = {}; + const stopOrderStatus = this.safeValue (params, 'stop_order_status'); + if (stopOrderStatus === undefined) { + request['order_status'] = status; + } else { + request['stop_order_status'] = stopOrderStatus; + } + return await this.fetchOrders (symbol, since, limit, this.extend (request, params)); + } + + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + const defaultStatuses = [ + 'Created', + 'New', + 'PartiallyFilled', + 'PendingCancel', + // conditional orders + // 'Untriggered', + ]; + const options = this.safeValue (this.options, 'fetchOpenOrders', {}); + let status = this.safeValue (options, 'order_status', defaultStatuses); + if (Array.isArray (status)) { + status = status.join (','); + } + const request = {}; + const stopOrderStatus = this.safeValue (params, 'stop_order_status'); + if (stopOrderStatus === undefined) { + request['order_status'] = status; + } else { + request['stop_order_status'] = stopOrderStatus; + } + return await this.fetchOrders (symbol, since, limit, this.extend (request, params)); + } + + async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { + const request = { + 'order_id': id, + }; + return await this.fetchMyTrades (symbol, since, limit, this.extend (request, params)); + } + + async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'order_id': 'f185806b-b801-40ff-adec-52289370ed62', // if not provided will return user's trading records + // 'symbol': market['id'], + // 'start_time': parseInt (since / 1000), + // 'page': 1, + // 'limit' 20, // max 50 + }; + let market = undefined; + if (symbol === undefined) { + const orderId = this.safeString (params, 'order_id'); + if (orderId === undefined) { + throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument or an order_id param'); + } else { + request['order_id'] = orderId; + params = this.omit (params, 'order_id'); + } + } else { + market = this.market (symbol); + request['symbol'] = market['id']; + } + if (since !== undefined) { + request['start_time'] = parseInt (since / 1000); + } + if (limit !== undefined) { + request['limit'] = limit; // default 20, max 50 + } + const response = await this.privateGetExecutionList (this.extend (request, params)); + // + // { + // "ret_code": 0, + // "ret_msg": "OK", + // "ext_code": "", + // "ext_info": "", + // "result": { + // "order_id": "Abandoned!!", // Abandoned!! + // "trade_list": [ + // { + // "closed_size": 0, + // "cross_seq": 277136382, + // "exec_fee": "0.0000001", + // "exec_id": "256e5ef8-abfe-5772-971b-f944e15e0d68", + // "exec_price": "8178.5", + // "exec_qty": 1, + // "exec_time": "1571676941.70682", + // "exec_type": "Trade", //Exec Type Enum + // "exec_value": "0.00012227", + // "fee_rate": "0.00075", + // "last_liquidity_ind": "RemovedLiquidity", //Liquidity Enum + // "leaves_qty": 0, + // "nth_fill": 2, + // "order_id": "7ad50cb1-9ad0-4f74-804b-d82a516e1029", + // "order_link_id": "", + // "order_price": "8178", + // "order_qty": 1, + // "order_type": "Market", //Order Type Enum + // "side": "Buy", //Side Enum + // "symbol": "BTCUSD", //Symbol Enum + // "user_id": 1 + // } + // ] + // }, + // "time_now": "1577483699.281488", + // "rate_limit_status": 118, + // "rate_limit_reset_ms": 1577483699244737, + // "rate_limit": 120 + // } + // + const result = this.safeValue (response, 'result', {}); + const trades = this.safeValue (result, 'trade_list', []); + return this.parseTrades (trades, market, since, limit); + } + + async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { + if (code === undefined) { + throw new ArgumentsRequired (this.id + ' fetchWithdrawals() requires a currency code argument'); + } + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + }; + if (limit !== undefined) { + request['count'] = limit; + } + const response = await this.privateGetGetDeposits (this.extend (request, params)); + // + // { + // "jsonrpc": "2.0", + // "id": 5611, + // "result": { + // "count": 1, + // "data": [ + // { + // "address": "2N35qDKDY22zmJq9eSyiAerMD4enJ1xx6ax", + // "amount": 5, + // "currency": "BTC", + // "received_timestamp": 1549295017670, + // "state": "completed", + // "transaction_id": "230669110fdaf0a0dbcdc079b6b8b43d5af29cc73683835b9bc6b3406c065fda", + // "updated_timestamp": 1549295130159 + // } + // ] + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const data = this.safeValue (result, 'data', []); + return this.parseTransactions (data, currency, since, limit, params); + } + + async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'coin': currency['id'], + // 'start_date': this.iso8601 (since), + // 'end_date': this.iso8601 (till), + // 'status': 'Pending', // ToBeConfirmed, UnderReview, Pending, Success, CancelByUser, Reject, Expire + // 'page': 1, + // 'limit': 20, // max 50 + }; + let currency = undefined; + if (code !== undefined) { + currency = this.currency (code); + request['coin'] = currency['id']; + } + if (since !== undefined) { + request['start_date'] = this.iso8601 (since); + } + if (limit !== undefined) { + request['limit'] = limit; + } + const response = await this.openapiGetWalletWithdrawList (this.extend (request, params)); + // + // { + // "ret_code": 0, + // "ret_msg": "ok", + // "ext_code": "", + // "result": { + // "data": [ + // { + // "id": 137, + // "user_id": 1, + // "coin": "XRP", // Coin Enum + // "status": "Pending", // Withdraw Status Enum + // "amount": "20.00000000", + // "fee": "0.25000000", + // "address": "rH7H595XYEVTEHU2FySYsWnmfACBnZS9zM", + // "tx_id": "", + // "submited_at": "2019-06-11T02:20:24.000Z", + // "updated_at": "2019-06-11T02:20:24.000Z" + // }, + // ], + // "current_page": 1, + // "last_page": 1 + // }, + // "ext_info": null, + // "time_now": "1577482295.125488", + // "rate_limit_status": 119, + // "rate_limit_reset_ms": 1577482295132, + // "rate_limit": 120 + // } + // + const result = this.safeValue (response, 'result', {}); + const data = this.safeValue (result, 'data', []); + return this.parseTransactions (data, currency, since, limit, params); + } + + parseTransactionStatus (status) { + const statuses = { + 'ToBeConfirmed': 'pending', + 'UnderReview': 'pending', + 'Pending': 'pending', + 'Success': 'ok', + 'CancelByUser': 'canceled', + 'Reject': 'rejected', + 'Expire': 'expired', + }; + return this.safeString (statuses, status, status); + } + + parseTransaction (transaction, currency = undefined) { + // + // fetchWithdrawals + // + // { + // "id": 137, + // "user_id": 1, + // "coin": "XRP", // Coin Enum + // "status": "Pending", // Withdraw Status Enum + // "amount": "20.00000000", + // "fee": "0.25000000", + // "address": "rH7H595XYEVTEHU2FySYsWnmfACBnZS9zM", + // "tx_id": "", + // "submited_at": "2019-06-11T02:20:24.000Z", + // "updated_at": "2019-06-11T02:20:24.000Z" + // } + // + const currencyId = this.safeString (transaction, 'coin'); + const code = this.safeCurrencyCode (currencyId, currency); + const timestamp = this.parse8601 (this.safeString (transaction, 'submited_at')); + const updated = this.parse8601 (this.safeString (transaction, 'updated_at')); + const status = this.parseTransactionStatus (this.safeString (transaction, 'status')); + const address = this.safeString (transaction, 'address'); + const feeCost = this.safeFloat (transaction, 'fee'); + let fee = undefined; + if (feeCost !== undefined) { + fee = { + 'cost': feeCost, + 'currency': code, + }; + } + return { + 'info': transaction, + 'id': this.safeString (transaction, 'id'), + 'txid': this.safeString (transaction, 'tx_id'), + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'address': address, + 'addressTo': undefined, + 'addressFrom': undefined, + 'tag': undefined, + 'tagTo': undefined, + 'tagFrom': undefined, + 'type': 'withdrawal', + 'amount': this.safeFloat (transaction, 'amount'), + 'currency': code, + 'status': status, + 'updated': updated, + 'fee': fee, + }; + } + + async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'coin': currency['id'], + // 'currency': currency['id'], // alias + // 'start_date': this.iso8601 (since), + // 'end_date': this.iso8601 (till), + // 'wallet_fund_type': 'Deposit', // Withdraw, RealisedPNL, Commission, Refund, Prize, ExchangeOrderWithdraw, ExchangeOrderDeposit + // 'page': 1, + // 'limit': 20, // max 50 + }; + let currency = undefined; + if (code !== undefined) { + currency = this.currency (code); + request['coin'] = currency['id']; + } + if (since !== undefined) { + request['start_date'] = this.iso8601 (since); + } + if (limit !== undefined) { + request['limit'] = limit; + } + const response = await this.openapiGetWalletFundRecords (this.extend (request, params)); + // + // { + // "ret_code": 0, + // "ret_msg": "ok", + // "ext_code": "", + // "result": { + // "data": [ + // { + // "id": 234467, + // "user_id": 1, + // "coin": "BTC", + // "wallet_id": 27913, + // "type": "Realized P&L", + // "amount": "-0.00000006", + // "tx_id": "", + // "address": "BTCUSD", + // "wallet_balance": "0.03000330", + // "exec_time": "2019-12-09T00:00:25.000Z", + // "cross_seq": 0 + // } + // ] + // }, + // "ext_info": null, + // "time_now": "1577481867.115552", + // "rate_limit_status": 119, + // "rate_limit_reset_ms": 1577481867122, + // "rate_limit": 120 + // } + // + const result = this.safeValue (response, 'result', {}); + const data = this.safeValue (result, 'data', []); + return this.parseLedger (data, currency, since, limit); + } + + parseLedgerEntry (item, currency = undefined) { + // + // { + // "id": 234467, + // "user_id": 1, + // "coin": "BTC", + // "wallet_id": 27913, + // "type": "Realized P&L", + // "amount": "-0.00000006", + // "tx_id": "", + // "address": "BTCUSD", + // "wallet_balance": "0.03000330", + // "exec_time": "2019-12-09T00:00:25.000Z", + // "cross_seq": 0 + // } + // + const currencyId = this.safeString (item, 'coin'); + const code = this.safeCurrencyCode (currencyId, currency); + const amount = this.safeFloat (item, 'amount'); + const after = this.safeFloat (item, 'wallet_balance'); + const direction = (amount < 0) ? 'out' : 'in'; + let before = undefined; + if (after !== undefined && amount !== undefined) { + const difference = (direction === 'out') ? amount : -amount; + before = this.sum (after, difference); + } + const timestamp = this.parse8601 (this.safeString (item, 'exec_time')); + const type = this.parseLedgerEntryType (this.safeString (item, 'type')); + const id = this.safeString (item, 'id'); + const referenceId = this.safeString (item, 'tx_id'); + return { + 'id': id, + 'currency': code, + 'account': this.safeString (item, 'wallet_id'), + 'referenceAccount': undefined, + 'referenceId': referenceId, + 'status': undefined, + 'amount': amount, + 'before': before, + 'after': after, + 'fee': undefined, + 'direction': direction, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'type': type, + 'info': item, + }; + } + + parseLedgerEntryType (type) { + const types = { + 'Deposit': 'transaction', + 'Withdraw': 'transaction', + 'RealisedPNL': 'trade', + 'Commission': 'fee', + 'Refund': 'cashback', + 'Prize': 'prize', // ? + 'ExchangeOrderWithdraw': 'transaction', + 'ExchangeOrderDeposit': 'transaction', + }; + return this.safeString (types, type, type); + } + + sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { + let url = this.urls['api']; + let request = path; + // public v2 + if (api === 'public') { + request = '/' + this.version + '/' + api + '/' + request; + if (Object.keys (params).length) { + request += '?' + this.rawencode (params); + } + } else { + this.checkRequiredCredentials (); + if (api === 'openapi') { + request = '/open-api/' + request; + } else if (api === 'private') { + // private v2 + request = '/' + this.version + '/' + api + '/' + request; + } else { + // position, user + request += '/' + api + '/' + request; + } + const timestamp = this.nonce (); + const query = this.extend (params, { + 'api_key': this.apiKey, + 'recvWindow': this.options['recvWindow'], + 'timestamp': timestamp, + }); + const auth = this.rawencode (this.keysort (query)); + const signature = this.hmac (this.encode (auth), this.encode (this.secret)); + if (method === 'POST') { + body = this.json (this.extend (query, { + 'sign': signature, + })); + headers = { + 'Content-Type': 'application/json', + }; + } else { + request += '?' + auth + '&sign=' + signature; + } + } + url += request; + return { 'url': url, 'method': method, 'body': body, 'headers': headers }; + } + + handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (!response) { + return; // fallback to default error handler + } + // + // { + // ret_code: 10001, + // ret_msg: 'ReadMapCB: expect { or n, but found \u0000, error ' + + // 'found in #0 byte of ...||..., bigger context ' + + // '...||...', + // ext_code: '', + // ext_info: '', + // result: null, + // time_now: '1583934106.590436' + // } + // + const errorCode = this.safeValue (response, 'ret_code'); + if (errorCode !== 0) { + const feedback = this.id + ' ' + body; + this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback); + this.throwBroadlyMatchedException (this.exceptions['broad'], body, feedback); + throw new ExchangeError (feedback); // unknown message + } + } +}; diff --git a/TaskServer/node_modules/ccxt/js/bytetrade.js b/TaskServer/node_modules/ccxt/js/bytetrade.js index 925504cf1..3019af02f 100644 --- a/TaskServer/node_modules/ccxt/js/bytetrade.js +++ b/TaskServer/node_modules/ccxt/js/bytetrade.js @@ -47,10 +47,10 @@ module.exports = class bytetrade extends Exchange { '1M': '1M', }, 'urls': { - 'test': 'https://api-v2-test.bytetrade.com', + 'test': 'https://api-v2-test.byte-trade.com', 'logo': 'https://user-images.githubusercontent.com/1294454/67288762-2f04a600-f4e6-11e9-9fd6-c60641919491.jpg', - 'api': 'https://api-v2.bytetrade.com', - 'www': 'https://www.bytetrade.com', + 'api': 'https://api-v2.byte-trade.com', + 'www': 'https://www.byte-trade.com', 'doc': 'https://github.com/Bytetrade/bytetrade-official-api-docs/wiki', }, 'api': { @@ -92,6 +92,7 @@ module.exports = class bytetrade extends Exchange { }, }, 'commonCurrencies': { + '44': 'ByteHub', '48': 'Blocktonic', }, 'exceptions': { @@ -116,7 +117,7 @@ module.exports = class bytetrade extends Exchange { code = this.safeString (currency, 'name'); } const name = this.safeString (currency, 'fullname'); - // in bytetrade.com DEX, request https://api-v2.bytetrade.com/currencies will return currencies, + // in byte-trade.com DEX, request https://api-v2.byte-trade.com/currencies will return currencies, // the api doc is https://github.com/Bytetrade/bytetrade-official-api-docs/wiki/rest-api#get-currencies-get-currencys-supported-in-bytetradecom // we can see the coin name is none-unique in the result, the coin which code is 18 is the CyberMiles ERC20, and the coin which code is 35 is the CyberMiles main chain, but their name is same. // that is because bytetrade is a DEX, supports people create coin with the same name, but the id(code) of coin is unique, so we should use the id or name and id as the identity of coin. @@ -216,6 +217,9 @@ module.exports = class bytetrade extends Exchange { const id = this.safeString (market, 'symbol'); let base = this.safeString (market, 'baseName'); let quote = this.safeString (market, 'quoteName'); + const normalBase = base.split ('@')[0]; + const normalQuote = quote.split ('@')[0]; + const normalSymbol = normalBase + '/' + normalQuote; const baseId = this.safeString (market, 'base'); const quoteId = this.safeString (market, 'quote'); if (baseId in this.commonCurrencies) { @@ -230,9 +234,6 @@ module.exports = class bytetrade extends Exchange { const price = this.safeValue (limits, 'price', {}); const precision = this.safeValue (market, 'precision', {}); const active = this.safeString (market, 'active'); - const normalBase = base.split ('@')[0]; - const normalQuote = quote.split ('@')[0]; - const normalSymbol = normalBase + '/' + normalQuote; const entry = { 'id': id, 'symbol': symbol, @@ -540,6 +541,7 @@ module.exports = class bytetrade extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': datetime, 'lastTradeTimestamp': lastTradeTimestamp, @@ -554,6 +556,7 @@ module.exports = class bytetrade extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; } @@ -575,23 +578,25 @@ module.exports = class bytetrade extends Exchange { typeNum = 1; } else { typeNum = 2; + price = 0; } const normalSymbol = market['normalSymbol']; const baseId = market['baseId']; const baseCurrency = this.currency (market['base']); const amountTruncated = this.amountToPrecision (symbol, amount); - const amountChain = this.toWei (amountTruncated, 'ether', baseCurrency['precision']['amount']); + const amountChain = this.toWei (amountTruncated, baseCurrency['precision']['amount']); const quoteId = market['quoteId']; const quoteCurrency = this.currency (market['quote']); const priceRounded = this.priceToPrecision (symbol, price); - const priceChain = this.toWei (priceRounded, 'ether', quoteCurrency['precision']['amount']); + const priceChain = this.toWei (priceRounded, quoteCurrency['precision']['amount']); const now = this.milliseconds (); const expiration = this.milliseconds (); let datetime = this.iso8601 (now); datetime = datetime.split ('.')[0]; let expirationDatetime = this.iso8601 (expiration); expirationDatetime = expirationDatetime.split ('.')[0]; - const chainName = 'Sagittarius'; + const defaultDappId = 'Sagittarius'; + const dappId = this.safeString (params, 'dappId', defaultDappId); const defaultFee = this.safeString (this.options, 'fee', '300000000000000'); const fee = this.safeString (params, 'fee', defaultFee); const eightBytes = this.integerPow ('2', '64'); @@ -622,8 +627,8 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (parseInt (baseId), 4), this.numberToLE (0, 1), this.numberToLE (1, 1), - this.numberToLE (chainName.length, 1), - this.stringToBinary (this.encode (chainName)), + this.numberToLE (dappId.length, 1), + this.stringToBinary (this.encode (dappId)), this.numberToLE (0, 1), ]; const txByteStringArray = [ @@ -652,8 +657,8 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (parseInt (baseId), 4), this.numberToLE (0, 1), this.numberToLE (1, 1), - this.numberToLE (chainName.length, 1), - this.stringToBinary (this.encode (chainName)), + this.numberToLE (dappId.length, 1), + this.stringToBinary (this.encode (dappId)), this.numberToLE (0, 1), ]; const txbytestring = this.binaryConcatArray (txByteStringArray); @@ -696,7 +701,7 @@ module.exports = class bytetrade extends Exchange { ], ], 'validate_type': 0, - 'dapp': 'Sagittarius', + 'dapp': dappId, 'signatures': [ mySignature, ], @@ -725,6 +730,8 @@ module.exports = class bytetrade extends Exchange { 'cost': undefined, 'trades': undefined, 'fee': undefined, + 'clientOrderId': undefined, + 'average': undefined, }; } @@ -825,7 +832,8 @@ module.exports = class bytetrade extends Exchange { datetime = datetime.split ('.')[0]; let expirationDatetime = this.iso8601 (expiration); expirationDatetime = expirationDatetime.split ('.')[0]; - const chainName = 'Sagittarius'; + const defaultDappId = 'Sagittarius'; + const dappId = this.safeString (params, 'dappId', defaultDappId); const byteStringArray = [ this.numberToBE (1, 32), this.numberToLE (Math.floor (now / 1000), 4), @@ -844,8 +852,8 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (parseInt (baseId), 4), this.numberToLE (0, 1), this.numberToLE (1, 1), - this.numberToLE (chainName.length, 1), - this.stringToBinary (this.encode (chainName)), + this.numberToLE (dappId.length, 1), + this.stringToBinary (this.encode (dappId)), this.numberToLE (0, 1), ]; const bytestring = this.binaryConcatArray (byteStringArray); @@ -871,7 +879,7 @@ module.exports = class bytetrade extends Exchange { ], ], 'validate_type': 0, - 'dapp': 'Sagittarius', + 'dapp': dappId, 'signatures': [ mySignature, ], @@ -900,10 +908,12 @@ module.exports = class bytetrade extends Exchange { 'cost': undefined, 'trades': undefined, 'fee': undefined, + 'clientOrderId': undefined, + 'average': undefined, }; } - async transfer (code, amount, address, params = {}) { + async transfer (code, amount, address, message = '', params = {}) { this.checkRequiredDependencies (); if (this.apiKey === undefined) { throw new ArgumentsRequired ('transfer requires this.apiKey'); @@ -911,7 +921,7 @@ module.exports = class bytetrade extends Exchange { await this.loadMarkets (); const currency = this.currency (code); const amountTruncate = this.decimalToPrecision (amount, TRUNCATE, currency['info']['transferPrecision'], DECIMAL_PLACES, NO_PADDING); - const amountChain = this.toWei (amountTruncate, 'ether', currency['precision']['amount']); + const amountChain = this.toWei (amountTruncate, currency['precision']['amount']); const assetType = parseInt (currency['id']); const now = this.milliseconds (); const expiration = now; @@ -920,7 +930,8 @@ module.exports = class bytetrade extends Exchange { let expirationDatetime = this.iso8601 (expiration); expirationDatetime = expirationDatetime.split ('.')[0]; const feeAmount = '300000000000000'; - const chainName = 'Sagittarius'; + const defaultDappId = 'Sagittarius'; + const dappId = this.safeString (params, 'dappId', defaultDappId); const eightBytes = this.integerPow ('2', '64'); const byteStringArray = [ this.numberToBE (1, 32), @@ -928,7 +939,7 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (1, 1), this.numberToLE (Math.floor (expiration / 1000), 4), this.numberToLE (1, 1), - this.numberToLE (0, 1), + this.numberToLE (28, 1), this.numberToLE (0, 8), this.numberToLE (feeAmount, 8), // string for 32 bit php this.numberToLE (this.apiKey.length, 1), @@ -938,10 +949,13 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (assetType, 4), this.numberToLE (this.integerDivide (amountChain, eightBytes), 8), this.numberToLE (this.integerModulo (amountChain, eightBytes), 8), + this.numberToLE (1, 1), + this.numberToLE (message.length, 1), + this.stringToBinary (this.encode (message)), this.numberToLE (0, 1), this.numberToLE (1, 1), - this.numberToLE (chainName.length, 1), - this.stringToBinary (this.encode (chainName)), + this.numberToLE (dappId.length, 1), + this.stringToBinary (this.encode (dappId)), this.numberToLE (0, 1), ]; const bytestring = this.binaryConcatArray (byteStringArray); @@ -955,18 +969,19 @@ module.exports = class bytetrade extends Exchange { 'to': address, 'asset_type': parseInt (currency['id']), 'amount': amountChain.toString (), + 'message': message, }; const fatty = { 'timestamp': datetime, 'expiration': expirationDatetime, 'operations': [ [ - 0, + 28, operation, ], ], 'validate_type': 0, - 'dapp': 'Sagittarius', + 'dapp': dappId, 'signatures': [ mySignature, ], @@ -999,6 +1014,9 @@ module.exports = class bytetrade extends Exchange { 'remaining': undefined, 'cost': undefined, 'fee': undefined, + 'clientOrderId': undefined, + 'average': undefined, + 'trades': undefined, }; } @@ -1178,12 +1196,13 @@ module.exports = class bytetrade extends Exchange { datetime = datetime.split ('.')[0]; let expirationDatetime = this.iso8601 (expiration); expirationDatetime = expirationDatetime.split ('.')[0]; - const chainName = 'Sagittarius'; + const defaultDappId = 'Sagittarius'; + const dappId = this.safeString (params, 'dappId', defaultDappId); const feeAmount = '300000000000000'; const currency = this.currency (code); const coinId = currency['id']; const amountTruncate = this.decimalToPrecision (amount, TRUNCATE, currency['info']['transferPrecision'], DECIMAL_PLACES, NO_PADDING); - const amountChain = this.toWei (amountTruncate, 'ether', currency['info']['externalPrecision']); + const amountChain = this.toWei (amountTruncate, currency['info']['externalPrecision']); const eightBytes = this.integerPow ('2', '64'); let assetFee = 0; let byteStringArray = []; @@ -1210,8 +1229,8 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (this.integerModulo (assetFee, eightBytes), 8), this.numberToLE (0, 1), this.numberToLE (1, 1), - this.numberToLE (chainName.length, 1), - this.stringToBinary (this.encode (chainName)), + this.numberToLE (dappId.length, 1), + this.stringToBinary (this.encode (dappId)), this.numberToLE (0, 1), ]; } else { @@ -1240,8 +1259,8 @@ module.exports = class bytetrade extends Exchange { this.numberToLE (this.integerModulo (amountChain, eightBytes), 8), this.numberToLE (0, 1), this.numberToLE (1, 1), - this.numberToLE (chainName.length, 1), - this.stringToBinary (this.encode (chainName)), + this.numberToLE (dappId.length, 1), + this.stringToBinary (this.encode (dappId)), this.numberToLE (0, 1), ]; } @@ -1273,7 +1292,7 @@ module.exports = class bytetrade extends Exchange { ], ], 'validate_type': 0, - 'dapp': 'Sagittarius', + 'dapp': dappId, 'signatures': [ mySignature, ], @@ -1281,7 +1300,7 @@ module.exports = class bytetrade extends Exchange { request = { 'chainType': chainId, 'trObj': this.json (fatty), - 'chainContractAddresss': chainContractAddress, + 'chainContractAddress': chainContractAddress, }; } else { operation = { @@ -1310,7 +1329,7 @@ module.exports = class bytetrade extends Exchange { ], ], 'validate_type': 0, - 'dapp': 'Sagittarius', + 'dapp': dappId, 'signatures': [ mySignature, ], @@ -1320,14 +1339,14 @@ module.exports = class bytetrade extends Exchange { 'chainType': chainId, 'toExternalAddress': 'noneed', 'trObj': this.json (fatty), - 'chainContractAddresss': chainContractAddress, + 'chainContractAddress': chainContractAddress, }; } else { request = { 'chainType': chainId, 'toExternalAddress': address, 'trObj': this.json (fatty), - 'chainContractAddresss': chainContractAddress, + 'chainContractAddress': chainContractAddress, }; } } diff --git a/TaskServer/node_modules/ccxt/js/cex.js b/TaskServer/node_modules/ccxt/js/cex.js index 076f2c312..24efe1a0e 100644 --- a/TaskServer/node_modules/ccxt/js/cex.js +++ b/TaskServer/node_modules/ccxt/js/cex.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, ArgumentsRequired, NullResponse, InvalidOrder, NotSupported, InsufficientFunds, InvalidNonce, OrderNotFound, RateLimitExceeded } = require ('./base/errors'); +const { ExchangeError, ArgumentsRequired, AuthenticationError, NullResponse, InvalidOrder, NotSupported, InsufficientFunds, InvalidNonce, OrderNotFound, RateLimitExceeded } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -15,7 +15,7 @@ module.exports = class cex extends Exchange { 'countries': [ 'GB', 'EU', 'CY', 'RU' ], 'rateLimit': 1500, 'has': { - 'CORS': true, + 'CORS': false, 'fetchCurrencies': true, 'fetchTickers': true, 'fetchOHLCV': true, @@ -126,6 +126,8 @@ module.exports = class cex extends Exchange { 'Invalid Order': InvalidOrder, 'Order not found': OrderNotFound, 'Rate limit exceeded': RateLimitExceeded, + 'Invalid API key': AuthenticationError, + 'There was an error while placing your order': InvalidOrder, }, }, 'options': { @@ -352,6 +354,7 @@ module.exports = class cex extends Exchange { 'max': undefined, }, }, + 'active': undefined, }); } return result; @@ -803,11 +806,14 @@ module.exports = class cex extends Exchange { 'currency': market['quote'], }, 'info': item, + 'type': undefined, + 'takerOrMaker': undefined, }); } } return { 'id': orderId, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -823,6 +829,7 @@ module.exports = class cex extends Exchange { 'trades': trades, 'fee': fee, 'info': order, + 'average': undefined, }; } @@ -1152,12 +1159,12 @@ module.exports = class cex extends Exchange { if (Array.isArray (response)) { return response; // public endpoints may return []-arrays } + if (body === 'true') { + return; + } if (response === undefined) { throw new NullResponse (this.id + ' returned ' + this.json (response)); } - if (response === true || response === 'true') { - return; - } if ('e' in response) { if ('ok' in response) { if (response['ok'] === 'ok') { diff --git a/TaskServer/node_modules/ccxt/js/cobinhood.js b/TaskServer/node_modules/ccxt/js/cobinhood.js deleted file mode 100644 index 4a1ac33a6..000000000 --- a/TaskServer/node_modules/ccxt/js/cobinhood.js +++ /dev/null @@ -1,861 +0,0 @@ -'use strict'; - -// --------------------------------------------------------------------------- - -const Exchange = require ('./base/Exchange'); -const { ExchangeError, InvalidAddress, InsufficientFunds, InvalidNonce, InvalidOrder, OrderNotFound, PermissionDenied } = require ('./base/errors'); - -// --------------------------------------------------------------------------- - -module.exports = class cobinhood extends Exchange { - describe () { - return this.deepExtend (super.describe (), { - 'id': 'cobinhood', - 'name': 'COBINHOOD', - 'countries': [ 'TW' ], - 'rateLimit': 1000 / 10, - 'version': 'v1', - 'has': { - 'fetchCurrencies': true, - 'fetchTickers': true, - 'fetchOHLCV': true, - 'fetchOpenOrders': true, - 'fetchClosedOrders': true, - 'fetchOrderTrades': true, - 'fetchOrder': true, - 'fetchDepositAddress': true, - 'createDepositAddress': true, - 'fetchDeposits': true, - 'fetchWithdrawals': true, - 'withdraw': true, - 'fetchMyTrades': true, - 'editOrder': true, - }, - 'requiredCredentials': { - 'apiKey': true, - 'secret': false, - }, - 'timeframes': { - // the first two don't seem to work at all - '1m': '1m', - '5m': '5m', - '15m': '15m', - '30m': '30m', - '1h': '1h', - '3h': '3h', - '6h': '6h', - '12h': '12h', - '1d': '1D', - '1w': '7D', - '2w': '14D', - '1M': '1M', - }, - 'urls': { - 'referral': 'https://cobinhood.com?referrerId=a9d57842-99bb-4d7c-b668-0479a15a458b', - 'logo': 'https://user-images.githubusercontent.com/1294454/35755576-dee02e5c-0878-11e8-989f-1595d80ba47f.jpg', - 'api': 'https://api.cobinhood.com', - 'www': 'https://cobinhood.com', - 'doc': 'https://cobinhood.github.io/api-public', - }, - 'api': { - 'system': { - 'get': [ - 'info', - 'time', - 'messages', - 'messages/{message_id}', - ], - }, - 'admin': { - 'get': [ - 'system/messages', - 'system/messages/{message_id}', - ], - 'post': [ - 'system/messages', - ], - 'patch': [ - 'system/messages/{message_id}', - ], - 'delete': [ - 'system/messages/{message_id}', - ], - }, - 'public': { - 'get': [ - 'market/fundingbook/precisions/{currency_id}', - 'market/fundingbooks/{currency_id}', - 'market/tickers', - 'market/currencies', - 'market/quote_currencies', - 'market/trading_pairs', - 'market/orderbook/precisions/{trading_pair_id}', - 'market/orderbooks/{trading_pair_id}', - 'market/stats', - 'market/tickers', // fetchTickers - 'market/tickers/{trading_pair_id}', - 'market/trades/{trading_pair_id}', - 'market/trades_history/{trading_pair_id}', - 'market/trading_pairs', - 'chart/candles/{trading_pair_id}', - 'system/time', - ], - }, - 'private': { - 'get': [ - 'funding/auto_offerings', - 'funding/auto_offerings/{currency_id}', - 'funding/funding_history', - 'funding/fundings', - 'funding/loans', - 'funding/loans/{loan_id}', - 'trading/orders/{order_id}', - 'trading/orders/{order_id}/trades', - 'trading/orders', - 'trading/order_history', - 'trading/positions', - 'trading/positions/{trading_pair_id}', - 'trading/positions/{trading_pair_id}/claimable_size', - 'trading/trades', - 'trading/trades/{trade_id}', - 'trading/volume', - 'wallet/balances', - 'wallet/ledger', - 'wallet/limits/withdrawal', - 'wallet/generic_deposits', - 'wallet/generic_deposits/{generic_deposit_id}', - 'wallet/generic_withdrawals', - 'wallet/generic_withdrawals/{generic_withdrawal_id}', - // older endpoints - 'wallet/deposit_addresses', - 'wallet/deposit_addresses/iota', - 'wallet/withdrawal_addresses', - 'wallet/withdrawal_frozen', - 'wallet/withdrawals/{withdrawal_id}', - 'wallet/withdrawals', - 'wallet/deposits/{deposit_id}', - 'wallet/deposits', - ], - 'patch': [ - 'trading/positions/{trading_pair_id}', - ], - 'post': [ - 'funding/auto_offerings', - 'funding/fundings', - 'trading/check_order', - 'trading/orders', - // older endpoints - 'wallet/deposit_addresses', - 'wallet/transfer', - 'wallet/withdrawal_addresses', - 'wallet/withdrawals', - 'wallet/withdrawals/fee', - ], - 'put': [ - 'funding/fundings/{funding_id}', - 'trading/orders/{order_id}', - ], - 'delete': [ - 'funding/auto_offerings/{currency_id}', - 'funding/fundings/{funding_id}', - 'funding/loans/{loan_id}', - 'trading/orders/{order_id}', - 'trading/positions/{trading_pair_id}', - 'wallet/generic_withdrawals/{generic_withdrawal_id}', - 'wallet/withdrawal_addresses/{wallet_id}', - ], - }, - }, - 'fees': { - 'trading': { - 'maker': 0.0, - 'taker': 0.0, - }, - }, - 'precision': { - 'amount': 8, - 'price': 8, - }, - 'exceptions': { - 'insufficient_balance': InsufficientFunds, - 'invalid_order_size': InvalidOrder, - 'invalid_nonce': InvalidNonce, - 'unauthorized_scope': PermissionDenied, - 'invalid_address': InvalidAddress, - 'parameter_error': OrderNotFound, - }, - 'commonCurrencies': { - 'SMT': 'SocialMedia.Market', - 'MTN': 'Motion Token', - }, - }); - } - - async fetchCurrencies (params = {}) { - const response = await this.publicGetMarketCurrencies (params); - const currencies = response['result']['currencies']; - const result = {}; - for (let i = 0; i < currencies.length; i++) { - const currency = currencies[i]; - const id = this.safeString (currency, 'currency'); - const name = this.safeString (currency, 'name'); - const code = this.safeCurrencyCode (id); - const minUnit = this.safeFloat (currency, 'min_unit'); - result[code] = { - 'id': id, - 'code': code, - 'name': name, - 'active': true, - 'fiat': false, - 'precision': this.precisionFromString (currency['min_unit']), - 'limits': { - 'amount': { - 'min': minUnit, - 'max': undefined, - }, - 'price': { - 'min': minUnit, - 'max': undefined, - }, - 'deposit': { - 'min': minUnit, - 'max': undefined, - }, - 'withdraw': { - 'min': minUnit, - 'max': undefined, - }, - }, - 'funding': { - 'withdraw': { - 'fee': this.safeFloat (currency, 'withdrawal_fee'), - }, - 'deposit': { - 'fee': this.safeFloat (currency, 'deposit_fee'), - }, - }, - 'info': currency, - }; - } - return result; - } - - async fetchMarkets (params = {}) { - const response = await this.publicGetMarketTradingPairs (params); - const markets = this.safeValue (response['result'], 'trading_pairs'); - const result = []; - for (let i = 0; i < markets.length; i++) { - const market = markets[i]; - const id = this.safeString (market, 'id'); - const [ baseId, quoteId ] = id.split ('-'); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - const symbol = base + '/' + quote; - const precision = { - 'amount': 8, - 'price': this.precisionFromString (market['quote_increment']), - }; - const active = this.safeValue (market, 'is_active', true); - result.push ({ - 'id': id, - 'symbol': symbol, - 'base': base, - 'quote': quote, - 'baseId': baseId, - 'quoteId': quoteId, - 'active': active, - 'precision': precision, - 'limits': { - 'amount': { - 'min': this.safeFloat (market, 'base_min_size'), - 'max': this.safeFloat (market, 'base_max_size'), - }, - 'price': { - 'min': undefined, - 'max': undefined, - }, - 'cost': { - 'min': undefined, - 'max': undefined, - }, - }, - 'info': market, - }); - } - return result; - } - - parseTicker (ticker, market = undefined) { - let symbol = undefined; - if (market === undefined) { - const marketId = this.safeString (ticker, 'trading_pair_id'); - if (marketId in this.markets_by_id) { - market = this.markets_by_id[marketId]; - } else { - const [ baseId, quoteId ] = marketId.split ('-'); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - symbol = base + '/' + quote; - } - } - if (market !== undefined) { - symbol = market['symbol']; - } - const timestamp = this.safeInteger (ticker, 'timestamp'); - const last = this.safeFloat (ticker, 'last_trade_price'); - return { - 'symbol': symbol, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'high': this.safeFloat (ticker, '24h_high'), - 'low': this.safeFloat (ticker, '24h_low'), - 'bid': this.safeFloat (ticker, 'highest_bid'), - 'bidVolume': undefined, - 'ask': this.safeFloat (ticker, 'lowest_ask'), - 'askVolume': undefined, - 'vwap': undefined, - 'open': undefined, - 'close': last, - 'last': last, - 'previousClose': undefined, - 'change': this.safeFloat (ticker, 'percentChanged24hr'), - 'percentage': undefined, - 'average': undefined, - 'baseVolume': this.safeFloat (ticker, '24h_volume'), - 'quoteVolume': this.safeFloat (ticker, 'quote_volume'), - 'info': ticker, - }; - } - - async fetchTicker (symbol, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'trading_pair_id': market['id'], - }; - const response = await this.publicGetMarketTickersTradingPairId (this.extend (request, params)); - const ticker = this.safeValue (response['result'], 'ticker'); - return this.parseTicker (ticker, market); - } - - async fetchTickers (symbols = undefined, params = {}) { - await this.loadMarkets (); - const response = await this.publicGetMarketTickers (params); - const tickers = this.safeValue (response['result'], 'tickers'); - const result = []; - for (let i = 0; i < tickers.length; i++) { - result.push (this.parseTicker (tickers[i])); - } - return this.indexBy (result, 'symbol'); - } - - async fetchOrderBook (symbol, limit = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'trading_pair_id': this.marketId (symbol), - }; - if (limit !== undefined) { - request['limit'] = limit; // 100 - } - const response = await this.publicGetMarketOrderbooksTradingPairId (this.extend (request, params)); - return this.parseOrderBook (response['result']['orderbook'], undefined, 'bids', 'asks', 0, 2); - } - - parseTrade (trade, market = undefined) { - let symbol = undefined; - if (market) { - symbol = market['symbol']; - } - const timestamp = this.safeInteger (trade, 'timestamp'); - const price = this.safeFloat (trade, 'price'); - const amount = this.safeFloat (trade, 'size'); - let cost = undefined; - if (price !== undefined) { - if (amount !== undefined) { - cost = price * amount; - } - } - // you can't determine your side from maker/taker side and vice versa - // you can't determine if your order/trade was a maker or a taker based - // on just the side of your order/trade - // https://github.com/ccxt/ccxt/issues/4300 - // let side = (trade['maker_side'] === 'bid') ? 'sell' : 'buy'; - const side = undefined; - const id = this.safeString (trade, 'id'); - return { - 'info': trade, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': symbol, - 'id': id, - 'order': undefined, - 'type': undefined, - 'side': side, - 'takerOrMaker': undefined, - 'price': price, - 'amount': amount, - 'cost': cost, - 'fee': undefined, - }; - } - - async fetchTrades (symbol, since = undefined, limit = 50, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'trading_pair_id': market['id'], - 'limit': limit, // default 20, but that seems too little - }; - const response = await this.publicGetMarketTradesTradingPairId (this.extend (request, params)); - const trades = this.safeValue (response['result'], 'trades'); - return this.parseTrades (trades, market, since, limit); - } - - parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) { - return [ - // they say that timestamps are Unix Timestamps in seconds, but in fact those are milliseconds - ohlcv['timestamp'], - parseFloat (ohlcv['open']), - parseFloat (ohlcv['high']), - parseFloat (ohlcv['low']), - parseFloat (ohlcv['close']), - parseFloat (ohlcv['volume']), - ]; - } - - async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - // - // they say in their docs that end_time defaults to current server time - // but if you don't specify it, their range limits does not allow you to query anything - // - // they also say that start_time defaults to 0, - // but most calls fail if you do not specify any of end_time - // - // to make things worse, their docs say it should be a Unix Timestamp - // but with seconds it fails, so we set milliseconds (somehow it works that way) - // - const endTime = this.milliseconds (); - const request = { - 'trading_pair_id': market['id'], - 'timeframe': this.timeframes[timeframe], - 'end_time': endTime, - }; - if (since !== undefined) { - request['start_time'] = since; - } - const response = await this.publicGetChartCandlesTradingPairId (this.extend (request, params)); - const ohlcv = this.safeValue (response['result'], 'candles'); - return this.parseOHLCVs (ohlcv, market, timeframe, since, limit); - } - - async fetchBalance (params = {}) { - await this.loadMarkets (); - const response = await this.privateGetWalletBalances (params); - const result = { 'info': response }; - const balances = this.safeValue (response['result'], 'balances'); - for (let i = 0; i < balances.length; i++) { - const balance = balances[i]; - const currencyId = this.safeString (balance, 'currency'); - const code = this.safeCurrencyCode (currencyId); - const account = this.account (); - account['used'] = this.safeFloat (balance, 'on_order'); - account['total'] = this.safeFloat (balance, 'total'); - result[code] = account; - } - return this.parseBalance (result); - } - - parseOrderStatus (status) { - const statuses = { - 'filled': 'closed', - 'rejected': 'closed', - 'partially_filled': 'open', - 'pending_cancellation': 'open', - 'pending_modification': 'open', - 'open': 'open', - 'new': 'open', - 'queued': 'open', - 'cancelled': 'canceled', - 'triggered': 'triggered', - }; - return this.safeString (statuses, status, status); - } - - parseOrder (order, market = undefined) { - // - // { - // 'completed_at': None, - // 'eq_price': '0', - // 'filled': '0', - // 'id': '88426800-beae-4407-b4a1-f65cef693542', - // 'price': '0.00000507', - // 'side': 'bid', - // 'size': '3503.6489', - // 'source': 'exchange', - // 'state': 'open', - // 'timestamp': 1535258403597, - // 'trading_pair_id': 'ACT-BTC', - // 'type': 'limit', - // } - // - let symbol = undefined; - if (market === undefined) { - const marketId = this.safeString2 (order, 'trading_pair', 'trading_pair_id'); - market = this.safeValue (this.markets_by_id, marketId); - } - if (market !== undefined) { - symbol = market['symbol']; - } - const timestamp = this.safeInteger (order, 'timestamp'); - const price = this.safeFloat (order, 'price'); - const average = this.safeFloat (order, 'eq_price'); - const amount = this.safeFloat (order, 'size'); - const filled = this.safeFloat (order, 'filled'); - let remaining = undefined; - let cost = undefined; - if (filled !== undefined && average !== undefined) { - cost = average * filled; - } else if (average !== undefined) { - cost = average * amount; - } - if (amount !== undefined) { - if (filled !== undefined) { - remaining = amount - filled; - } - } - const status = this.parseOrderStatus (this.safeString (order, 'state')); - let side = this.safeString (order, 'side'); - if (side === 'bid') { - side = 'buy'; - } else if (side === 'ask') { - side = 'sell'; - } - return { - 'id': this.safeString (order, 'id'), - 'datetime': this.iso8601 (timestamp), - 'timestamp': timestamp, - 'lastTradeTimestamp': undefined, - 'status': status, - 'symbol': symbol, - 'type': this.safeString (order, 'type'), // market, limit, stop, stop_limit, trailing_stop, fill_or_kill - 'side': side, - 'price': price, - 'cost': cost, - 'average': average, - 'amount': amount, - 'filled': filled, - 'remaining': remaining, - 'trades': undefined, - 'fee': undefined, - 'info': order, - }; - } - - async createOrder (symbol, type, side, amount, price = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - side = (side === 'sell') ? 'ask' : 'bid'; - const request = { - 'trading_pair_id': market['id'], - 'type': type, // market, limit, stop, stop_limit - 'side': side, - 'size': this.amountToPrecision (symbol, amount), - }; - if (type !== 'market') { - request['price'] = this.priceToPrecision (symbol, price); - } - const response = await this.privatePostTradingOrders (this.extend (request, params)); - const order = this.parseOrder (response['result']['order'], market); - const id = order['id']; - this.orders[id] = order; - return order; - } - - async editOrder (id, symbol, type, side, amount, price, params = {}) { - await this.loadMarkets (); - const request = { - 'order_id': id, - 'price': this.priceToPrecision (symbol, price), - 'size': this.amountToPrecision (symbol, amount), - }; - const response = await this.privatePutTradingOrdersOrderId (this.extend (request, params)); - return this.parseOrder (this.extend (response, { - 'id': id, - })); - } - - async cancelOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'order_id': id, - }; - const response = await this.privateDeleteTradingOrdersOrderId (this.extend (request, params)); - return this.parseOrder (this.extend (response, { - 'id': id, - })); - } - - async fetchOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'order_id': id.toString (), - }; - const response = await this.privateGetTradingOrdersOrderId (this.extend (request, params)); - return this.parseOrder (response['result']['order']); - } - - async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const result = await this.privateGetTradingOrders (params); - const orders = this.parseOrders (result['result']['orders'], undefined, since, limit); - if (symbol !== undefined) { - return this.filterBySymbolSinceLimit (orders, symbol, since, limit); - } - return this.filterBySinceLimit (orders, since, limit); - } - - async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const request = {}; - let market = undefined; - if (symbol !== undefined) { - market = this.market (symbol); - request['trading_pair_id'] = market['id']; - } - if (limit !== undefined) { - request['limit'] = limit; // default 50, max 100 - } - const response = await this.privateGetTradingOrderHistory (this.extend (request, params)); - const orders = this.parseOrders (response['result']['orders'], market, since, limit); - if (symbol !== undefined) { - return this.filterBySymbolSinceLimit (orders, symbol, since, limit); - } - return this.filterBySinceLimit (orders, since, limit); - } - - async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'order_id': id, - }; - const response = await this.privateGetTradingOrdersOrderIdTrades (this.extend (request, params)); - const market = (symbol === undefined) ? undefined : this.market (symbol); - return this.parseTrades (response['result']['trades'], market); - } - - async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const request = {}; - if (symbol !== undefined) { - request['trading_pair_id'] = market['id']; - } - const response = await this.privateGetTradingTrades (this.extend (request, params)); - return this.parseTrades (response['result']['trades'], market, since, limit); - } - - async createDepositAddress (code, params = {}) { - await this.loadMarkets (); - const currency = this.currency (code); - // 'ledger_type' is required, see: https://cobinhood.github.io/api-public/#create-new-deposit-address - const ledgerType = this.safeString (params, 'ledger_type', 'exchange'); - const request = { - 'currency': currency['id'], - 'ledger_type': ledgerType, - }; - const response = await this.privatePostWalletDepositAddresses (this.extend (request, params)); - const address = this.safeString (response['result']['deposit_address'], 'address'); - const tag = this.safeString (response['result']['deposit_address'], 'memo'); - this.checkAddress (address); - return { - 'currency': code, - 'address': address, - 'tag': tag, - 'info': response, - }; - } - - async fetchDepositAddress (code, params = {}) { - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'currency': currency['id'], - }; - const response = await this.privateGetWalletDepositAddresses (this.extend (request, params)); - // - // { success: true, - // result: { deposit_addresses: [ { address: "abcdefg", - // blockchain_id: "eosio", - // created_at: 1536768050235, - // currency: "EOS", - // memo: "12345678", - // type: "exchange" } ] } } - // - const addresses = this.safeValue (response['result'], 'deposit_addresses', []); - let address = undefined; - let tag = undefined; - if (addresses.length > 0) { - address = this.safeString (addresses[0], 'address'); - tag = this.safeString2 (addresses[0], 'memo', 'tag'); - } - this.checkAddress (address); - return { - 'currency': code, - 'address': address, - 'tag': tag, - 'info': response, - }; - } - - async withdraw (code, amount, address, tag = undefined, params = {}) { - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'currency': currency['id'], - 'amount': amount, - 'address': address, - }; - if (tag !== undefined) { - request['memo'] = tag; - } - const response = await this.privatePostWalletWithdrawals (this.extend (request, params)); - return { - 'id': undefined, - 'info': response, - }; - } - - async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - if (code === undefined) { - throw new ExchangeError (this.id + ' fetchDeposits() requires a currency code argument'); - } - const currency = this.currency (code); - const request = { - 'currency': currency['id'], - }; - const response = await this.privateGetWalletDeposits (this.extend (request, params)); - return this.parseTransactions (response['result']['deposits'], currency); - } - - async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - if (code === undefined) { - throw new ExchangeError (this.id + ' fetchWithdrawals() requires a currency code argument'); - } - const currency = this.currency (code); - const request = { - 'currency': currency['id'], - }; - const response = await this.privateGetWalletWithdrawals (this.extend (request, params)); - return this.parseTransactions (response['result']['withdrawals'], currency); - } - - parseTransactionStatus (status) { - const statuses = { - 'tx_pending_two_factor_auth': 'pending', - 'tx_pending_email_auth': 'pending', - 'tx_pending_approval': 'pending', - 'tx_approved': 'pending', - 'tx_processing': 'pending', - 'tx_pending': 'pending', - 'tx_sent': 'pending', - 'tx_cancelled': 'canceled', - 'tx_timeout': 'failed', - 'tx_invalid': 'failed', - 'tx_rejected': 'failed', - 'tx_confirmed': 'ok', - }; - return this.safeString (statuses, status, status); - } - - parseTransaction (transaction, currency = undefined) { - const timestamp = this.safeInteger (transaction, 'created_at'); - const currencyId = this.safeString (transaction, 'currency'); - const code = this.safeCurrencyCode (currencyId, currency); - let id = undefined; - const withdrawalId = this.safeString (transaction, 'withdrawal_id'); - const depositId = this.safeString (transaction, 'deposit_id'); - let type = undefined; - let address = undefined; - if (withdrawalId !== undefined) { - type = 'withdrawal'; - id = withdrawalId; - address = this.safeString (transaction, 'to_address'); - } else if (depositId !== undefined) { - type = 'deposit'; - id = depositId; - address = this.safeString (transaction, 'from_address'); - } - const additionalInfo = this.safeValue (transaction, 'additional_info', {}); - const tag = this.safeString (additionalInfo, 'memo'); - return { - 'info': transaction, - 'id': id, - 'txid': this.safeString (transaction, 'txhash'), - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'address': address, - 'tag': tag, // refix it properly - 'type': type, - 'amount': this.safeFloat (transaction, 'amount'), - 'currency': code, - 'status': this.parseTransactionStatus (transaction['status']), - 'updated': undefined, - 'fee': { - 'cost': this.safeFloat (transaction, 'fee'), - 'rate': undefined, - }, - }; - } - - sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = this.urls['api'] + '/' + this.version + '/' + this.implodeParams (path, params); - let query = this.omit (params, this.extractParams (path)); - headers = {}; - if (api === 'private') { - this.checkRequiredCredentials (); - // headers['device_id'] = this.apiKey; - headers['nonce'] = this.nonce ().toString (); - headers['Authorization'] = this.apiKey; - } - if (method === 'GET') { - query = this.urlencode (query); - if (query.length) { - url += '?' + query; - } - } else { - headers['Content-type'] = 'application/json; charset=UTF-8'; - body = this.json (query); - } - return { 'url': url, 'method': method, 'body': body, 'headers': headers }; - } - - handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { - if (code < 400 || code >= 600) { - return; - } - if (body[0] !== '{') { - throw new ExchangeError (this.id + ' ' + body); - } - const feedback = this.id + ' ' + this.json (response); - const errorCode = this.safeValue (response['error'], 'error_code'); - if (method === 'DELETE' || method === 'GET') { - if (errorCode === 'parameter_error') { - if (url.indexOf ('trading/orders/') >= 0) { - // Cobinhood returns vague "parameter_error" on fetchOrder() and cancelOrder() calls - // for invalid order IDs as well as orders that are not "open" - throw new InvalidOrder (feedback); - } - } - } - this.throwExactlyMatchedException (this.exceptions, errorCode, feedback); - throw new ExchangeError (feedback); - } - - nonce () { - return this.milliseconds (); - } -}; diff --git a/TaskServer/node_modules/ccxt/js/coinbaseprime.js b/TaskServer/node_modules/ccxt/js/coinbaseprime.js index 3cebe5a2c..647e94e11 100644 --- a/TaskServer/node_modules/ccxt/js/coinbaseprime.js +++ b/TaskServer/node_modules/ccxt/js/coinbaseprime.js @@ -11,6 +11,7 @@ module.exports = class coinbaseprime extends coinbasepro { return this.deepExtend (super.describe (), { 'id': 'coinbaseprime', 'name': 'Coinbase Prime', + 'pro': true, 'urls': { 'test': { 'public': 'https://api-public.sandbox.prime.coinbase.com', diff --git a/TaskServer/node_modules/ccxt/js/coinbasepro.js b/TaskServer/node_modules/ccxt/js/coinbasepro.js index 744c62e58..7c7db7483 100644 --- a/TaskServer/node_modules/ccxt/js/coinbasepro.js +++ b/TaskServer/node_modules/ccxt/js/coinbasepro.js @@ -15,6 +15,7 @@ module.exports = class coinbasepro extends Exchange { 'countries': [ 'US' ], 'rateLimit': 1000, 'userAgent': this.userAgents['chrome'], + 'pro': true, 'has': { 'cancelAllOrders': true, 'CORS': true, @@ -581,6 +582,7 @@ module.exports = class coinbasepro extends Exchange { const side = this.safeString (order, 'side'); return { 'id': id, + 'clientOrderId': undefined, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -595,6 +597,8 @@ module.exports = class coinbasepro extends Exchange { 'filled': filled, 'remaining': remaining, 'fee': fee, + 'average': undefined, + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/coincheck.js b/TaskServer/node_modules/ccxt/js/coincheck.js index 5b9bfdc8f..34f00e870 100644 --- a/TaskServer/node_modules/ccxt/js/coincheck.js +++ b/TaskServer/node_modules/ccxt/js/coincheck.js @@ -192,6 +192,7 @@ module.exports = class coincheck extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -206,6 +207,8 @@ module.exports = class coincheck extends Exchange { 'cost': cost, 'fee': undefined, 'info': order, + 'average': undefined, + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/coinegg.js b/TaskServer/node_modules/ccxt/js/coinegg.js index fd7a16cc9..6bb1fbbdb 100644 --- a/TaskServer/node_modules/ccxt/js/coinegg.js +++ b/TaskServer/node_modules/ccxt/js/coinegg.js @@ -352,6 +352,7 @@ module.exports = class coinegg extends Exchange { const id = this.safeString (order, 'id'); return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -367,6 +368,7 @@ module.exports = class coinegg extends Exchange { 'trades': undefined, 'fee': undefined, 'info': info, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/coinex.js b/TaskServer/node_modules/ccxt/js/coinex.js index 9d13942c6..410b3a864 100644 --- a/TaskServer/node_modules/ccxt/js/coinex.js +++ b/TaskServer/node_modules/ccxt/js/coinex.js @@ -464,6 +464,7 @@ module.exports = class coinex extends Exchange { const side = this.safeString (order, 'type'); return { 'id': this.safeString (order, 'id'), + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -724,7 +725,7 @@ module.exports = class coinex extends Exchange { const code = this.safeCurrencyCode (currencyId, currency); const timestamp = this.safeTimestamp (transaction, 'create_time'); const type = ('coin_withdraw_id' in transaction) ? 'withdraw' : 'deposit'; - const status = this.parseTransactionStatus (this.safeString (transaction, 'status'), type); + const status = this.parseTransactionStatus (this.safeString (transaction, 'status')); const amount = this.safeFloat (transaction, 'amount'); let feeCost = this.safeFloat (transaction, 'tx_fee'); if (type === 'deposit') { diff --git a/TaskServer/node_modules/ccxt/js/coinfalcon.js b/TaskServer/node_modules/ccxt/js/coinfalcon.js index c30b05e0a..79a0ab615 100644 --- a/TaskServer/node_modules/ccxt/js/coinfalcon.js +++ b/TaskServer/node_modules/ccxt/js/coinfalcon.js @@ -275,6 +275,23 @@ module.exports = class coinfalcon extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "id":"8bdd79f4-8414-40a2-90c3-e9f4d6d1eef4" + // "market":"IOT-BTC" + // "price":"0.0000003" + // "size":"4.0" + // "size_filled":"3.0" + // "fee":"0.0075" + // "fee_currency_code":"iot" + // "funds":"0.0" + // "status":"canceled" + // "order_type":"buy" + // "post_only":false + // "operation_type":"market_order" + // "created_at":"2018-01-12T21:14:06.747828Z" + // } + // if (market === undefined) { const marketId = this.safeString (order, 'market'); if (marketId in this.markets_by_id) { @@ -308,6 +325,7 @@ module.exports = class coinfalcon extends Exchange { const side = this.safeString (order, 'order_type'); return { 'id': this.safeString (order, 'id'), + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'status': status, @@ -322,6 +340,8 @@ module.exports = class coinfalcon extends Exchange { 'trades': undefined, 'fee': undefined, 'info': order, + 'lastTradeTimestamp': undefined, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/coinfloor.js b/TaskServer/node_modules/ccxt/js/coinfloor.js index e21e3fb57..6ea4f339a 100644 --- a/TaskServer/node_modules/ccxt/js/coinfloor.js +++ b/TaskServer/node_modules/ccxt/js/coinfloor.js @@ -59,7 +59,6 @@ module.exports = class coinfloor extends Exchange { 'markets': { 'BTC/GBP': { 'id': 'XBT/GBP', 'symbol': 'BTC/GBP', 'base': 'BTC', 'quote': 'GBP', 'baseId': 'XBT', 'quoteId': 'GBP', 'precision': { 'price': 0, 'amount': 4 }}, 'BTC/EUR': { 'id': 'XBT/EUR', 'symbol': 'BTC/EUR', 'base': 'BTC', 'quote': 'EUR', 'baseId': 'XBT', 'quoteId': 'EUR', 'precision': { 'price': 0, 'amount': 4 }}, - 'ETH/GBP': { 'id': 'ETH/GBP', 'symbol': 'ETH/GBP', 'base': 'ETH', 'quote': 'GBP', 'baseId': 'ETH', 'quoteId': 'GBP', 'precision': { 'price': 0, 'amount': 4 }}, }, 'exceptions': { 'exact': { @@ -446,6 +445,7 @@ module.exports = class coinfloor extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -459,6 +459,8 @@ module.exports = class coinfloor extends Exchange { 'remaining': undefined, 'cost': cost, 'fee': undefined, + 'average': undefined, + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/coinmarketcap.js b/TaskServer/node_modules/ccxt/js/coinmarketcap.js index 6e7f7b115..b9338c4c7 100644 --- a/TaskServer/node_modules/ccxt/js/coinmarketcap.js +++ b/TaskServer/node_modules/ccxt/js/coinmarketcap.js @@ -126,10 +126,13 @@ module.exports = class coinmarketcap extends Exchange { 'KingN Coin': 'KingN Coin', // conflict with KNC (Kyber Network) 'LiteBitcoin': 'LiteBitcoin', // conflict with LBTC (LightningBitcoin) 'Maggie': 'Maggie', + 'Monarch': 'Monarch', // conflict with MyToken (MT) 'MTC Mesh Network': 'MTC Mesh Network', // conflict with MTC Docademic doc.com Token https://github.com/ccxt/ccxt/issues/6081 https://github.com/ccxt/ccxt/issues/3025 'IOTA': 'IOTA', // a special case, most exchanges list it as IOTA, therefore we change just the Coinmarketcap instead of changing them all 'NetCoin': 'NetCoin', 'PCHAIN': 'PCHAIN', // conflict with PAI (Project Pai) + 'Plair': 'Plair', // conflict with PLA (PLANET) + 'PlayChip': 'PlayChip', // conflict with PLA (PLANET) 'Polcoin': 'Polcoin', 'PutinCoin': 'PutinCoin', // conflict with PUT (Profile Utility Token) 'Rcoin': 'Rcoin', // conflict with RCN (Ripio Credit Network) @@ -167,6 +170,9 @@ module.exports = class coinmarketcap extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'info': market, + 'active': undefined, + 'precision': this.precision, + 'limits': this.limits, }); } } diff --git a/TaskServer/node_modules/ccxt/js/coinmate.js b/TaskServer/node_modules/ccxt/js/coinmate.js index 3418dfb9d..0046f4303 100644 --- a/TaskServer/node_modules/ccxt/js/coinmate.js +++ b/TaskServer/node_modules/ccxt/js/coinmate.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError } = require ('./base/errors'); +const { ExchangeError, ArgumentsRequired, InvalidOrder, OrderNotFound, RateLimitExceeded, InsufficientFunds } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -16,8 +16,14 @@ module.exports = class coinmate extends Exchange { 'rateLimit': 1000, 'has': { 'CORS': true, + 'fetchBalance': true, + 'fetchOrders': true, + 'fetchOrder': true, 'fetchMyTrades': true, 'fetchTransactions': true, + 'fetchOpenOrders': true, + 'createOrder': true, + 'cancelOrder': true, }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/27811229-c1efb510-606c-11e7-9a36-84ba2ce412d8.jpg', @@ -66,6 +72,7 @@ module.exports = class coinmate extends Exchange { 'openOrders', 'order', 'orderHistory', + 'orderById', 'pusherAuth', 'redeemVoucher', 'replaceByBuyLimit', @@ -92,8 +99,74 @@ module.exports = class coinmate extends Exchange { }, 'fees': { 'trading': { - 'maker': 0.05 / 100, - 'taker': 0.15 / 100, + 'tierBased': true, + 'percentage': true, + 'maker': 0.12 / 100, + 'taker': 0.25 / 100, + 'tiers': { + 'taker': [ + [0, 0.25 / 100], + [10000, 0.23 / 100], + [100000, 0.21 / 100], + [250000, 0.20 / 100], + [500000, 0.15 / 100], + [1000000, 0.13 / 100], + [3000000, 0.10 / 100], + [15000000, 0.05 / 100], + ], + 'maker': [ + [0, 0.12 / 100], + [10000, 0.11 / 100], + [1000000, 0.10 / 100], + [250000, 0.08 / 100], + [500000, 0.05 / 100], + [1000000, 0.03 / 100], + [3000000, 0.02 / 100], + [15000000, 0], + ], + }, + }, + 'promotional': { + 'trading': { + 'maker': 0.05 / 100, + 'taker': 0.15 / 100, + 'tiers': { + 'taker': [ + [0, 0.15 / 100], + [10000, 0.14 / 100], + [100000, 0.13 / 100], + [250000, 0.12 / 100], + [500000, 0.11 / 100], + [1000000, 0.1 / 100], + [3000000, 0.08 / 100], + [15000000, 0.05 / 100], + ], + 'maker': [ + [0, 0.05 / 100], + [10000, 0.04 / 100], + [1000000, 0.03 / 100], + [250000, 0.02 / 100], + [500000, 0], + [1000000, 0], + [3000000, 0], + [15000000, 0], + ], + }, + }, + }, + }, + 'options': { + 'promotionalMarkets': ['ETH/EUR', 'ETH/CZK', 'ETH/BTC', 'XRP/EUR', 'XRP/CZK', 'XRP/BTC', 'DASH/EUR', 'DASH/CZK', 'DASH/BTC', 'BCH/EUR', 'BCH/CZK', 'BCH/BTC'], + }, + 'exceptions': { + 'exact': { + 'No order with given ID': OrderNotFound, + }, + 'broad': { + 'Not enough account balance available': InsufficientFunds, + 'Incorrect order ID': InvalidOrder, + 'Minimum Order Size ': InvalidOrder, + 'TOO MANY REQUESTS': RateLimitExceeded, }, }, }); @@ -130,6 +203,12 @@ module.exports = class coinmate extends Exchange { const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const symbol = base + '/' + quote; + const promotionalMarkets = this.safeValue (this.options, 'promotionalMarkets', []); + let fees = this.safeValue (this.fees, 'trading'); + if (this.inArray (symbol, promotionalMarkets)) { + const promotionalFees = this.safeValue (this.fees, 'promotional', {}); + fees = this.safeValue (promotionalFees, 'trading', fees); + } result.push ({ 'id': id, 'symbol': symbol, @@ -138,6 +217,8 @@ module.exports = class coinmate extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'active': undefined, + 'maker': fees['maker'], + 'taker': fees['taker'], 'info': market, 'precision': { 'price': this.safeInteger (market, 'priceDecimals'), @@ -326,6 +407,10 @@ module.exports = class coinmate extends Exchange { const request = { 'limit': limit, }; + if (symbol !== undefined) { + const market = this.market (symbol); + request['currencyPair'] = market['id']; + } if (since !== undefined) { request['timestampFrom'] = since; } @@ -449,6 +534,144 @@ module.exports = class coinmate extends Exchange { return this.parseTrades (data, market, since, limit); } + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + const response = await this.privatePostOpenOrders (this.extend ({}, params)); + const extension = { 'status': 'open' }; + return this.parseOrders (response['data'], undefined, since, limit, extension); + } + + async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOrders requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'currencyPair': market['id'], + }; + // offset param that appears in other parts of the API doesn't appear to be supported here + if (limit !== undefined) { + request['limit'] = limit; + } + const response = await this.privatePostOrderHistory (this.extend (request, params)); + return this.parseOrders (response['data'], market, since, limit); + } + + parseOrderStatus (status) { + const statuses = { + 'FILLED': 'closed', + 'CANCELLED': 'canceled', + 'OPEN': 'open', + }; + return this.safeString (statuses, status, status); + } + + parseOrderType (type) { + const types = { + 'LIMIT': 'limit', + 'MARKET': 'market', + }; + return this.safeString (types, type, type); + } + + parseOrder (order, market = undefined) { + // + // limit sell + // + // { + // id: 781246605, + // timestamp: 1584480015133, + // trailingUpdatedTimestamp: null, + // type: 'SELL', + // currencyPair: 'ETH_BTC', + // price: 0.0345, + // amount: 0.01, + // stopPrice: null, + // originalStopPrice: null, + // marketPriceAtLastUpdate: null, + // marketPriceAtOrderCreation: null, + // orderTradeType: 'LIMIT', + // hidden: false, + // trailing: false, + // clientOrderId: null + // } + // + // limit buy + // + // { + // id: 67527001, + // timestamp: 1517931722613, + // trailingUpdatedTimestamp: null, + // type: 'BUY', + // price: 5897.24, + // remainingAmount: 0.002367, + // originalAmount: 0.1, + // stopPrice: null, + // originalStopPrice: null, + // marketPriceAtLastUpdate: null, + // marketPriceAtOrderCreation: null, + // status: 'CANCELLED', + // orderTradeType: 'LIMIT', + // hidden: false, + // avgPrice: null, + // trailing: false, + // } + // + const id = this.safeString (order, 'id'); + const timestamp = this.safeInteger (order, 'timestamp'); + const side = this.safeStringLower (order, 'type'); + const price = this.safeFloat (order, 'price'); + const amount = this.safeFloat2 (order, 'originalAmount', 'amount'); + const remaining = this.safeFloat (order, 'remainingAmount', amount); + const status = this.parseOrderStatus (this.safeString (order, 'status')); + const type = this.parseOrderType (this.safeString (order, 'orderTradeType')); + let filled = undefined; + let cost = undefined; + if ((amount !== undefined) && (remaining !== undefined)) { + filled = amount - remaining; + if (price !== undefined) { + cost = filled * price; + } + } + const average = this.safeFloat (order, 'avgPrice'); + let symbol = undefined; + const marketId = this.safeString (order, 'currencyPair'); + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + } else { + const [ baseId, quoteId ] = marketId.split ('_'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const clientOrderId = this.safeString (order, 'clientOrderId'); + return { + 'id': id, + 'clientOrderId': clientOrderId, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': undefined, + 'symbol': symbol, + 'type': type, + 'side': side, + 'price': price, + 'amount': amount, + 'cost': cost, + 'average': average, + 'filled': filled, + 'remaining': remaining, + 'status': status, + 'trades': undefined, + 'info': order, + 'fee': undefined, + }; + } + async createOrder (symbol, type, side, amount, price = undefined, params = {}) { await this.loadMarkets (); let method = 'privatePost' + this.capitalize (side); @@ -457,25 +680,45 @@ module.exports = class coinmate extends Exchange { }; if (type === 'market') { if (side === 'buy') { - request['total'] = amount; // amount in fiat + request['total'] = this.amountToPrecision (symbol, amount); // amount in fiat } else { - request['amount'] = amount; // amount in fiat + request['amount'] = this.amountToPrecision (symbol, amount); // amount in fiat } method += 'Instant'; } else { - request['amount'] = amount; // amount in crypto - request['price'] = price; + request['amount'] = this.amountToPrecision (symbol, amount); // amount in crypto + request['price'] = this.priceToPrecision (symbol, price); method += this.capitalize (type); } const response = await this[method] (this.extend (request, params)); + const id = this.safeString (response, 'data'); return { 'info': response, - 'id': response['data'].toString (), + 'id': id, }; } + async fetchOrder (id, symbol = undefined, params = {}) { + await this.loadMarkets (); + const request = { + 'orderId': id, + }; + let market = undefined; + if (symbol) { + market = this.market (symbol); + } + const response = await this.privatePostOrderById (this.extend (request, params)); + const data = this.safeValue (response, 'data'); + return this.parseOrder (data, market); + } + async cancelOrder (id, symbol = undefined, params = {}) { - return await this.privatePostCancelOrder ({ 'orderId': id }); + // {"error":false,"errorMessage":null,"data":{"success":true,"remainingAmount":0.01}} + const request = { 'orderId': id }; + const response = await this.privatePostCancelOrderWithInfo (this.extend (request, params)); + return { + 'info': response, + }; } nonce () { @@ -506,13 +749,27 @@ module.exports = class coinmate extends Exchange { return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } - async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - const response = await this.fetch2 (path, api, method, params, headers, body); - if ('error' in response) { - if (response['error']) { - throw new ExchangeError (this.id + ' ' + this.json (response)); + handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (response !== undefined) { + if ('error' in response) { + // {"error":true,"errorMessage":"Minimum Order Size 0.01 ETH","data":null} + if (response['error']) { + const message = this.safeString (response, 'errorMessage'); + const feedback = this.id + ' ' + message; + this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback); + this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback); + throw new ExchangeError (this.id + ' ' + this.json (response)); + } } } - return response; + if (code > 400) { + if (body) { + const feedback = this.id + ' ' + body; + this.throwExactlyMatchedException (this.exceptions['exact'], body, feedback); + this.throwBroadlyMatchedException (this.exceptions['broad'], body, feedback); + throw new ExchangeError (feedback); // unknown message + } + throw new ExchangeError (this.id + ' ' + body); + } } }; diff --git a/TaskServer/node_modules/ccxt/js/coinone.js b/TaskServer/node_modules/ccxt/js/coinone.js index 56bb65ce9..4577aa6b0 100644 --- a/TaskServer/node_modules/ccxt/js/coinone.js +++ b/TaskServer/node_modules/ccxt/js/coinone.js @@ -305,6 +305,8 @@ module.exports = class coinone extends Exchange { 'remaining': amount, 'status': 'open', 'fee': undefined, + 'clientOrderId': undefined, + 'trades': undefined, }; this.orders[id] = order; return order; @@ -356,6 +358,17 @@ module.exports = class coinone extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "index": "0", + // "orderId": "68665943-1eb5-4e4b-9d76-845fc54f5489", + // "timestamp": "1449037367", + // "price": "444000.0", + // "qty": "0.3456", + // "type": "ask", + // "feeRate": "-0.0015" + // } + // const info = this.safeValue (order, 'info'); const id = this.safeStringUpper (info, 'orderId'); const timestamp = this.safeTimestamp (info, 'timestamp'); @@ -398,6 +411,7 @@ module.exports = class coinone extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -411,6 +425,8 @@ module.exports = class coinone extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'average': undefined, + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/coss.js b/TaskServer/node_modules/ccxt/js/coss.js index 1524d0d1f..35fe5767e 100644 --- a/TaskServer/node_modules/ccxt/js/coss.js +++ b/TaskServer/node_modules/ccxt/js/coss.js @@ -833,6 +833,7 @@ module.exports = class coss extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, diff --git a/TaskServer/node_modules/ccxt/js/crex24.js b/TaskServer/node_modules/ccxt/js/crex24.js index 93f89a92a..cb448a0ff 100644 --- a/TaskServer/node_modules/ccxt/js/crex24.js +++ b/TaskServer/node_modules/ccxt/js/crex24.js @@ -120,6 +120,7 @@ module.exports = class crex24 extends Exchange { }, 'commonCurrencies': { 'YOYO': 'YOYOW', + 'BULL': 'BuySell', 'BCC': 'BCH', }, // exchange-specific options @@ -705,6 +706,7 @@ module.exports = class crex24 extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, diff --git a/TaskServer/node_modules/ccxt/js/deribit.js b/TaskServer/node_modules/ccxt/js/deribit.js index 9027c5bf1..04f0380a8 100644 --- a/TaskServer/node_modules/ccxt/js/deribit.js +++ b/TaskServer/node_modules/ccxt/js/deribit.js @@ -4,7 +4,7 @@ const Exchange = require ('./base/Exchange'); const { TICK_SIZE } = require ('./base/functions/number'); -const { AuthenticationError, ExchangeError, ArgumentsRequired, PermissionDenied, InvalidOrder, OrderNotFound, DDoSProtection, NotSupported, ExchangeNotAvailable, InsufficientFunds } = require ('./base/errors'); +const { AuthenticationError, ExchangeError, ArgumentsRequired, PermissionDenied, InvalidOrder, OrderNotFound, DDoSProtection, NotSupported, ExchangeNotAvailable, InsufficientFunds, BadRequest, InvalidAddress, OnMaintenance } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -14,18 +14,46 @@ module.exports = class deribit extends Exchange { 'id': 'deribit', 'name': 'Deribit', 'countries': [ 'NL' ], // Netherlands - 'version': 'v1', + 'version': 'v2', 'userAgent': undefined, - 'rateLimit': 2000, + 'rateLimit': 500, 'has': { 'CORS': true, 'editOrder': true, + 'fetchBalance': true, 'fetchOrder': true, 'fetchOrders': false, 'fetchOpenOrders': true, 'fetchClosedOrders': true, 'fetchMyTrades': true, - 'fetchTickers': false, + 'fetchTickers': true, + 'fetchOHLCV': true, + 'fetchDepositAddress': true, + 'createDepositAddress': true, + 'fetchOrderTrades': true, + 'createOrder': true, + 'cancelOrder': true, + 'cancelAllOrders': true, + 'withdraw': true, + 'fetchTime': true, + 'fetchStatus': true, + 'fetchDeposits': true, + 'fetchWithdrawals': true, + 'fetchTransactions': false, + }, + 'timeframes': { + '1m': '1', + '3m': '3', + '5m': '5', + '10m': '10', + '15m': '15', + '30m': '30', + '1h': '60', + '2h': '120', + '3h': '180', + '6h': '360', + '12h': '720', + '1d': '1D', }, 'urls': { 'test': 'https://test.deribit.com', @@ -33,7 +61,7 @@ module.exports = class deribit extends Exchange { 'api': 'https://www.deribit.com', 'www': 'https://www.deribit.com', 'doc': [ - 'https://docs.deribit.com', + 'https://docs.deribit.com/v2', 'https://github.com/deribit', ], 'fees': 'https://www.deribit.com/pages/information/fees', @@ -42,193 +70,461 @@ module.exports = class deribit extends Exchange { 'api': { 'public': { 'get': [ - 'ping', + // Authentication + 'auth', + 'exchange_token', + 'fork_token', + // Session management + 'set_heartbeat', + 'disable_heartbeat', + // Supporting + 'get_time', + 'hello', 'test', - 'getinstruments', - 'index', - 'getcurrencies', - 'getorderbook', - 'getlasttrades', - 'getsummary', - 'stats', - 'getannouncments', + // Subscription management + 'subscribe', + 'unsubscribe', + // Account management + 'get_announcements', + // Market data + 'get_book_summary_by_currency', + 'get_book_summary_by_instrument', + 'get_contract_size', + 'get_currencies', + 'get_funding_chart_data', + 'get_funding_rate_history', + 'get_funding_rate_value', + 'get_historical_volatility', + 'get_index', + 'get_instruments', + 'get_last_settlements_by_currency', + 'get_last_settlements_by_instrument', + 'get_last_trades_by_currency', + 'get_last_trades_by_currency_and_time', + 'get_last_trades_by_instrument', + 'get_last_trades_by_instrument_and_time', + 'get_order_book', + 'get_trade_volumes', + 'get_tradingview_chart_data', + 'ticker', ], }, 'private': { 'get': [ - 'account', - 'getopenorders', - 'positions', - 'orderhistory', - 'orderstate', - 'tradehistory', - 'newannouncements', - ], - 'post': [ + // Authentication + 'logout', + // Session management + 'enable_cancel_on_disconnect', + 'disable_cancel_on_disconnect', + 'get_cancel_on_disconnect', + // Subscription management + 'subscribe', + 'unsubscribe', + // Account management + 'change_api_key_name', + 'change_scope_in_api_key', + 'change_subaccount_name', + 'create_api_key', + 'create_subaccount', + 'disable_api_key', + 'disable_tfa_for_subaccount', + 'enable_api_key', + 'get_account_summary', + 'get_email_language', + 'get_new_announcements', + 'get_position', + 'get_positions', + 'get_subaccounts', + 'list_api_keys', + 'remove_api_key', + 'reset_api_key', + 'set_announcement_as_read', + 'set_api_key_as_default', + 'set_email_for_subaccount', + 'set_email_language', + 'set_password_for_subaccount', + 'toggle_notifications_from_subaccount', + 'toggle_subaccount_login', + // Block Trade + 'execute_block_trade', + 'get_block_trade', + 'get_last_block_trades_by_currency', + 'invalidate_block_trade_signature', + 'verify_block_trade', + // Trading 'buy', 'sell', 'edit', 'cancel', - 'cancelall', + 'cancel_all', + 'cancel_all_by_currency', + 'cancel_all_by_instrument', + 'cancel_by_label', + 'close_position', + 'get_margins', + 'get_open_orders_by_currency', + 'get_open_orders_by_instrument', + 'get_order_history_by_currency', + 'get_order_history_by_instrument', + 'get_order_margin_by_ids', + 'get_order_state', + 'get_stop_order_history', + 'get_user_trades_by_currency', + 'get_user_trades_by_currency_and_time', + 'get_user_trades_by_instrument', + 'get_user_trades_by_instrument_and_time', + 'get_user_trades_by_order', + 'get_settlement_history_by_instrument', + 'get_settlement_history_by_currency', + // Wallet + 'cancel_transfer_by_id', + 'cancel_withdrawal', + 'create_deposit_address', + 'get_current_deposit_address', + 'get_deposits', + 'get_transfers', + 'get_withdrawals', + 'submit_transfer_to_subaccount', + 'submit_transfer_to_user', + 'withdraw', ], }, }, 'exceptions': { - // 0 or absent Success, No error - '9999': PermissionDenied, // "api_not_enabled" User didn't enable API for the Account - '10000': AuthenticationError, // "authorization_required" Authorization issue, invalid or absent signature etc - '10001': ExchangeError, // "error" Some general failure, no public information available - '10002': InvalidOrder, // "qty_too_low" Order quantity is too low - '10003': InvalidOrder, // "order_overlap" Rejection, order overlap is found and self-trading is not enabled - '10004': OrderNotFound, // "order_not_found" Attempt to operate with order that can't be found by specified id - '10005': InvalidOrder, // "price_too_low " Price is too low, defines current limit for the operation - '10006': InvalidOrder, // "price_too_low4idx " Price is too low for current index, defines current bottom limit for the operation - '10007': InvalidOrder, // "price_too_high " Price is too high, defines current up limit for the operation - '10008': InvalidOrder, // "price_too_high4idx " Price is too high for current index, defines current up limit for the operation - '10009': InsufficientFunds, // "not_enough_funds" Account has not enough funds for the operation - '10010': OrderNotFound, // "already_closed" Attempt of doing something with closed order - '10011': InvalidOrder, // "price_not_allowed" This price is not allowed for some reason - '10012': InvalidOrder, // "book_closed" Operation for instrument which order book had been closed - '10013': PermissionDenied, // "pme_max_total_open_orders " Total limit of open orders has been exceeded, it is applicable for PME users - '10014': PermissionDenied, // "pme_max_future_open_orders " Limit of count of futures' open orders has been exceeded, it is applicable for PME users - '10015': PermissionDenied, // "pme_max_option_open_orders " Limit of count of options' open orders has been exceeded, it is applicable for PME users - '10016': PermissionDenied, // "pme_max_future_open_orders_size " Limit of size for futures has been exceeded, it is applicable for PME users - '10017': PermissionDenied, // "pme_max_option_open_orders_size " Limit of size for options has been exceeded, it is applicable for PME users - '10019': PermissionDenied, // "locked_by_admin" Trading is temporary locked by admin - '10020': ExchangeError, // "invalid_or_unsupported_instrument" Instrument name is not valid - '10022': InvalidOrder, // "invalid_quantity" quantity was not recognized as a valid number - '10023': InvalidOrder, // "invalid_price" price was not recognized as a valid number - '10024': InvalidOrder, // "invalid_max_show" max_show parameter was not recognized as a valid number - '10025': InvalidOrder, // "invalid_order_id" Order id is missing or its format was not recognized as valid - '10026': InvalidOrder, // "price_precision_exceeded" Extra precision of the price is not supported - '10027': InvalidOrder, // "non_integer_contract_amount" Futures contract amount was not recognized as integer - '10028': DDoSProtection, // "too_many_requests" Allowed request rate has been exceeded - '10029': OrderNotFound, // "not_owner_of_order" Attempt to operate with not own order - '10030': ExchangeError, // "must_be_websocket_request" REST request where Websocket is expected - '10031': ExchangeError, // "invalid_args_for_instrument" Some of arguments are not recognized as valid - '10032': InvalidOrder, // "whole_cost_too_low" Total cost is too low - '10033': NotSupported, // "not_implemented" Method is not implemented yet - '10034': InvalidOrder, // "stop_price_too_high" Stop price is too high - '10035': InvalidOrder, // "stop_price_too_low" Stop price is too low - '11035': InvalidOrder, // "no_more_stops " Allowed amount of stop orders has been exceeded - '11036': InvalidOrder, // "invalid_stoppx_for_index_or_last" Invalid StopPx (too high or too low) as to current index or market - '11037': InvalidOrder, // "outdated_instrument_for_IV_order" Instrument already not available for trading - '11038': InvalidOrder, // "no_adv_for_futures" Advanced orders are not available for futures - '11039': InvalidOrder, // "no_adv_postonly" Advanced post-only orders are not supported yet - '11040': InvalidOrder, // "impv_not_in_range 0..499%" Implied volatility is out of allowed range - '11041': InvalidOrder, // "not_adv_order" Advanced order properties can't be set if the order is not advanced - '11042': PermissionDenied, // "permission_denied" Permission for the operation has been denied - '11044': OrderNotFound, // "not_open_order" Attempt to do open order operations with the not open order - '11045': ExchangeError, // "invalid_event" Event name has not been recognized - '11046': ExchangeError, // "outdated_instrument" At several minutes to instrument expiration, corresponding advanced implied volatility orders are not allowed - '11047': ExchangeError, // "unsupported_arg_combination" The specified combination of arguments is not supported - '11048': ExchangeError, // "not_on_this_server" The requested operation is not available on this server. - '11050': ExchangeError, // "invalid_request" Request has not been parsed properly - '11051': ExchangeNotAvailable, // "system_maintenance" System is under maintenance - '11030': ExchangeError, // "other_reject " Some rejects which are not considered as very often, more info may be specified in - '11031': ExchangeError, // "other_error " Some errors which are not considered as very often, more info may be specified in + // 0 or absent Success, No error. + '9999': PermissionDenied, // 'api_not_enabled' User didn't enable API for the Account. + '10000': AuthenticationError, // 'authorization_required' Authorization issue, invalid or absent signature etc. + '10001': ExchangeError, // 'error' Some general failure, no public information available. + '10002': InvalidOrder, // 'qty_too_low' Order quantity is too low. + '10003': InvalidOrder, // 'order_overlap' Rejection, order overlap is found and self-trading is not enabled. + '10004': OrderNotFound, // 'order_not_found' Attempt to operate with order that can't be found by specified id. + '10005': InvalidOrder, // 'price_too_low ' Price is too low, defines current limit for the operation. + '10006': InvalidOrder, // 'price_too_low4idx ' Price is too low for current index, defines current bottom limit for the operation. + '10007': InvalidOrder, // 'price_too_high ' Price is too high, defines current up limit for the operation. + '10008': InvalidOrder, // 'price_too_high4idx ' Price is too high for current index, defines current up limit for the operation. + '10009': InsufficientFunds, // 'not_enough_funds' Account has not enough funds for the operation. + '10010': OrderNotFound, // 'already_closed' Attempt of doing something with closed order. + '10011': InvalidOrder, // 'price_not_allowed' This price is not allowed for some reason. + '10012': InvalidOrder, // 'book_closed' Operation for instrument which order book had been closed. + '10013': PermissionDenied, // 'pme_max_total_open_orders ' Total limit of open orders has been exceeded, it is applicable for PME users. + '10014': PermissionDenied, // 'pme_max_future_open_orders ' Limit of count of futures' open orders has been exceeded, it is applicable for PME users. + '10015': PermissionDenied, // 'pme_max_option_open_orders ' Limit of count of options' open orders has been exceeded, it is applicable for PME users. + '10016': PermissionDenied, // 'pme_max_future_open_orders_size ' Limit of size for futures has been exceeded, it is applicable for PME users. + '10017': PermissionDenied, // 'pme_max_option_open_orders_size ' Limit of size for options has been exceeded, it is applicable for PME users. + '10018': PermissionDenied, // 'non_pme_max_future_position_size ' Limit of size for futures has been exceeded, it is applicable for non-PME users. + '10019': PermissionDenied, // 'locked_by_admin' Trading is temporary locked by admin. + '10020': ExchangeError, // 'invalid_or_unsupported_instrument' Instrument name is not valid. + '10021': InvalidOrder, // 'invalid_amount' Amount is not valid. + '10022': InvalidOrder, // 'invalid_quantity' quantity was not recognized as a valid number (for API v1). + '10023': InvalidOrder, // 'invalid_price' price was not recognized as a valid number. + '10024': InvalidOrder, // 'invalid_max_show' max_show parameter was not recognized as a valid number. + '10025': InvalidOrder, // 'invalid_order_id' Order id is missing or its format was not recognized as valid. + '10026': InvalidOrder, // 'price_precision_exceeded' Extra precision of the price is not supported. + '10027': InvalidOrder, // 'non_integer_contract_amount' Futures contract amount was not recognized as integer. + '10028': DDoSProtection, // 'too_many_requests' Allowed request rate has been exceeded. + '10029': OrderNotFound, // 'not_owner_of_order' Attempt to operate with not own order. + '10030': ExchangeError, // 'must_be_websocket_request' REST request where Websocket is expected. + '10031': ExchangeError, // 'invalid_args_for_instrument' Some of arguments are not recognized as valid. + '10032': InvalidOrder, // 'whole_cost_too_low' Total cost is too low. + '10033': NotSupported, // 'not_implemented' Method is not implemented yet. + '10034': InvalidOrder, // 'stop_price_too_high' Stop price is too high. + '10035': InvalidOrder, // 'stop_price_too_low' Stop price is too low. + '10036': InvalidOrder, // 'invalid_max_show_amount' Max Show Amount is not valid. + '10040': ExchangeNotAvailable, // 'retry' Request can't be processed right now and should be retried. + '10041': OnMaintenance, // 'settlement_in_progress' Settlement is in progress. Every day at settlement time for several seconds, the system calculates user profits and updates balances. That time trading is paused for several seconds till the calculation is completed. + '10043': InvalidOrder, // 'price_wrong_tick' Price has to be rounded to a certain tick size. + '10044': InvalidOrder, // 'stop_price_wrong_tick' Stop Price has to be rounded to a certain tick size. + '10045': InvalidOrder, // 'can_not_cancel_liquidation_order' Liquidation order can't be canceled. + '10046': InvalidOrder, // 'can_not_edit_liquidation_order' Liquidation order can't be edited. + '10047': DDoSProtection, // 'matching_engine_queue_full' Reached limit of pending Matching Engine requests for user. + '10048': ExchangeError, // 'not_on_this_server' The requested operation is not available on this server. + '11008': InvalidOrder, // 'already_filled' This request is not allowed in regards to the filled order. + '11029': BadRequest, // 'invalid_arguments' Some invalid input has been detected. + '11030': ExchangeError, // 'other_reject ' Some rejects which are not considered as very often, more info may be specified in . + '11031': ExchangeError, // 'other_error ' Some errors which are not considered as very often, more info may be specified in . + '11035': DDoSProtection, // 'no_more_stops ' Allowed amount of stop orders has been exceeded. + '11036': InvalidOrder, // 'invalid_stoppx_for_index_or_last' Invalid StopPx (too high or too low) as to current index or market. + '11037': BadRequest, // 'outdated_instrument_for_IV_order' Instrument already not available for trading. + '11038': InvalidOrder, // 'no_adv_for_futures' Advanced orders are not available for futures. + '11039': InvalidOrder, // 'no_adv_postonly' Advanced post-only orders are not supported yet. + '11041': InvalidOrder, // 'not_adv_order' Advanced order properties can't be set if the order is not advanced. + '11042': PermissionDenied, // 'permission_denied' Permission for the operation has been denied. + '11043': BadRequest, // 'bad_argument' Bad argument has been passed. + '11044': InvalidOrder, // 'not_open_order' Attempt to do open order operations with the not open order. + '11045': BadRequest, // 'invalid_event' Event name has not been recognized. + '11046': BadRequest, // 'outdated_instrument' At several minutes to instrument expiration, corresponding advanced implied volatility orders are not allowed. + '11047': BadRequest, // 'unsupported_arg_combination' The specified combination of arguments is not supported. + '11048': ExchangeError, // 'wrong_max_show_for_option' Wrong Max Show for options. + '11049': BadRequest, // 'bad_arguments' Several bad arguments have been passed. + '11050': BadRequest, // 'bad_request' Request has not been parsed properly. + '11051': OnMaintenance, // 'system_maintenance' System is under maintenance. + '11052': ExchangeError, // 'subscribe_error_unsubscribed' Subscription error. However, subscription may fail without this error, please check list of subscribed channels returned, as some channels can be not subscribed due to wrong input or lack of permissions. + '11053': ExchangeError, // 'transfer_not_found' Specified transfer is not found. + '11090': InvalidAddress, // 'invalid_addr' Invalid address. + '11091': InvalidAddress, // 'invalid_transfer_address' Invalid addres for the transfer. + '11092': InvalidAddress, // 'address_already_exist' The address already exists. + '11093': DDoSProtection, // 'max_addr_count_exceeded' Limit of allowed addresses has been reached. + '11094': ExchangeError, // 'internal_server_error' Some unhandled error on server. Please report to admin. The details of the request will help to locate the problem. + '11095': ExchangeError, // 'disabled_deposit_address_creation' Deposit address creation has been disabled by admin. + '11096': ExchangeError, // 'address_belongs_to_user' Withdrawal instead of transfer. + '12000': AuthenticationError, // 'bad_tfa' Wrong TFA code + '12001': DDoSProtection, // 'too_many_subaccounts' Limit of subbacounts is reached. + '12002': ExchangeError, // 'wrong_subaccount_name' The input is not allowed as name of subaccount. + '12998': AuthenticationError, // 'tfa_over_limit' The number of failed TFA attempts is limited. + '12003': AuthenticationError, // 'login_over_limit' The number of failed login attempts is limited. + '12004': AuthenticationError, // 'registration_over_limit' The number of registration requests is limited. + '12005': AuthenticationError, // 'country_is_banned' The country is banned (possibly via IP check). + '12100': ExchangeError, // 'transfer_not_allowed' Transfer is not allowed. Possible wrong direction or other mistake. + '12999': AuthenticationError, // 'tfa_used' TFA code is correct but it is already used. Please, use next code. + '13000': AuthenticationError, // 'invalid_login' Login name is invalid (not allowed or it contains wrong characters). + '13001': AuthenticationError, // 'account_not_activated' Account must be activated. + '13002': PermissionDenied, // 'account_blocked' Account is blocked by admin. + '13003': AuthenticationError, // 'tfa_required' This action requires TFA authentication. + '13004': AuthenticationError, // 'invalid_credentials' Invalid credentials has been used. + '13005': AuthenticationError, // 'pwd_match_error' Password confirmation error. + '13006': AuthenticationError, // 'security_error' Invalid Security Code. + '13007': AuthenticationError, // 'user_not_found' User's security code has been changed or wrong. + '13008': ExchangeError, // 'request_failed' Request failed because of invalid input or internal failure. + '13009': AuthenticationError, // 'unauthorized' Wrong or expired authorization token or bad signature. For example, please check scope of the token, 'connection' scope can't be reused for other connections. + '13010': BadRequest, // 'value_required' Invalid input, missing value. + '13011': BadRequest, // 'value_too_short' Input is too short. + '13012': PermissionDenied, // 'unavailable_in_subaccount' Subaccount restrictions. + '13013': BadRequest, // 'invalid_phone_number' Unsupported or invalid phone number. + '13014': BadRequest, // 'cannot_send_sms' SMS sending failed -- phone number is wrong. + '13015': BadRequest, // 'invalid_sms_code' Invalid SMS code. + '13016': BadRequest, // 'invalid_input' Invalid input. + '13017': ExchangeError, // 'subscription_failed' Subscription hailed, invalid subscription parameters. + '13018': ExchangeError, // 'invalid_content_type' Invalid content type of the request. + '13019': ExchangeError, // 'orderbook_closed' Closed, expired order book. + '13020': ExchangeError, // 'not_found' Instrument is not found, invalid instrument name. + '13021': PermissionDenied, // 'forbidden' Not enough permissions to execute the request, forbidden. + '13025': ExchangeError, // 'method_switched_off_by_admin' API method temporarily switched off by administrator. + '-32602': BadRequest, // 'Invalid params' see JSON-RPC spec. + '-32601': BadRequest, // 'Method not found' see JSON-RPC spec. + '-32700': BadRequest, // 'Parse error' see JSON-RPC spec. + '-32000': BadRequest, // 'Missing params' see JSON-RPC spec. }, 'precisionMode': TICK_SIZE, 'options': { - 'fetchTickerQuotes': true, + 'code': 'BTC', + 'fetchBalance': { + 'code': 'BTC', + }, }, }); } + async fetchTime (params = {}) { + const response = await this.publicGetGetTime (params); + // + // { + // jsonrpc: '2.0', + // result: 1583922446019, + // usIn: 1583922446019955, + // usOut: 1583922446019956, + // usDiff: 1, + // testnet: false + // } + // + return this.safeInteger (response, 'result'); + } + + codeFromOptions (methodName) { + const defaultCode = this.safeValue (this.options, 'code', 'BTC'); + const options = this.safeValue (this.options, methodName, {}); + return this.safeValue (options, 'code', defaultCode); + } + + async fetchStatus (params = {}) { + const request = { + // 'expected_result': false, // true will trigger an error for testing purposes + }; + await this.publicGetTest (this.extend (request, params)); + // + // { + // jsonrpc: '2.0', + // result: { version: '1.2.26' }, + // usIn: 1583922623964485, + // usOut: 1583922623964487, + // usDiff: 2, + // testnet: false + // } + // + this.status = this.extend (this.status, { + 'status': 'ok', + 'updated': this.milliseconds (), + }); + return this.status; + } + async fetchMarkets (params = {}) { - const response = await this.publicGetGetinstruments (params); - const markets = this.safeValue (response, 'result'); + const currenciesResponse = await this.publicGetGetCurrencies (params); + // + // { + // jsonrpc: '2.0', + // result: [ + // { + // withdrawal_priorities: [ + // { value: 0.15, name: 'very_low' }, + // { value: 1.5, name: 'very_high' }, + // ], + // withdrawal_fee: 0.0005, + // min_withdrawal_fee: 0.0005, + // min_confirmations: 1, + // fee_precision: 4, + // currency_long: 'Bitcoin', + // currency: 'BTC', + // coin_type: 'BITCOIN' + // } + // ], + // usIn: 1583761588590479, + // usOut: 1583761588590544, + // usDiff: 65, + // testnet: false + // } + // + const currenciesResult = this.safeValue (currenciesResponse, 'result', []); const result = []; - for (let i = 0; i < markets.length; i++) { - const market = markets[i]; - const id = this.safeString (market, 'instrumentName'); - const baseId = this.safeString (market, 'baseCurrency'); - const quoteId = this.safeString (market, 'currency'); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - const type = this.safeString (market, 'kind'); - const future = (type === 'future'); - const option = (type === 'option'); - const active = this.safeValue (market, 'isActive'); - const precision = { - 'amount': this.safeFloat (market, 'minTradeAmount'), - 'price': this.safeFloat (market, 'tickSize'), + for (let i = 0; i < currenciesResult.length; i++) { + const currencyId = this.safeString (currenciesResult[i], 'currency'); + const request = { + 'currency': currencyId, }; - result.push ({ - 'id': id, - 'symbol': id, - 'base': base, - 'quote': quote, - 'active': active, - 'precision': precision, - 'limits': { - 'amount': { - 'min': this.safeFloat (market, 'minTradeAmount'), - 'max': undefined, + const instrumentsResponse = await this.publicGetGetInstruments (this.extend (request, params)); + // + // { + // jsonrpc: '2.0', + // result: [ + // { + // tick_size: 0.0005, + // taker_commission: 0.0004, + // strike: 300, + // settlement_period: 'week', + // quote_currency: 'USD', + // option_type: 'call', + // min_trade_amount: 1, + // maker_commission: 0.0004, + // kind: 'option', + // is_active: true, + // instrument_name: 'ETH-13MAR20-300-C', + // expiration_timestamp: 1584086400000, + // creation_timestamp: 1582790403000, + // contract_size: 1, + // base_currency: 'ETH' + // }, + // ], + // usIn: 1583761889500586, + // usOut: 1583761889505066, + // usDiff: 4480, + // testnet: false + // } + // + const instrumentsResult = this.safeValue (instrumentsResponse, 'result', []); + for (let k = 0; k < instrumentsResult.length; k++) { + const market = instrumentsResult[k]; + const id = this.safeString (market, 'instrument_name'); + const baseId = this.safeString (market, 'base_currency'); + const quoteId = this.safeString (market, 'quote_currency'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + const type = this.safeString (market, 'kind'); + const future = (type === 'future'); + const option = (type === 'option'); + const active = this.safeValue (market, 'is_active'); + const minTradeAmount = this.safeFloat (market, 'min_trade_amount'); + const tickSize = this.safeFloat (market, 'tick_size'); + const precision = { + 'amount': minTradeAmount, + 'price': tickSize, + }; + result.push ({ + 'id': id, + 'symbol': id, + 'base': base, + 'quote': quote, + 'active': active, + 'precision': precision, + 'taker': this.safeFloat (market, 'taker_commission'), + 'maker': this.safeFloat (market, 'maker_commission'), + 'limits': { + 'amount': { + 'min': minTradeAmount, + 'max': undefined, + }, + 'price': { + 'min': tickSize, + 'max': undefined, + }, + 'cost': { + 'min': undefined, + 'max': undefined, + }, }, - 'price': { - 'min': this.safeFloat (market, 'tickSize'), - 'max': undefined, - }, - 'cost': { - 'min': undefined, - 'max': undefined, - }, - }, - 'type': type, - 'spot': false, - 'future': future, - 'option': option, - 'info': market, - }); + 'type': type, + 'spot': false, + 'future': future, + 'option': option, + 'info': market, + }); + } } return result; } async fetchBalance (params = {}) { await this.loadMarkets (); - const response = await this.privateGetAccount (params); + const code = this.codeFromOptions ('fetchBalance'); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + }; + const response = await this.privateGetGetAccountSummary (this.extend (request, params)); // // { - // "usOut":1569048827943520, - // "usIn":1569048827943020, - // "usDiff":500, - // "testnet":false, - // "success":true, - // "result":{ - // "equity":2e-9, - // "maintenanceMargin":0.0, - // "initialMargin":0.0, - // "availableFunds":0.0, - // "balance":0.0, - // "marginBalance":0.0, - // "SUPL":0.0, - // "SRPL":0.0, - // "PNL":0.0, - // "optionsPNL":0.0, - // "optionsSUPL":0.0, - // "optionsSRPL":0.0, - // "optionsD":0.0, - // "optionsG":0.0, - // "optionsV":0.0, - // "optionsTh":0.0, - // "futuresPNL":0.0, - // "futuresSUPL":0.0, - // "futuresSRPL":0.0, - // "deltaTotal":0.0, - // "sessionFunding":0.0, - // "depositAddress":"13tUtNsJSZa1F5GeCmwBywVrymHpZispzw", - // "currency":"BTC" + // jsonrpc: '2.0', + // result: { + // total_pl: 0, + // session_upl: 0, + // session_rpl: 0, + // session_funding: 0, + // portfolio_margining_enabled: false, + // options_vega: 0, + // options_theta: 0, + // options_session_upl: 0, + // options_session_rpl: 0, + // options_pl: 0, + // options_gamma: 0, + // options_delta: 0, + // margin_balance: 0.00062359, + // maintenance_margin: 0, + // limits: { + // non_matching_engine_burst: 300, + // non_matching_engine: 200, + // matching_engine_burst: 20, + // matching_engine: 2 + // }, + // initial_margin: 0, + // futures_session_upl: 0, + // futures_session_rpl: 0, + // futures_pl: 0, + // equity: 0.00062359, + // deposit_address: '13tUtNsJSZa1F5GeCmwBywVrymHpZispzw', + // delta_total: 0, + // currency: 'BTC', + // balance: 0.00062359, + // available_withdrawal_funds: 0.00062359, + // available_funds: 0.00062359 // }, - // "message":"" + // usIn: 1583775838115975, + // usOut: 1583775838116520, + // usDiff: 545, + // testnet: false // } // const result = { 'info': response, }; const balance = this.safeValue (response, 'result', {}); - const currencyId = this.safeString (balance, 'currency'); - const code = this.safeCurrencyCode (currencyId); const account = this.account (); account['free'] = this.safeFloat (balance, 'availableFunds'); account['used'] = this.safeFloat (balance, 'maintenanceMargin'); @@ -237,15 +533,63 @@ module.exports = class deribit extends Exchange { return this.parseBalance (result); } + async createDepositAddress (code, params = {}) { + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + }; + const response = await this.privateGetCreateDepositAddress (this.extend (request, params)); + // + // { + // 'jsonrpc': '2.0', + // 'id': 7538, + // 'result': { + // 'address': '2N8udZGBc1hLRCFsU9kGwMPpmYUwMFTuCwB', + // 'creation_timestamp': 1550575165170, + // 'currency': 'BTC', + // 'type': 'deposit' + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const address = this.safeString (result, 'address'); + this.checkAddress (address); + return { + 'currency': code, + 'address': address, + 'tag': undefined, + 'info': response, + }; + } + async fetchDepositAddress (code, params = {}) { await this.loadMarkets (); const currency = this.currency (code); const request = { 'currency': currency['id'], }; - const response = await this.privateGetAccount (this.extend (request, params)); + const response = await this.privateGetGetCurrentDepositAddress (this.extend (request, params)); + // + // { + // jsonrpc: '2.0', + // result: { + // type: 'deposit', + // status: 'ready', + // requires_confirmation: true, + // currency: 'BTC', + // creation_timestamp: 1514694684651, + // address: '13tUtNsJSZa1F5GeCmwBywVrymHpZispzw' + // }, + // usIn: 1583785137274288, + // usOut: 1583785137274454, + // usDiff: 166, + // testnet: false + // } + // const result = this.safeValue (response, 'result', {}); - const address = this.safeString (result, 'depositAddress'); + const address = this.safeString (result, 'address'); + this.checkAddress (address); return { 'currency': code, 'address': address, @@ -255,47 +599,73 @@ module.exports = class deribit extends Exchange { } parseTicker (ticker, market = undefined) { + // + // fetchTicker /public/ticker // // { - // "currentFunding":0.0, - // "funding8h":0.0000017213784611422821, - // "instrumentName":"BTC-PERPETUAL", - // "openInterest":7600223, - // "openInterestAmount":76002230, - // "high":7665.5, - // "low":7450.0, - // "volume":12964792.0, - // "volumeUsd":129647920, - // "volumeBtc":17214.63595316, - // "last":7520.5, - // "bidPrice":7520.0, - // "askPrice":7520.5, - // "midPrice":7520.25, - // "estDelPrice":"", - // "markPrice":7521.0, - // "created":"2019-12-09 15:17:00 GMT" + // timestamp: 1583778859480, + // stats: { volume: 60627.57263769, low: 7631.5, high: 8311.5 }, + // state: 'open', + // settlement_price: 7903.21, + // open_interest: 111543850, + // min_price: 7634, + // max_price: 7866.51, + // mark_price: 7750.02, + // last_price: 7750.5, + // instrument_name: 'BTC-PERPETUAL', + // index_price: 7748.01, + // funding_8h: 0.0000026, + // current_funding: 0, + // best_bid_price: 7750, + // best_bid_amount: 19470, + // best_ask_price: 7750.5, + // best_ask_amount: 343280 // } // - const timestamp = this.safeInteger (ticker, 'created'); - let symbol = undefined; - const marketId = this.safeString (ticker, 'instrumentName'); + // fetchTicker /public/get_book_summary_by_instrument + // fetchTickers /public/get_book_summary_by_currency + // + // { + // volume: 124.1, + // underlying_price: 7856.445926872601, + // underlying_index: 'SYN.BTC-10MAR20', + // quote_currency: 'USD', + // open_interest: 121.8, + // mid_price: 0.01975, + // mark_price: 0.01984559, + // low: 0.0095, + // last: 0.0205, + // interest_rate: 0, + // instrument_name: 'BTC-10MAR20-7750-C', + // high: 0.0295, + // estimated_delivery_price: 7856.29, + // creation_timestamp: 1583783678366, + // bid_price: 0.0185, + // base_currency: 'BTC', + // ask_price: 0.021 + // }, + // + const timestamp = this.safeInteger2 (ticker, 'timestamp', 'creation_timestamp'); + const marketId = this.safeString (ticker, 'instrument_name'); + let symbol = marketId; if (marketId in this.markets_by_id) { market = this.markets_by_id[marketId]; } if ((symbol === undefined) && (market !== undefined)) { symbol = market['symbol']; } - const last = this.safeFloat (ticker, 'last'); + const last = this.safeFloat2 (ticker, 'last_price', 'last'); + const stats = this.safeValue (ticker, 'stats', ticker); return { 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), - 'high': this.safeFloat (ticker, 'high'), - 'low': this.safeFloat (ticker, 'low'), - 'bid': this.safeFloat (ticker, 'bidPrice'), - 'bidVolume': undefined, - 'ask': this.safeFloat (ticker, 'askPrice'), - 'askVolume': undefined, + 'high': this.safeFloat2 (stats, 'high', 'max_price'), + 'low': this.safeFloat2 (stats, 'low', 'min_price'), + 'bid': this.safeFloat2 (ticker, 'best_bid_price', 'bid_price'), + 'bidVolume': this.safeFloat (ticker, 'best_bid_amount'), + 'ask': this.safeFloat2 (ticker, 'best_ask_price', 'ask_price'), + 'askVolume': this.safeFloat (ticker, 'best_ask_amount'), 'vwap': undefined, 'open': undefined, 'close': last, @@ -305,7 +675,7 @@ module.exports = class deribit extends Exchange { 'percentage': undefined, 'average': undefined, 'baseVolume': undefined, - 'quoteVolume': this.safeFloat (ticker, 'volume'), + 'quoteVolume': this.safeFloat (stats, 'volume'), 'info': ticker, }; } @@ -314,39 +684,136 @@ module.exports = class deribit extends Exchange { await this.loadMarkets (); const market = this.market (symbol); const request = { - 'instrument': market['id'], + 'instrument_name': market['id'], }; - const response = await this.publicGetGetsummary (this.extend (request, params)); + const response = await this.publicGetTicker (this.extend (request, params)); // // { - // "usOut":1575904620528163, - // "usIn":1575904620528129, - // "usDiff":34, - // "testnet":false, - // "success":true, - // "result": { - // "currentFunding":0.0, - // "funding8h":0.0000017213784611422821, - // "instrumentName":"BTC-PERPETUAL", - // "openInterest":7600223, - // "openInterestAmount":76002230, - // "high":7665.5, - // "low":7450.0, - // "volume":12964792.0, - // "volumeUsd":129647920, - // "volumeBtc":17214.63595316, - // "last":7520.5, - // "bidPrice":7520.0, - // "askPrice":7520.5, - // "midPrice":7520.25, - // "estDelPrice":"", - // "markPrice":7521.0, - // "created":"2019-12-09 15:17:00 GMT" + // jsonrpc: '2.0', + // result: { + // timestamp: 1583778859480, + // stats: { volume: 60627.57263769, low: 7631.5, high: 8311.5 }, + // state: 'open', + // settlement_price: 7903.21, + // open_interest: 111543850, + // min_price: 7634, + // max_price: 7866.51, + // mark_price: 7750.02, + // last_price: 7750.5, + // instrument_name: 'BTC-PERPETUAL', + // index_price: 7748.01, + // funding_8h: 0.0000026, + // current_funding: 0, + // best_bid_price: 7750, + // best_bid_amount: 19470, + // best_ask_price: 7750.5, + // best_ask_amount: 343280 // }, - // "message":"" + // usIn: 1583778859483941, + // usOut: 1583778859484075, + // usDiff: 134, + // testnet: false // } // - return this.parseTicker (response['result'], market); + const result = this.safeValue (response, 'result'); + return this.parseTicker (result, market); + } + + async fetchTickers (symbols = undefined, params = {}) { + await this.loadMarkets (); + const code = this.codeFromOptions ('fetchTickers'); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + }; + const response = await this.publicGetGetBookSummaryByCurrency (this.extend (request, params)); + // + // { + // jsonrpc: '2.0', + // result: [ + // { + // volume: 124.1, + // underlying_price: 7856.445926872601, + // underlying_index: 'SYN.BTC-10MAR20', + // quote_currency: 'USD', + // open_interest: 121.8, + // mid_price: 0.01975, + // mark_price: 0.01984559, + // low: 0.0095, + // last: 0.0205, + // interest_rate: 0, + // instrument_name: 'BTC-10MAR20-7750-C', + // high: 0.0295, + // estimated_delivery_price: 7856.29, + // creation_timestamp: 1583783678366, + // bid_price: 0.0185, + // base_currency: 'BTC', + // ask_price: 0.021 + // }, + // ], + // usIn: 1583783678361966, + // usOut: 1583783678372069, + // usDiff: 10103, + // testnet: false + // } + // + const result = this.safeValue (response, 'result', []); + const tickers = {}; + for (let i = 0; i < result.length; i++) { + const ticker = this.parseTicker (result[i]); + const symbol = ticker['symbol']; + tickers[symbol] = ticker; + } + return this.filterByArray (tickers, 'symbol', symbols); + } + + async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'instrument_name': market['id'], + 'resolution': this.timeframes[timeframe], + }; + const duration = this.parseTimeframe (timeframe); + const now = this.milliseconds (); + if (since === undefined) { + if (limit === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument or a limit argument'); + } else { + request['start_timestamp'] = now - (limit - 1) * duration * 1000; + request['end_timestamp'] = now; + } + } else { + request['start_timestamp'] = since; + if (limit === undefined) { + request['end_timestamp'] = now; + } else { + request['end_timestamp'] = this.sum (since, limit * duration * 1000); + } + } + const response = await this.publicGetGetTradingviewChartData (this.extend (request, params)); + // + // { + // jsonrpc: '2.0', + // result: { + // volume: [ 3.6680847969999992, 22.682721123, 3.011587939, 0 ], + // ticks: [ 1583916960000, 1583917020000, 1583917080000, 1583917140000 ], + // status: 'ok', + // open: [ 7834, 7839, 7833.5, 7833 ], + // low: [ 7834, 7833.5, 7832.5, 7833 ], + // high: [ 7839.5, 7839, 7833.5, 7833 ], + // cost: [ 28740, 177740, 23590, 0 ], + // close: [ 7839.5, 7833.5, 7833, 7833 ] + // }, + // usIn: 1583917166709801, + // usOut: 1583917166710175, + // usDiff: 374, + // testnet: false + // } + // + const result = this.safeValue (response, 'result', {}); + const ohlcvs = this.convertTradingViewToOHLCV (result, 'ticks', 'open', 'high', 'low', 'close', 'volume', true); + return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit); } parseTrade (trade, market = undefined) { @@ -354,59 +821,72 @@ module.exports = class deribit extends Exchange { // fetchTrades (public) // // { - // "tradeId":23197559, - // "instrument":"BTC-28JUN19", - // "timeStamp":1559643011379, - // "tradeSeq":1997200, - // "quantity":2, - // "amount":20.0, - // "price":8010.0, - // "direction":"sell", - // "tickDirection":2, - // "indexPrice":7969.01 + // 'trade_seq': 39201926, + // 'trade_id':' 64135724', + // 'timestamp': 1583174775400, + // 'tick_direction': 1, + // 'price': 8865.0, + // 'instrument_name': 'BTC-PERPETUAL', + // 'index_price': 8863.31, + // 'direction': 'buy', + // 'amount': 10.0 // } // - // fetchMyTrades (private) + // fetchMyTrades, fetchOrderTrades (private) // // { - // "quantity":54, - // "amount":540.0, - // "tradeId":23087297, - // "instrument":"BTC-PERPETUAL", - // "timeStamp":1559604178803, - // "tradeSeq":8265011, - // "price":8213.0, - // "side":"sell", - // "orderId":12373631800, - // "matchingId":0, - // "liquidity":"T", - // "fee":0.000049312, - // "feeCurrency":"BTC", - // "tickDirection":3, - // "indexPrice":8251.94, - // "selfTrade":false + // "trade_seq": 3, + // "trade_id": "ETH-34066", + // "timestamp": 1550219814585, + // "tick_direction": 1, + // "state": "open", + // "self_trade": false, + // "reduce_only": false, + // "price": 0.04, + // "post_only": false, + // "order_type": "limit", + // "order_id": "ETH-334607", + // "matching_id": null, + // "liquidity": "M", + // "iv": 56.83, + // "instrument_name": "ETH-22FEB19-120-C", + // "index_price": 121.37, + // "fee_currency": "ETH", + // "fee": 0.0011, + // "direction": "buy", + // "amount": 11 // } // - const id = this.safeString (trade, 'tradeId'); - const orderId = this.safeString (trade, 'orderId'); + const id = this.safeString (trade, 'trade_id'); let symbol = undefined; - if (market !== undefined) { + const marketId = this.safeString (trade, 'instrument_name'); + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; symbol = market['symbol']; } - const timestamp = this.safeInteger (trade, 'timeStamp'); - const side = this.safeString2 (trade, 'side', 'direction'); + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const timestamp = this.safeInteger (trade, 'timestamp'); + const side = this.safeString (trade, 'direction'); const price = this.safeFloat (trade, 'price'); - const amount = this.safeFloat (trade, 'quantity'); + const amount = this.safeFloat (trade, 'amount'); let cost = undefined; if (amount !== undefined) { if (price !== undefined) { cost = amount * price; } } + const liquidity = this.safeString (trade, 'liquidity'); + let takerOrMaker = undefined; + if (liquidity !== undefined) { + // M = maker, T = taker, MT = both + takerOrMaker = (liquidity === 'M') ? 'maker' : 'taker'; + } + const feeCost = this.safeFloat (trade, 'feeCost'); let fee = undefined; - const feeCost = this.safeFloat (trade, 'fee'); if (feeCost !== undefined) { - const feeCurrencyId = this.safeString (trade, 'feeCurrency'); + const feeCurrencyId = this.safeString (trade, 'fee_currency'); const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); fee = { 'cost': feeCost, @@ -419,10 +899,10 @@ module.exports = class deribit extends Exchange { 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'symbol': symbol, - 'order': orderId, - 'type': undefined, + 'order': this.safeString (trade, 'order_id'), + 'type': this.safeString (trade, 'order_type'), 'side': side, - 'takerOrMaker': undefined, + 'takerOrMaker': takerOrMaker, 'price': price, 'amount': amount, 'cost': cost, @@ -434,54 +914,102 @@ module.exports = class deribit extends Exchange { await this.loadMarkets (); const market = this.market (symbol); const request = { - 'instrument': market['id'], + 'instrument_name': market['id'], + 'include_old': true, }; - if (limit !== undefined) { - request['limit'] = limit; - } else { - request['limit'] = 10000; + const method = (since === undefined) ? 'publicGetGetLastTradesByInstrument' : 'publicGetGetLastTradesByInstrumentAndTime'; + if (since !== undefined) { + request['start_timestamp'] = since; } - const response = await this.publicGetGetlasttrades (this.extend (request, params)); + if (limit !== undefined) { + request['count'] = limit; // default 10 + } + const response = await this[method] (this.extend (request, params)); // // { - // "usOut":1559643108984527, - // "usIn":1559643108984470, - // "usDiff":57, - // "testnet":false, - // "success":true, - // "result": [ - // { - // "tradeId":23197559, - // "instrument":"BTC-28JUN19", - // "timeStamp":1559643011379, - // "tradeSeq":1997200, - // "quantity":2, - // "amount":20.0, - // "price":8010.0, - // "direction":"sell", - // "tickDirection":2, - // "indexPrice":7969.01 - // } - // ], - // "message":"" + // 'jsonrpc': '2.0', + // 'result': { + // 'trades': [ + // { + // 'trade_seq': 39201926, + // 'trade_id':' 64135724', + // 'timestamp': 1583174775400, + // 'tick_direction': 1, + // 'price': 8865.0, + // 'instrument_name': 'BTC-PERPETUAL', + // 'index_price': 8863.31, + // 'direction': 'buy', + // 'amount': 10.0 + // }, + // ], + // 'has_more': true, + // }, + // 'usIn': 1583779594843931, + // 'usOut': 1583779594844446, + // 'usDiff': 515, + // 'testnet': false // } // - const result = this.safeValue (response, 'result', []); - return this.parseTrades (result, market, since, limit); + const result = this.safeValue (response, 'result', {}); + const trades = this.safeValue (result, 'trades', []); + return this.parseTrades (trades, market, since, limit); } async fetchOrderBook (symbol, limit = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = { - 'instrument': market['id'], + 'instrument_name': market['id'], }; - const response = await this.publicGetGetorderbook (this.extend (request, params)); - const timestamp = this.safeInteger (response, 'usOut') / 1000; - const orderbook = this.parseOrderBook (response['result'], timestamp, 'bids', 'asks', 'price', 'quantity'); - return this.extend (orderbook, { - 'nonce': this.safeInteger (response, 'tstamp'), - }); + if (limit !== undefined) { + request['depth'] = limit; + } + const response = await this.publicGetGetOrderBook (this.extend (request, params)); + // + // { + // jsonrpc: '2.0', + // result: { + // timestamp: 1583781354740, + // stats: { volume: 61249.66735634, low: 7631.5, high: 8311.5 }, + // state: 'open', + // settlement_price: 7903.21, + // open_interest: 111536690, + // min_price: 7695.13, + // max_price: 7929.49, + // mark_price: 7813.06, + // last_price: 7814.5, + // instrument_name: 'BTC-PERPETUAL', + // index_price: 7810.12, + // funding_8h: 0.0000031, + // current_funding: 0, + // change_id: 17538025952, + // bids: [ + // [7814, 351820], + // [7813.5, 207490], + // [7813, 32160], + // ], + // best_bid_price: 7814, + // best_bid_amount: 351820, + // best_ask_price: 7814.5, + // best_ask_amount: 11880, + // asks: [ + // [7814.5, 11880], + // [7815, 18100], + // [7815.5, 2640], + // ], + // }, + // usIn: 1583781354745804, + // usOut: 1583781354745932, + // usDiff: 128, + // testnet: false + // } + // + const result = this.safeValue (response, 'result', {}); + const timestamp = this.safeInteger (result, 'timestamp'); + const nonce = this.safeInteger (result, 'change_id'); + const orderbook = this.parseOrderBook (result, timestamp); + orderbook['nonce'] = nonce; + return orderbook; } parseOrderStatus (status) { @@ -489,48 +1017,51 @@ module.exports = class deribit extends Exchange { 'open': 'open', 'cancelled': 'canceled', 'filled': 'closed', + 'rejected': 'rejected', + // 'untriggered': 'open', }; return this.safeString (statuses, status, status); } parseOrder (order, market = undefined) { + // + // createOrder // // { - // "orderId": 5258039, // ID of the order - // "type": "limit", // not documented, but present in the actual response - // "instrument": "BTC-26MAY17", // instrument name (market id) - // "direction": "sell", // order direction, "buy" or "sell" - // "price": 1860, // float, USD for futures, BTC for options - // "label": "", // label set by the owner, up to 32 chars - // "quantity": 10, // quantity, in contracts ($10 per contract for futures, ฿1 — for options) - // "filledQuantity": 3, // filled quantity, in contracts ($10 per contract for futures, ฿1 — for options) - // "avgPrice": 1860, // average fill price of the order - // "commission": -0.000001613, // in BTC units - // "created": 1494491899308, // creation timestamp - // "state": "open", // open, cancelled, etc - // "postOnly": false // true for post-only orders only - // open orders -------------------------------------------------------- - // "lastUpdate": 1494491988754, // timestamp of the last order state change (before this cancelorder of course) - // closed orders ------------------------------------------------------ - // "tstamp": 1494492913288, // timestamp of the last order state change, documented, but may be missing in the actual response - // "modified": 1494492913289, // timestamp of the last db write operation, e.g. trade that doesn't change order status, documented, but may missing in the actual response - // "adv": false // advanced type (false, or "usd" or "implv") - // "trades": [], // not documented, injected from the outside of the parseOrder method into the order + // "time_in_force": "good_til_cancelled", + // "reduce_only": false, + // "profit_loss": 0, + // "price": "market_price", + // "post_only": false, + // "order_type": "market", + // "order_state": "filled", + // "order_id": "ETH-349249", + // "max_show": 40, + // "last_update_timestamp": 1550657341322, + // "label": "market0000234", + // "is_liquidation": false, + // "instrument_name": "ETH-PERPETUAL", + // "filled_amount": 40, + // "direction": "buy", + // "creation_timestamp": 1550657341322, + // "commission": 0.000139, + // "average_price": 143.81, + // "api": true, + // "amount": 40, + // "trades": [], // injected by createOrder // } // - const timestamp = this.safeInteger (order, 'created'); - const lastUpdate = this.safeInteger (order, 'lastUpdate'); - let lastTradeTimestamp = this.safeInteger2 (order, 'tstamp', 'modified'); - const id = this.safeString (order, 'orderId'); + const timestamp = this.safeInteger (order, 'creation_timestamp'); + const lastUpdate = this.safeInteger (order, 'last_update_timestamp'); + const id = this.safeString (order, 'order_id'); const price = this.safeFloat (order, 'price'); - const average = this.safeFloat (order, 'avgPrice'); - const amount = this.safeFloat (order, 'quantity'); - const filled = this.safeFloat (order, 'filledQuantity'); - if (lastTradeTimestamp === undefined) { - if (filled !== undefined) { - if (filled > 0) { - lastTradeTimestamp = lastUpdate; - } + const average = this.safeFloat (order, 'average_price'); + const amount = this.safeFloat (order, 'amount'); + const filled = this.safeFloat (order, 'filled_amount'); + let lastTradeTimestamp = undefined; + if (filled !== undefined) { + if (filled > 0) { + lastTradeTimestamp = lastUpdate; } } let remaining = undefined; @@ -543,26 +1074,43 @@ module.exports = class deribit extends Exchange { cost = price * filled; } } - const status = this.parseOrderStatus (this.safeString (order, 'state')); - const side = this.safeStringLower (order, 'direction'); - let feeCost = this.safeFloat (order, 'commission'); - if (feeCost !== undefined) { - feeCost = Math.abs (feeCost); - } - const fee = { - 'cost': feeCost, - 'currency': 'BTC', - }; - const type = this.safeString (order, 'type'); - const marketId = this.safeString (order, 'instrument'); + const status = this.parseOrderStatus (this.safeString (order, 'order_state')); + const marketId = this.safeString (order, 'instrument_name'); let symbol = undefined; + let base = undefined; if (marketId in this.markets_by_id) { market = this.markets_by_id[marketId]; symbol = market['symbol']; + base = market['base']; + } + if (market !== undefined) { + if (symbol === undefined) { + symbol = market['symbol']; + } + if (base === undefined) { + base = market['base']; + } + } + const side = this.safeStringLower (order, 'direction'); + let feeCost = this.safeFloat (order, 'commission'); + let fee = undefined; + if (feeCost !== undefined) { + feeCost = Math.abs (feeCost); + fee = { + 'cost': feeCost, + 'currency': base, + }; + } + const type = this.safeString (order, 'order_type'); + // injected in createOrder + let trades = this.safeValue (order, 'trades'); + if (trades !== undefined) { + trades = this.parseTrades (trades, market); } return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -577,169 +1125,561 @@ module.exports = class deribit extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, - 'trades': undefined, // todo: parse trades + 'trades': trades, }; } async fetchOrder (id, symbol = undefined, params = {}) { await this.loadMarkets (); const request = { - 'orderId': id, + 'order_id': id, }; - const response = await this.privateGetOrderstate (this.extend (request, params)); + const response = await this.privateGetGetOrderState (this.extend (request, params)); + // + // { + // "jsonrpc": "2.0", + // "id": 4316, + // "result": { + // "time_in_force": "good_til_cancelled", + // "reduce_only": false, + // "profit_loss": 0.051134, + // "price": 118.94, + // "post_only": false, + // "order_type": "limit", + // "order_state": "filled", + // "order_id": "ETH-331562", + // "max_show": 37, + // "last_update_timestamp": 1550219810944, + // "label": "", + // "is_liquidation": false, + // "instrument_name": "ETH-PERPETUAL", + // "filled_amount": 37, + // "direction": "sell", + // "creation_timestamp": 1550219749176, + // "commission": 0.000031, + // "average_price": 118.94, + // "api": false, + // "amount": 37 + // } + // } + // const result = this.safeValue (response, 'result'); - if (result === undefined) { - throw new OrderNotFound (this.id + ' fetchOrder() ' + this.json (response)); - } return this.parseOrder (result); } async createOrder (symbol, type, side, amount, price = undefined, params = {}) { await this.loadMarkets (); + const market = this.market (symbol); const request = { - 'instrument': this.marketId (symbol), - 'quantity': amount, - 'type': type, - // 'post_only': 'false' or 'true', https://github.com/ccxt/ccxt/issues/5159 + 'instrument_name': market['id'], + // for perpetual and futures the amount is in USD + // for options it is in corresponding cryptocurrency contracts, e.g., BTC or ETH + 'amount': this.amountToPrecision (symbol, amount), + 'type': type, // limit, stop_limit, market, stop_market, default is limit + // 'label': 'string', // user-defined label for the order (maximum 64 characters) + // 'price': this.priceToPrecision (symbol, 123.45), // only for limit and stop_limit orders + // 'time_in_force' : 'good_til_cancelled', // fill_or_kill, immediate_or_cancel + // 'max_show': 123.45, // max amount within an order to be shown to other customers, 0 for invisible order + // 'post_only': false, // if the new price would cause the order to be filled immediately (as taker), the price will be changed to be just below the spread. + // 'reject_post_only': false, // if true the order is put to order book unmodified or request is rejected + // 'reduce_only': false, // if true, the order is intended to only reduce a current position + // 'stop_price': false, // stop price, required for stop_limit orders + // 'trigger': 'index_price', // mark_price, last_price, required for stop_limit orders + // 'advanced': 'usd', // 'implv', advanced option order type, options only }; - if (price !== undefined) { - request['price'] = price; + let priceIsRequired = false; + let stopPriceIsRequired = false; + if (type === 'limit') { + priceIsRequired = true; + } else if (type === 'stop_limit') { + priceIsRequired = true; + stopPriceIsRequired = true; } - const method = 'privatePost' + this.capitalize (side); + if (priceIsRequired) { + if (price !== undefined) { + request['price'] = this.priceToPrecision (symbol, price); + } else { + throw new ArgumentsRequired (this.id + ' createOrder requires a price argument for a ' + type + ' order'); + } + } + if (stopPriceIsRequired) { + const stopPrice = this.safeFloat2 (params, 'stop_price', 'stopPrice'); + if (stopPrice === undefined) { + throw new ArgumentsRequired (this.id + ' createOrder requires a stop_price or stopPrice param for a ' + type + ' order'); + } else { + request['stop_price'] = this.priceToPrecision (symbol, stopPrice); + } + } + const method = 'privateGet' + this.capitalize (side); const response = await this[method] (this.extend (request, params)); - const order = this.safeValue (response['result'], 'order'); - if (order === undefined) { - return response; - } - return this.parseOrder (order); + // + // { + // "jsonrpc": "2.0", + // "id": 5275, + // "result": { + // "trades": [ + // { + // "trade_seq": 14151, + // "trade_id": "ETH-37435", + // "timestamp": 1550657341322, + // "tick_direction": 2, + // "state": "closed", + // "self_trade": false, + // "price": 143.81, + // "order_type": "market", + // "order_id": "ETH-349249", + // "matching_id": null, + // "liquidity": "T", + // "label": "market0000234", + // "instrument_name": "ETH-PERPETUAL", + // "index_price": 143.73, + // "fee_currency": "ETH", + // "fee": 0.000139, + // "direction": "buy", + // "amount": 40 + // } + // ], + // "order": { + // "time_in_force": "good_til_cancelled", + // "reduce_only": false, + // "profit_loss": 0, + // "price": "market_price", + // "post_only": false, + // "order_type": "market", + // "order_state": "filled", + // "order_id": "ETH-349249", + // "max_show": 40, + // "last_update_timestamp": 1550657341322, + // "label": "market0000234", + // "is_liquidation": false, + // "instrument_name": "ETH-PERPETUAL", + // "filled_amount": 40, + // "direction": "buy", + // "creation_timestamp": 1550657341322, + // "commission": 0.000139, + // "average_price": 143.81, + // "api": true, + // "amount": 40 + // } + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const order = this.safeValue (result, 'order'); + const trades = this.safeValue (result, 'trades', []); + order['trades'] = trades; + return this.parseOrder (order, market); } async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) { + if (amount === undefined) { + throw new ArgumentsRequired (this.id + ' editOrder requires an amount argument'); + } + if (price === undefined) { + throw new ArgumentsRequired (this.id + ' editOrder requires a price argument'); + } await this.loadMarkets (); const request = { - 'orderId': id, + 'order_id': id, + // for perpetual and futures the amount is in USD + // for options it is in corresponding cryptocurrency contracts, e.g., BTC or ETH + 'amount': this.amountToPrecision (symbol, amount), + 'price': this.priceToPrecision (symbol, price), // required + // 'post_only': false, // if the new price would cause the order to be filled immediately (as taker), the price will be changed to be just below the spread. + // 'reject_post_only': false, // if true the order is put to order book unmodified or request is rejected + // 'reduce_only': false, // if true, the order is intended to only reduce a current position + // 'stop_price': false, // stop price, required for stop_limit orders + // 'advanced': 'usd', // 'implv', advanced option order type, options only }; - if (amount !== undefined) { - request['quantity'] = amount; - } - if (price !== undefined) { - request['price'] = price; - } - const response = await this.privatePostEdit (this.extend (request, params)); - return this.parseOrder (response['result']['order']); + const response = await this.privateGetEdit (this.extend (request, params)); + const result = this.safeValue (response, 'result', {}); + const order = this.safeValue (result, 'order'); + const trades = this.safeValue (result, 'trades', []); + order['trades'] = trades; + return this.parseOrder (order); } async cancelOrder (id, symbol = undefined, params = {}) { await this.loadMarkets (); const request = { - 'orderId': id, + 'order_id': id, }; - const response = await this.privatePostCancel (this.extend (request, params)); - return this.parseOrder (response['result']['order']); + const response = await this.privateGetCancel (this.extend (request, params)); + const result = this.safeValue (response, 'result', {}); + return this.parseOrder (result); + } + + async cancelAllOrders (symbol = undefined, params = {}) { + await this.loadMarkets (); + const request = {}; + let method = undefined; + if (symbol === undefined) { + method = 'privateGetCancelAll'; + } else { + method = 'privateGetCancelAllByInstrument'; + const market = this.market (symbol); + request['instrument_name'] = market['id']; + } + const response = await this[method] (this.extend (request, params)); + return response; } async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchClosedOrders() requires a `symbol` argument'); - } await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'instrument': market['id'], - }; - const response = await this.privateGetGetopenorders (this.extend (request, params)); - return this.parseOrders (response['result'], market, since, limit); + const request = {}; + let market = undefined; + let method = undefined; + if (symbol === undefined) { + const code = this.codeFromOptions ('fetchOpenOrders'); + const currency = this.currency (code); + request['currency'] = currency['id']; + method = 'privateGetGetOpenOrdersByCurrency'; + } else { + market = this.market (symbol); + request['instrument_name'] = market['id']; + method = 'privateGetGetOpenOrdersByInstrument'; + } + const response = await this[method] (this.extend (request, params)); + const result = this.safeValue (response, 'result', []); + return this.parseOrders (result, market, since, limit); } async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchClosedOrders() requires a `symbol` argument'); - } await this.loadMarkets (); - const market = this.market (symbol); + const request = {}; + let market = undefined; + let method = undefined; + if (symbol === undefined) { + const code = this.codeFromOptions ('fetchClosedOrders'); + const currency = this.currency (code); + request['currency'] = currency['id']; + method = 'privateGetGetOrderHistoryByCurrency'; + } else { + market = this.market (symbol); + request['instrument_name'] = market['id']; + method = 'privateGetGetOrderHistoryByInstrument'; + } + const response = await this[method] (this.extend (request, params)); + const result = this.safeValue (response, 'result', []); + return this.parseOrders (result, market, since, limit); + } + + async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); const request = { - 'instrument': market['id'], + 'order_id': id, }; - const response = await this.privateGetOrderhistory (this.extend (request, params)); - return this.parseOrders (response['result'], market, since, limit); + const response = await this.privateGetGetUserTradesByOrder (this.extend (request, params)); + // + // { + // "jsonrpc": "2.0", + // "id": 9367, + // "result": { + // "trades": [ + // { + // "trade_seq": 3, + // "trade_id": "ETH-34066", + // "timestamp": 1550219814585, + // "tick_direction": 1, + // "state": "open", + // "self_trade": false, + // "reduce_only": false, + // "price": 0.04, + // "post_only": false, + // "order_type": "limit", + // "order_id": "ETH-334607", + // "matching_id": null, + // "liquidity": "M", + // "iv": 56.83, + // "instrument_name": "ETH-22FEB19-120-C", + // "index_price": 121.37, + // "fee_currency": "ETH", + // "fee": 0.0011, + // "direction": "buy", + // "amount": 11 + // }, + // ], + // "has_more": true + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const trades = this.safeValue (result, 'trades', []); + return this.parseTrades (trades, undefined, since, limit); } async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); - const market = this.market (symbol); const request = { - 'instrument': market['id'], + 'include_old': true, }; - if (limit !== undefined) { - request['count'] = limit; // default = 20 + let market = undefined; + let method = undefined; + if (symbol === undefined) { + const code = this.codeFromOptions ('fetchMyTrades'); + const currency = this.currency (code); + request['currency'] = currency['id']; + if (since === undefined) { + method = 'privateGetGetUserTradesByCurrency'; + } else { + method = 'privateGetGetUserTradesByCurrencyAndTime'; + request['start_timestamp'] = since; + } + } else { + market = this.market (symbol); + request['instrument_name'] = market['id']; + if (since === undefined) { + method = 'privateGetGetUserTradesByInstrument'; + } else { + method = 'privateGetGetUserTradesByInstrumentAndTime'; + request['start_timestamp'] = since; + } } - const response = await this.privateGetTradehistory (this.extend (request, params)); + if (limit !== undefined) { + request['count'] = limit; // default 10 + } + const response = await this[method] (this.extend (request, params)); // // { - // "usOut":1559611553394836, - // "usIn":1559611553394000, - // "usDiff":836, - // "testnet":false, - // "success":true, - // "result": [ - // { - // "quantity":54, - // "amount":540.0, - // "tradeId":23087297, - // "instrument":"BTC-PERPETUAL", - // "timeStamp":1559604178803, - // "tradeSeq":8265011, - // "price":8213.0, - // "side":"sell", - // "orderId":12373631800, - // "matchingId":0, - // "liquidity":"T", - // "fee":0.000049312, - // "feeCurrency":"BTC", - // "tickDirection":3, - // "indexPrice":8251.94, - // "selfTrade":false - // } - // ], - // "message":"", - // "has_more":true + // "jsonrpc": "2.0", + // "id": 9367, + // "result": { + // "trades": [ + // { + // "trade_seq": 3, + // "trade_id": "ETH-34066", + // "timestamp": 1550219814585, + // "tick_direction": 1, + // "state": "open", + // "self_trade": false, + // "reduce_only": false, + // "price": 0.04, + // "post_only": false, + // "order_type": "limit", + // "order_id": "ETH-334607", + // "matching_id": null, + // "liquidity": "M", + // "iv": 56.83, + // "instrument_name": "ETH-22FEB19-120-C", + // "index_price": 121.37, + // "fee_currency": "ETH", + // "fee": 0.0011, + // "direction": "buy", + // "amount": 11 + // }, + // ], + // "has_more": true + // } // } // - const trades = this.safeValue (response, 'result', []); + const result = this.safeValue (response, 'result', {}); + const trades = this.safeValue (result, 'trades', []); return this.parseTrades (trades, market, since, limit); } + async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { + if (code === undefined) { + throw new ArgumentsRequired (this.id + ' fetchDeposits() requires a currency code argument'); + } + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + }; + if (limit !== undefined) { + request['count'] = limit; + } + const response = await this.privateGetGetDeposits (this.extend (request, params)); + // + // { + // "jsonrpc": "2.0", + // "id": 5611, + // "result": { + // "count": 1, + // "data": [ + // { + // "address": "2N35qDKDY22zmJq9eSyiAerMD4enJ1xx6ax", + // "amount": 5, + // "currency": "BTC", + // "received_timestamp": 1549295017670, + // "state": "completed", + // "transaction_id": "230669110fdaf0a0dbcdc079b6b8b43d5af29cc73683835b9bc6b3406c065fda", + // "updated_timestamp": 1549295130159 + // } + // ] + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const data = this.safeValue (result, 'data', []); + return this.parseTransactions (data, currency, since, limit, params); + } + + async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { + if (code === undefined) { + throw new ArgumentsRequired (this.id + ' fetchWithdrawals() requires a currency code argument'); + } + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + }; + if (limit !== undefined) { + request['count'] = limit; + } + const response = await this.privateGetGetWithdrawals (this.extend (request, params)); + // + // { + // "jsonrpc": "2.0", + // "id": 2745, + // "result": { + // "count": 1, + // "data": [ + // { + // "address": "2NBqqD5GRJ8wHy1PYyCXTe9ke5226FhavBz", + // "amount": 0.5, + // "confirmed_timestamp": null, + // "created_timestamp": 1550571443070, + // "currency": "BTC", + // "fee": 0.0001, + // "id": 1, + // "priority": 0.15, + // "state": "unconfirmed", + // "transaction_id": null, + // "updated_timestamp": 1550571443070 + // } + // ] + // } + // } + // + const result = this.safeValue (response, 'result', {}); + const data = this.safeValue (result, 'data', []); + return this.parseTransactions (data, currency, since, limit, params); + } + + parseTransactionStatus (status) { + const statuses = { + 'completed': 'ok', + 'unconfirmed': 'pending', + }; + return this.safeString (statuses, status, status); + } + + parseTransaction (transaction, currency = undefined) { + // + // fetchWithdrawals + // + // { + // "address": "2NBqqD5GRJ8wHy1PYyCXTe9ke5226FhavBz", + // "amount": 0.5, + // "confirmed_timestamp": null, + // "created_timestamp": 1550571443070, + // "currency": "BTC", + // "fee": 0.0001, + // "id": 1, + // "priority": 0.15, + // "state": "unconfirmed", + // "transaction_id": null, + // "updated_timestamp": 1550571443070 + // } + // + // fetchDeposits + // + // { + // "address": "2N35qDKDY22zmJq9eSyiAerMD4enJ1xx6ax", + // "amount": 5, + // "currency": "BTC", + // "received_timestamp": 1549295017670, + // "state": "completed", + // "transaction_id": "230669110fdaf0a0dbcdc079b6b8b43d5af29cc73683835b9bc6b3406c065fda", + // "updated_timestamp": 1549295130159 + // } + // + const currencyId = this.safeString (transaction, 'currency'); + const code = this.safeCurrencyCode (currencyId, currency); + const timestamp = this.safeInteger2 (transaction, 'created_timestamp', 'received_timestamp'); + const updated = this.safeInteger (transaction, 'updated_timestamp'); + const status = this.parseTransactionStatus (this.safeString (transaction, 'state')); + const address = this.safeString (transaction, 'address'); + const feeCost = this.safeFloat (transaction, 'fee'); + let type = 'deposit'; + let fee = undefined; + if (feeCost !== undefined) { + type = 'withdrawal'; + fee = { + 'cost': feeCost, + 'currency': code, + }; + } + return { + 'info': transaction, + 'id': this.safeString (transaction, 'id'), + 'txid': this.safeString (transaction, 'transaction_id'), + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'address': address, + 'addressTo': address, + 'addressFrom': undefined, + 'tag': undefined, + 'tagTo': undefined, + 'tagFrom': undefined, + 'type': type, + 'amount': this.safeFloat (transaction, 'amount'), + 'currency': code, + 'status': status, + 'updated': updated, + 'fee': fee, + }; + } + + async withdraw (code, amount, address, tag = undefined, params = {}) { + this.checkAddress (address); + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + 'address': address, // must be in the address book + 'amount': amount, + // 'priority': 'high', // low, mid, high, very_high, extreme_high, insane + // 'tfa': '123456', // if enabled + }; + if (this.twofa !== undefined) { + request['tfa'] = this.oath (); + } + const response = await this.privateGetWithdraw (this.extend (request, params)); + return { + 'info': response, + 'id': this.safeString (response, 'id'), + }; + } + nonce () { return this.milliseconds (); } sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - const query = '/' + 'api/' + this.version + '/' + api + '/' + path; - let url = this.urls['api'] + query; + let request = '/' + 'api/' + this.version + '/' + api + '/' + path; if (api === 'public') { if (Object.keys (params).length) { - url += '?' + this.urlencode (params); - } - } else { - this.checkRequiredCredentials (); - const nonce = this.nonce ().toString (); - let auth = '_=' + nonce + '&_ackey=' + this.apiKey + '&_acsec=' + this.secret + '&_action=' + query; - if (Object.keys (params).length) { - params = this.keysort (params); - auth += '&' + this.urlencode (params); - } - const hash = this.hash (this.encode (auth), 'sha256', 'base64'); - const signature = this.apiKey + '.' + nonce + '.' + this.decode (hash); - headers = { - 'x-deribit-sig': signature, - }; - if (method !== 'GET') { - headers['Content-Type'] = 'application/x-www-form-urlencoded'; - body = this.urlencode (params); - } else if (Object.keys (params).length) { - url += '?' + this.urlencode (params); + request += '?' + this.urlencode (params); } } + if (api === 'private') { + this.checkRequiredCredentials (); + const nonce = this.nonce ().toString (); + const timestamp = this.milliseconds ().toString (); + const requestBody = ''; + if (Object.keys (params).length) { + request += '?' + this.urlencode (params); + } + const requestData = method + "\n" + request + "\n" + requestBody + "\n"; // eslint-disable-line quotes + const auth = timestamp + "\n" + nonce + "\n" + requestData; // eslint-disable-line quotes + const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256'); + headers = { + 'Authorization': 'deri-hmac-sha256 id=' + this.apiKey + ',ts=' + timestamp + ',sig=' + signature + ',' + 'nonce=' + nonce, + }; + } + const url = this.urls['api'] + request; return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } @@ -748,12 +1688,24 @@ module.exports = class deribit extends Exchange { return; // fallback to default error handler } // - // {"usOut":1535877098645376,"usIn":1535877098643364,"usDiff":2012,"testnet":false,"success":false,"message":"order_not_found","error":10004} + // { + // jsonrpc: '2.0', + // error: { + // message: 'Invalid params', + // data: { reason: 'invalid currency', param: 'currency' }, + // code: -32602 + // }, + // testnet: false, + // usIn: 1583763842150374, + // usOut: 1583763842150410, + // usDiff: 36 + // } // - const error = this.safeString (response, 'error'); - if ((error !== undefined) && (error !== '0')) { + const error = this.safeValue (response, 'error'); + if (error !== undefined) { + const errorCode = this.safeString (error, 'code'); const feedback = this.id + ' ' + body; - this.throwExactlyMatchedException (this.exceptions, error, feedback); + this.throwExactlyMatchedException (this.exceptions, errorCode, feedback); throw new ExchangeError (feedback); // unknown message } } diff --git a/TaskServer/node_modules/ccxt/js/digifinex.js b/TaskServer/node_modules/ccxt/js/digifinex.js index ab6133e23..53c23d198 100644 --- a/TaskServer/node_modules/ccxt/js/digifinex.js +++ b/TaskServer/node_modules/ccxt/js/digifinex.js @@ -43,7 +43,7 @@ module.exports = class digifinex extends Exchange { 'doc': [ 'https://docs.digifinex.vip', ], - 'fees': 'https://digifinex.zendesk.com/hc/en-us/articles/360000328482-Fee-Structure-on-DigiFinex', + 'fees': 'https://digifinex.zendesk.com/hc/en-us/articles/360000328422-Fee-Structure-on-DigiFinex', 'referral': 'https://www.digifinex.vip/en-ww/from/DhOzBg/3798****5114', }, 'api': { @@ -100,6 +100,14 @@ module.exports = class digifinex extends Exchange { ], }, }, + 'fees': { + 'trading': { + 'tierBased': false, + 'percentage': true, + 'maker': 0.002, + 'taker': 0.002, + }, + }, 'exceptions': { 'exact': { '10001': [ BadRequest, "Wrong request method, please check it's a GET ot POST request" ], @@ -136,6 +144,9 @@ module.exports = class digifinex extends Exchange { 'defaultType': 'spot', 'types': [ 'spot', 'margin', 'otc' ], }, + 'commonCurrencies': { + 'BHT': 'Black House Test', + }, }); } @@ -838,6 +849,7 @@ module.exports = class digifinex extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -852,6 +864,7 @@ module.exports = class digifinex extends Exchange { 'average': average, 'status': status, 'fee': undefined, + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/dsx.js b/TaskServer/node_modules/ccxt/js/dsx.js index b37bcf6c3..b8aca2bbb 100644 --- a/TaskServer/node_modules/ccxt/js/dsx.js +++ b/TaskServer/node_modules/ccxt/js/dsx.js @@ -32,7 +32,7 @@ module.exports = class dsx extends Exchange { 'withdraw': true, }, 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/27990275-1413158a-645a-11e7-931c-94717f7510e3.jpg', + 'logo': 'https://user-images.githubusercontent.com/51840849/76909626-cb2bb100-68bc-11ea-99e0-28ba54f04792.jpg', 'api': { 'public': 'https://dsx.uk/mapi', // market data 'private': 'https://dsx.uk/tapi', // trading @@ -714,6 +714,9 @@ module.exports = class dsx extends Exchange { 'filled': filled, 'fee': undefined, // 'trades': this.parseTrades (order['trades'], market), + 'clientOrderId': undefined, + 'average': undefined, + 'trades': undefined, }; } @@ -825,6 +828,7 @@ module.exports = class dsx extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -839,6 +843,7 @@ module.exports = class dsx extends Exchange { 'status': status, 'fee': fee, 'trades': trades, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/exmo.js b/TaskServer/node_modules/ccxt/js/exmo.js index c354a0393..dcf0f2036 100644 --- a/TaskServer/node_modules/ccxt/js/exmo.js +++ b/TaskServer/node_modules/ccxt/js/exmo.js @@ -103,159 +103,185 @@ module.exports = class exmo extends Exchange { 'error': '', 'data': { 'limits': [ - { 'pair': 'BTC/USD', 'min_q': '0.001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'BTC/EUR', 'min_q': '0.001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'BTC/RUB', 'min_q': '0.001', 'max_q': '1000', 'min_p': '1', 'max_p': '2000000', 'min_a': '10', 'max_a': '50000000' }, - { 'pair': 'BTC/UAH', 'min_q': '0.001', 'max_q': '1000', 'min_p': '1', 'max_p': '1500000', 'min_a': '10', 'max_a': '15000000' }, - { 'pair': 'BTC/PLN', 'min_q': '0.001', 'max_q': '1000', 'min_p': '0.001', 'max_p': '90000', 'min_a': '1', 'max_a': '2000000' }, - { 'pair': 'BTC/TRY', 'min_q': '0.001', 'max_q': '1000', 'min_p': '1', 'max_p': '800000', 'min_a': '40', 'max_a': '6000000' }, - { 'pair': 'ROOBEE/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.0001', 'max_a': '10' }, - { 'pair': 'ROOBEE/ETH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'USDC/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'USDC/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '1000' }, - { 'pair': 'USDC/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'USDC/USDT', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'ETZ/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '10' }, - { 'pair': 'ETZ/ETH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'ETZ/USDT', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '1000' }, - { 'pair': 'PTI/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' }, - { 'pair': 'PTI/USDT', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' }, - { 'pair': 'PTI/EOS', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '5000', 'min_a': '0.01', 'max_a': '20000' }, - { 'pair': 'ATMCASH/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' }, - { 'pair': 'TRX/UAH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, - { 'pair': 'ETH/TRY', 'min_q': '0.01', 'max_q': '5000', 'min_p': '0.1', 'max_p': '80000', 'min_a': '10', 'max_a': '6000000' }, - { 'pair': 'XRP/TRY', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '6000000' }, - { 'pair': 'XLM/TRY', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '6000000' }, - { 'pair': 'MNC/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' }, - { 'pair': 'MNC/ETH', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '1000' }, - { 'pair': 'MNC/USD', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' }, - { 'pair': 'DAI/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'DAI/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '5000' }, - { 'pair': 'DAI/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'DAI/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '0.5', 'max_a': '30000000' }, - { 'pair': 'MKR/BTC', 'min_q': '0.001', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.000001', 'max_a': '100' }, - { 'pair': 'MKR/DAI', 'min_q': '0.001', 'max_q': '1000', 'min_p': '0.5', 'max_p': '500000', 'min_a': '0.005', 'max_a': '500000' }, - { 'pair': 'QTUM/BTC', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'QTUM/ETH', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' }, - { 'pair': 'QTUM/USD', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '10000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'HB/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' }, - { 'pair': 'SMART/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'SMART/USD', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'SMART/EUR', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'SMART/RUB', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '10', 'max_a': '50000000' }, - { 'pair': 'XEM/BTC', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00015', 'max_a': '100' }, - { 'pair': 'XEM/USD', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'XEM/EUR', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'GUSD/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' }, - { 'pair': 'GUSD/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'GUSD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' }, - { 'pair': 'LSK/BTC', 'min_q': '1', 'max_q': '200000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' }, - { 'pair': 'LSK/USD', 'min_q': '1', 'max_q': '200000', 'min_p': '0.1', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'LSK/RUB', 'min_q': '1', 'max_q': '200000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '50000000' }, - { 'pair': 'NEO/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'NEO/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'NEO/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1500000', 'min_a': '50', 'max_a': '50000000' }, - { 'pair': 'ADA/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'ADA/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'ADA/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000' }, - { 'pair': 'ZRX/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'ZRX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, - { 'pair': 'GNT/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'GNT/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, - { 'pair': 'TRX/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'TRX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'TRX/RUB', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, - { 'pair': 'GAS/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'GAS/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'INK/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'INK/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000' }, - { 'pair': 'INK/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'MNX/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'MNX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, - { 'pair': 'MNX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, - { 'pair': 'OMG/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'OMG/ETH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, - { 'pair': 'OMG/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, - { 'pair': 'XLM/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'XLM/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'XLM/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, - { 'pair': 'EOS/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'EOS/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, - { 'pair': 'BTG/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'BTG/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'DXT/BTC', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'DXT/USD', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'BTCZ/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.1', 'max_a': '100' }, - { 'pair': 'BCH/BTC', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '5', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'BCH/USD', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '30000', 'min_a': '0.0001', 'max_a': '500000' }, - { 'pair': 'BCH/RUB', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '2000000', 'min_a': '0.0001', 'max_a': '50000000' }, - { 'pair': 'BCH/ETH', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.0000001', 'max_p': '200', 'min_a': '0.0001', 'max_a': '5000' }, - { 'pair': 'DASH/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'DASH/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'DASH/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, + { 'pair': 'EXM/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, + { 'pair': 'EXM/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' }, + { 'pair': 'BTC/USD', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'BTC/KZT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1000', 'max_p': '12000000', 'min_a': '1000', 'max_a': '100000000' }, + { 'pair': 'ETH/KZT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '4', 'max_p': '40000000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'USDT/KZT', 'min_q': '1', 'max_q': '500000', 'min_p': '200', 'max_p': '4000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'ONT/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '15000000' }, + { 'pair': 'ONT/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' }, + { 'pair': 'ONT/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '6000000' }, + { 'pair': 'ONT/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '250000' }, + { 'pair': 'ONG/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '15000000' }, + { 'pair': 'ONG/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' }, + { 'pair': 'ONG/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '250000' }, + { 'pair': 'ONG/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '6000000' }, + { 'pair': 'CRON/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'CRON/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' }, + { 'pair': 'CRON/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, + { 'pair': 'CRON/EXM', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, + { 'pair': 'BTC/RUB', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '2000000', 'min_a': '10', 'max_a': '50000000' }, + { 'pair': 'BTC/EUR', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'BTC/UAH', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '15000000', 'min_a': '10', 'max_a': '15000000' }, + { 'pair': 'BTC/PLN', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '20000000', 'min_a': '50', 'max_a': '2000000' }, + { 'pair': 'BTC/TRY', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '800000', 'min_a': '40', 'max_a': '6000000' }, + { 'pair': 'BTC/USDT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.01', 'max_p': '30000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'ETH/BTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'ETH/LTC', 'min_q': '0.01', 'max_q': '5000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '100000' }, - { 'pair': 'ETH/USD', 'min_q': '0.01', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'ETH/EUR', 'min_q': '0.01', 'max_q': '5000', 'min_p': '0.001', 'max_p': '10000', 'min_a': '1', 'max_a': '500000' }, - { 'pair': 'ETH/RUB', 'min_q': '0.01', 'max_q': '5000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '1', 'max_a': '50000000' }, - { 'pair': 'ETH/UAH', 'min_q': '0.01', 'max_q': '5000', 'min_p': '0.01', 'max_p': '1000000', 'min_a': '90', 'max_a': '15000000' }, - { 'pair': 'ETH/PLN', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.001', 'max_p': '8000', 'min_a': '1', 'max_a': '2000000' }, - { 'pair': 'ETC/BTC', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '0.5', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'ETC/USD', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'ETC/RUB', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '50000000' }, - { 'pair': 'LTC/BTC', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'LTC/USD', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'LTC/EUR', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'LTC/RUB', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, - { 'pair': 'ZEC/BTC', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'ZEC/USD', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'ZEC/EUR', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'ZEC/RUB', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'ETH/USD', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'ETH/RUB', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, { 'pair': 'XRP/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, { 'pair': 'XRP/USD', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, { 'pair': 'XRP/RUB', 'min_q': '1', 'max_q': '100000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '50000000' }, - { 'pair': 'XMR/BTC', 'min_q': '0.03', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'XMR/USD', 'min_q': '0.03', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'XMR/EUR', 'min_q': '0.03', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'BTC/USDT', 'min_q': '0.001', 'max_q': '1000', 'min_p': '0.01', 'max_p': '30000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'ETH/USDT', 'min_q': '0.01', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'USDT/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'USDT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' }, - { 'pair': 'USD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' }, - { 'pair': 'DOGE/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'WAVES/BTC', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, - { 'pair': 'WAVES/RUB', 'min_q': '0.5', 'max_q': '10000', 'min_p': '1', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' }, - { 'pair': 'KICK/BTC', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'KICK/ETH', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' }, - { 'pair': 'KICK/USDT', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, - { 'pair': 'EOS/EUR', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'ADA/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ADA/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000' }, + { 'pair': 'ADA/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'BCH/USD', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '30000', 'min_a': '0.0001', 'max_a': '500000' }, + { 'pair': 'BCH/RUB', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '2000000', 'min_a': '0.0001', 'max_a': '50000000' }, { 'pair': 'BCH/EUR', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'XRP/EUR', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, - { 'pair': 'XRP/UAH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '15000000' }, - { 'pair': 'XEM/UAH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' }, - { 'pair': 'BCH/USDT', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' }, - { 'pair': 'DASH/USDT', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' }, { 'pair': 'BCH/UAH', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.1', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' }, - { 'pair': 'XRP/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, - { 'pair': 'USDT/UAH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '1', 'max_p': '3000', 'min_a': '2', 'max_a': '15000000' }, - { 'pair': 'USDT/EUR', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, - { 'pair': 'ZRX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'BCH/BTC', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '5', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'BCH/ETH', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.0000001', 'max_p': '200', 'min_a': '0.0001', 'max_a': '5000' }, + { 'pair': 'BCH/USDT', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'BTCZ/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'BTG/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'BTG/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, { 'pair': 'BTG/ETH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.01', 'max_a': '5000' }, - { 'pair': 'WAVES/USD', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.001', 'max_p': '3500', 'min_a': '0.5', 'max_a': '500000' }, - { 'pair': 'DOGE/USD', 'min_q': '100', 'max_q': '1000000000', 'min_p': '0.0000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, - { 'pair': 'XRP/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' }, - { 'pair': 'DASH/UAH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '200000', 'min_a': '10', 'max_a': '15000000' }, - { 'pair': 'XMR/ETH', 'min_q': '0.03', 'max_q': '1000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' }, - { 'pair': 'WAVES/ETH', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.00001', 'max_p': '30', 'min_a': '0.0035', 'max_a': '3500' }, - { 'pair': 'DCR/BTC', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, - { 'pair': 'DCR/RUB', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '3000000' }, - { 'pair': 'DCR/UAH', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.25', 'max_a': '1000000' }, - { 'pair': 'ZAG/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'EXM/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0000001', 'max_a': '100' }, - { 'pair': 'VLX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, - { 'pair': 'BTT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, { 'pair': 'BTT/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' }, { 'pair': 'BTT/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' }, + { 'pair': 'BTT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'DAI/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'DAI/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '0.5', 'max_a': '30000000' }, + { 'pair': 'DAI/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'DAI/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '5000' }, + { 'pair': 'DASH/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'DASH/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, + { 'pair': 'DASH/UAH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '200000', 'min_a': '10', 'max_a': '15000000' }, + { 'pair': 'DASH/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'DASH/USDT', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'DCR/RUB', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '3000000' }, + { 'pair': 'DCR/UAH', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.25', 'max_a': '1000000' }, + { 'pair': 'DCR/BTC', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'DOGE/USD', 'min_q': '100', 'max_q': '1000000000', 'min_p': '0.0000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'DOGE/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'DXT/USD', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'DXT/BTC', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'EOS/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'EOS/EUR', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'EOS/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ETC/USD', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'ETC/RUB', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '50000000' }, + { 'pair': 'ETC/BTC', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '0.5', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ETH/EUR', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'ETH/UAH', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '1000000', 'min_a': '90', 'max_a': '15000000' }, + { 'pair': 'ETH/PLN', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '2000000' }, + { 'pair': 'ETH/TRY', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.1', 'max_p': '80000', 'min_a': '10', 'max_a': '6000000' }, + { 'pair': 'ETH/USDT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'ETH/LTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '100000', 'min_a': '0.05', 'max_a': '100000' }, + { 'pair': 'ETZ/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '10' }, + { 'pair': 'ETZ/ETH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ETZ/USDT', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '1000' }, + { 'pair': 'GAS/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'GAS/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'GNT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'GNT/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, + { 'pair': 'GUSD/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'GUSD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' }, + { 'pair': 'GUSD/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' }, + { 'pair': 'HP/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'HB/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' }, + { 'pair': 'INK/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'INK/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'INK/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000' }, + { 'pair': 'KICK/RUB', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' }, + { 'pair': 'KICK/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' }, + { 'pair': 'KICK/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'KICK/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' }, + { 'pair': 'LSK/USD', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.1', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'LSK/RUB', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '50000000' }, + { 'pair': 'LSK/BTC', 'min_q': '1', 'max_q': '200000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' }, + { 'pair': 'LTC/USD', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'LTC/RUB', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' }, + { 'pair': 'LTC/EUR', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'LTC/UAH', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '5', 'max_a': '18000000' }, + { 'pair': 'LTC/BTC', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'MKR/BTC', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.000001', 'max_a': '100' }, + { 'pair': 'MKR/DAI', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.5', 'max_p': '500000', 'min_a': '0.005', 'max_a': '500000' }, + { 'pair': 'MNC/USD', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' }, + { 'pair': 'MNC/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' }, + { 'pair': 'MNC/ETH', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '1000' }, + { 'pair': 'MNX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'MNX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'MNX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, + { 'pair': 'NEO/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'NEO/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1500000', 'min_a': '50', 'max_a': '50000000' }, + { 'pair': 'NEO/BTC', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'OMG/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'OMG/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'OMG/ETH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, + { 'pair': 'PTI/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '600000', 'min_a': '10', 'max_a': '600000' }, + { 'pair': 'PTI/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' }, + { 'pair': 'PTI/EOS', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '5000', 'min_a': '0.01', 'max_a': '20000' }, + { 'pair': 'PTI/USDT', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' }, + { 'pair': 'QTUM/USD', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '10000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'QTUM/BTC', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'QTUM/ETH', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' }, + { 'pair': 'ROOBEE/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'SMART/USD', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'SMART/RUB', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '100000', 'min_a': '10', 'max_a': '50000000' }, + { 'pair': 'SMART/EUR', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' }, + { 'pair': 'SMART/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'TRX/USD', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'TRX/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'TRX/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'TRX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'USDC/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'USDC/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'USDC/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '1000' }, + { 'pair': 'USDC/USDT', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' }, + { 'pair': 'USDT/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'USDT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' }, + { 'pair': 'USDT/EUR', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'USDT/UAH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '1', 'max_p': '3000', 'min_a': '2', 'max_a': '15000000' }, + { 'pair': 'VLX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'WAVES/USD', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.001', 'max_p': '3500', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'WAVES/RUB', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' }, + { 'pair': 'WAVES/BTC', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' }, + { 'pair': 'WAVES/ETH', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.00001', 'max_p': '30', 'min_a': '0.0035', 'max_a': '3500' }, + { 'pair': 'XEM/USD', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'XEM/EUR', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'XEM/UAH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' }, + { 'pair': 'XEM/BTC', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00015', 'max_a': '100' }, + { 'pair': 'XLM/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' }, + { 'pair': 'XLM/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'XLM/TRY', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '6000000' }, + { 'pair': 'XLM/BTC', 'min_q': '1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'XMR/USD', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'XMR/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '600000', 'min_a': '10', 'max_a': '16000000' }, + { 'pair': 'XMR/EUR', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'XMR/UAH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '300000', 'min_a': '5', 'max_a': '16000000' }, + { 'pair': 'XMR/BTC', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'XMR/ETH', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' }, + { 'pair': 'XRP/EUR', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, + { 'pair': 'XRP/TRY', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '6000000' }, + { 'pair': 'XRP/UAH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '15000000' }, + { 'pair': 'XRP/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' }, + { 'pair': 'XRP/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' }, + { 'pair': 'XTZ/USD', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '100000' }, + { 'pair': 'XTZ/RUB', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '500000' }, + { 'pair': 'XTZ/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' }, + { 'pair': 'XTZ/ETH', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '1000' }, + { 'pair': 'ZEC/USD', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'ZEC/RUB', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' }, + { 'pair': 'ZEC/EUR', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'ZEC/BTC', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.00001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ZRX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' }, + { 'pair': 'ZRX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' }, + { 'pair': 'ZRX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' }, + { 'pair': 'ZAG/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' }, + { 'pair': 'USD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' }, + { 'pair': 'EXM/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0000001', 'max_a': '1' }, + { 'pair': 'ATMCASH/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' }, ], 'fees': [ { @@ -308,75 +334,79 @@ module.exports = class exmo extends Exchange { { 'prov': 'ZAG', 'dep': '0%', 'wd': '0%' }, { 'prov': 'BTT', 'dep': '0%', 'wd': '100 BTT' }, { 'prov': 'VLX', 'dep': '0%', 'wd': '1 VLX' }, + { 'prov': 'CRON', 'dep': '0%', 'wd': '5 CRON' }, + { 'prov': 'ONT', 'dep': '0%', 'wd': '1 ONT' }, + { 'prov': 'ONG', 'dep': '0%', 'wd': '5 ONG' }, ], }, { 'group': 'usd', 'title': 'USD', 'items': [ - { 'prov': 'Payeer', 'dep': '3.95%', 'wd': '-' }, { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, - { 'prov': 'Perfect Money', 'dep': '-', 'wd': '0.5%' }, - { 'prov': 'AdvCash', 'dep': '3.45%', 'wd': '2.95%' }, + { 'prov': 'Payeer', 'dep': '3.95%', 'wd': '-' }, + { 'prov': 'AdvCash', 'dep': '0%', 'wd': '3.99%' }, + { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 0.5 USD', 'wd': '-' }, { 'prov': 'Visa', 'dep': '3.45%', 'wd': '-' }, - { 'prov': 'CryptoCapital', 'dep': '-', 'wd': '0.45%' }, - { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5%', 'wd': '-' }, ], }, { 'group': 'eur', 'title': 'EUR', 'items': [ - { 'prov': 'Visa', 'dep': '3.45%', 'wd': '-' }, - { 'prov': 'CryptoCapital', 'dep': '-', 'wd': '0.45%' }, - { 'prov': 'AdvCash', 'dep': '0.45%', 'wd': '-' }, - { 'prov': 'Wire Transfer', 'dep': '6.95 EUR', 'wd': '-' }, - { 'prov': 'SEPA', 'dep': '6.95 EUR', 'wd': '-' }, - { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5%', 'wd': '-' }, - { 'prov': 'Payeer', 'dep': '3.95%', 'wd': '-' }, { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, + { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 0.5 EUR', 'wd': '-' }, + { 'prov': 'Visa', 'dep': '2.95%', 'wd': '-' }, + { 'prov': 'SEPA', 'dep': '10 EUR', 'wd': '50 EUR' }, ], }, { 'group': 'rub', 'title': 'RUB', 'items': [ - { 'prov': 'Yandex Money', 'dep': '2.95%', 'wd': '1.95%' }, - { 'prov': 'Payeer', 'dep': '3.95%', 'wd': '-' }, - { 'prov': 'AdvCash', 'dep': '3.95%', 'wd': '0.95%' }, - { 'prov': 'Qiwi', 'dep': '3.95%', 'wd': '2.95%' }, - { 'prov': 'Visa/MasterCard', 'dep': '3.95%', 'wd': '4.95% + 60 RUB' }, - { 'prov': 'WebMoney', 'dep': '-', 'wd': '3.5%' }, + { 'prov': 'Payeer', 'dep': '2.49%', 'wd': '-' }, { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, + { 'prov': 'Qiwi', 'dep': '0.99%', 'wd': '2%' }, + { 'prov': 'Yandex Money', 'dep': '1.95%', 'wd': '-' }, + { 'prov': 'Enfins', 'dep': '0%', 'wd': '1.49%' }, + { 'prov': 'AdvCash', 'dep': '0%', 'wd': '2.49%' }, + { 'prov': 'Visa/MasterCard', 'dep': '1.99%', 'wd': '4.49% + 60 RUB' }, ], }, { 'group': 'pln', 'title': 'PLN', 'items': [ - { 'prov': 'CryptoCapital', 'dep': '-', 'wd': '0.45%' }, - { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5%', 'wd': '-' }, { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, + { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 1 PLN', 'wd': '-' }, ], }, { 'group': 'try', 'title': 'TRY', 'items': [ - { 'prov': 'QR ile yatırma', 'dep': '5.95%', 'wd': '-' }, - { 'prov': 'Visa', 'dep': '3.45%', 'wd': '-' }, { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, + { 'prov': 'Visa', 'dep': '3.05%', 'wd': '-' }, + { 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 2 TRY', 'wd': '-' }, ], }, { 'group': 'uah', 'title': 'UAH', 'items': [ - { 'prov': 'Terminal', 'dep': '2.6%', 'wd': '-' }, { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' }, - { 'prov': 'AdvCash', 'dep': '-', 'wd': '2.95%' }, - { 'prov': 'Visa/MasterCard', 'dep': '2.6%', 'wd': '3.95% + 20 UAH' }, + { 'prov': 'Terminal', 'dep': '2.6%', 'wd': '-' }, { 'prov': 'Enfins', 'dep': '0%', 'wd': '1.95%' }, + { 'prov': 'Visa/MasterCard', 'dep': '1% + 5 UAH', 'wd': '2.99%' }, + ], + }, + { + 'group': 'kzt', + 'title': 'KZT', + 'items': [ + { 'prov': 'Visa/MasterCard RoyalPay', 'dep': '-', 'wd': '2.99% + 450 KZT' }, + { 'prov': 'Visa/MasterCard', 'dep': '3.5%', 'wd': '-' }, + { 'prov': 'AdvCash', 'dep': '0%', 'wd': '1.49%' }, ], }, ], @@ -390,6 +420,7 @@ module.exports = class exmo extends Exchange { '40015': ExchangeError, // API function do not exist '40016': OnMaintenance, // {"result":false,"error":"Error 40016: Maintenance work in progress"} '40017': AuthenticationError, // Wrong API Key + '40034': RateLimitExceeded, // {"result":false,"error":"Error 40034: Access is denied, rate limit is exceeded"} '50052': InsufficientFunds, '50054': InsufficientFunds, '50304': OrderNotFound, // "Order was not found '123456789'" (fetching order trades for an order that does not have trades yet) @@ -869,6 +900,8 @@ module.exports = class exmo extends Exchange { 'filled': 0.0, 'fee': undefined, 'trades': undefined, + 'clientOrderId': undefined, + 'average': undefined, }; this.orders[id] = order; return order; @@ -1136,6 +1169,7 @@ module.exports = class exmo extends Exchange { }; return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': lastTradeTimestamp, diff --git a/TaskServer/node_modules/ccxt/js/exx.js b/TaskServer/node_modules/ccxt/js/exx.js index 0fd106329..545adaabb 100644 --- a/TaskServer/node_modules/ccxt/js/exx.js +++ b/TaskServer/node_modules/ccxt/js/exx.js @@ -272,6 +272,20 @@ module.exports = class exx extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "fees": 0, + // "total_amount": 1, + // "trade_amount": 0, + // "price": 30, + // "currency": “eth_hsr", + // "id": "13878", + // "trade_money": 0, + // "type": "buy", + // "trade_date": 1509728897772, + // "status": 0 + // } + // const symbol = market['symbol']; const timestamp = parseInt (order['trade_date']); const price = this.safeFloat (order, 'price'); @@ -296,6 +310,7 @@ module.exports = class exx extends Exchange { } return { 'id': this.safeString (order, 'id'), + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -311,6 +326,7 @@ module.exports = class exx extends Exchange { 'trades': undefined, 'fee': fee, 'info': order, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/fcoin.js b/TaskServer/node_modules/ccxt/js/fcoin.js index 692eca143..871186527 100644 --- a/TaskServer/node_modules/ccxt/js/fcoin.js +++ b/TaskServer/node_modules/ccxt/js/fcoin.js @@ -514,6 +514,22 @@ module.exports = class fcoin extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "id": "string", + // "symbol": "string", + // "type": "limit", + // "side": "buy", + // "price": "string", + // "amount": "string", + // "state": "submitted", + // "executed_value": "string", + // "fill_fees": "string", + // "filled_amount": "string", + // "created_at": 0, + // "source": "web" + // } + // const id = this.safeString (order, 'id'); const side = this.safeString (order, 'side'); const status = this.parseOrderStatus (this.safeString (order, 'state')); @@ -562,6 +578,7 @@ module.exports = class fcoin extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, diff --git a/TaskServer/node_modules/ccxt/js/flowbtc.js b/TaskServer/node_modules/ccxt/js/flowbtc.js index 0658415ca..d4ca90c05 100644 --- a/TaskServer/node_modules/ccxt/js/flowbtc.js +++ b/TaskServer/node_modules/ccxt/js/flowbtc.js @@ -16,7 +16,7 @@ module.exports = class flowbtc extends Exchange { 'version': 'v1', 'rateLimit': 1000, 'has': { - 'CORS': true, + 'CORS': false, }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/28162465-cd815d4c-67cf-11e7-8e57-438bea0523a2.jpg', @@ -108,6 +108,7 @@ module.exports = class flowbtc extends Exchange { }, }, 'info': market, + 'active': undefined, }; } return result; @@ -197,6 +198,8 @@ module.exports = class flowbtc extends Exchange { 'price': price, 'amount': amount, 'cost': cost, + 'takerOrMaker': undefined, + 'fee': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/ftx.js b/TaskServer/node_modules/ccxt/js/ftx.js index 0af5d417e..8237d20e1 100644 --- a/TaskServer/node_modules/ccxt/js/ftx.js +++ b/TaskServer/node_modules/ccxt/js/ftx.js @@ -16,10 +16,14 @@ module.exports = class ftx extends Exchange { 'countries': [ 'HK' ], 'rateLimit': 100, 'certified': true, + 'pro': true, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/67149189-df896480-f2b0-11e9-8816-41593e17f9ec.jpg', 'www': 'https://ftx.com', - 'api': 'https://ftx.com', + 'api': { + 'public': 'https://ftx.com', + 'private': 'https://ftx.com', + }, 'doc': 'https://github.com/ftexchange/ftx', 'fees': 'https://ftexchange.zendesk.com/hc/en-us/articles/360024479432-Fees', 'referral': 'https://ftx.com/#a=1623029', @@ -159,6 +163,19 @@ module.exports = class ftx extends Exchange { }, }, 'precisionMode': TICK_SIZE, + 'options': { + // support for canceling conditional orders + // https://github.com/ccxt/ccxt/issues/6669 + 'cancelOrder': { + 'method': 'privateDeleteOrdersOrderId', // privateDeleteConditionalOrdersOrderId + }, + 'fetchOpenOrders': { + 'method': 'privateGetOrders', // privateGetConditionalOrders + }, + 'fetchOrders': { + 'method': 'privateGetOrdersHistory', // privateGetConditionalOrdersHistory + }, + }, }); } @@ -334,14 +351,16 @@ module.exports = class ftx extends Exchange { } else { const base = this.safeCurrencyCode (this.safeString (ticker, 'baseCurrency')); const quote = this.safeCurrencyCode (this.safeString (ticker, 'quoteCurrency')); - symbol = base + '/' + quote; + if ((base !== undefined) && (quote !== undefined)) { + symbol = base + '/' + quote; + } } } if ((symbol === undefined) && (market !== undefined)) { symbol = market['symbol']; } const last = this.safeFloat (ticker, 'last'); - const timestamp = this.milliseconds (); + const timestamp = this.safeTimestamp (ticker, 'time', this.milliseconds ()); return { 'symbol': symbol, 'timestamp': timestamp, @@ -349,9 +368,9 @@ module.exports = class ftx extends Exchange { 'high': this.safeFloat (ticker, 'high'), 'low': this.safeFloat (ticker, 'low'), 'bid': this.safeFloat (ticker, 'bid'), - 'bidVolume': undefined, + 'bidVolume': this.safeFloat (ticker, 'bidSize'), 'ask': this.safeFloat (ticker, 'ask'), - 'askVolume': undefined, + 'askVolume': this.safeFloat (ticker, 'askSize'), 'vwap': undefined, 'open': undefined, 'close': last, @@ -502,11 +521,16 @@ module.exports = class ftx extends Exchange { 'market_name': market['id'], 'resolution': this.timeframes[timeframe], }; - if (limit !== undefined) { + // max 1501 candles, including the current candle when since is not specified + limit = (limit === undefined) ? 1501 : limit; + if (since === undefined) { + request['end_time'] = this.seconds (); request['limit'] = limit; - } - if (since !== undefined) { + request['start_time'] = request['end_time'] - limit * this.parseTimeframe (timeframe); + } else { request['start_time'] = parseInt (since / 1000); + request['limit'] = limit; + request['end_time'] = this.sum (request['start_time'], limit * this.parseTimeframe (timeframe)); } const response = await this.publicGetMarketsMarketNameCandles (this.extend (request, params)); // @@ -756,7 +780,7 @@ module.exports = class ftx extends Exchange { parseOrder (order, market = undefined) { // - // fetchOrder, fetchOrders, fetchOpenOrders, createOrder ("limit", "market") + // limit orders - fetchOrder, fetchOrders, fetchOpenOrders, createOrder // // { // "createdAt": "2019-03-05T09:56:55.728933+00:00", @@ -776,6 +800,27 @@ module.exports = class ftx extends Exchange { // "clientId": null, // } // + // market orders - fetchOrder, fetchOrders, fetchOpenOrders, createOrder + // + // { + // "avgFillPrice": 2666.0, + // "clientId": None, + // "createdAt": "2020-02-12T00: 53: 49.009726+00: 00", + // "filledSize": 0.0007, + // "future": None, + // "id": 3109208514, + // "ioc": True, + // "market": "BNBBULL/USD", + // "postOnly": False, + // "price": None, + // "reduceOnly": False, + // "remainingSize": 0.0, + // "side": "buy", + // "size": 0.0007, + // "status": "closed", + // "type": "market" + // } + // // createOrder (conditional, "stop", "trailingStop", or "takeProfit") // // { @@ -812,15 +857,18 @@ module.exports = class ftx extends Exchange { const side = this.safeString (order, 'side'); const type = this.safeString (order, 'type'); const amount = this.safeFloat (order, 'size'); + const average = this.safeFloat (order, 'avgFillPrice'); + const price = this.safeFloat2 (order, 'price', 'triggerPrice', average); let cost = undefined; - if (filled !== undefined && amount !== undefined) { - cost = filled * amount; + if (filled !== undefined && price !== undefined) { + cost = filled * price; } - const price = this.safeFloat2 (order, 'price', 'triggerPrice'); const lastTradeTimestamp = this.parse8601 (this.safeString (order, 'triggeredAt')); + const clientOrderId = this.safeString (order, 'clientId'); return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -830,7 +878,7 @@ module.exports = class ftx extends Exchange { 'price': price, 'amount': amount, 'cost': cost, - 'average': undefined, + 'average': average, 'filled': filled, 'remaining': remaining, 'status': status, @@ -933,7 +981,17 @@ module.exports = class ftx extends Exchange { const request = { 'order_id': parseInt (id), }; - const response = await this.privateDeleteOrdersOrderId (this.extend (request, params)); + // support for canceling conditional orders + // https://github.com/ccxt/ccxt/issues/6669 + const options = this.safeValue (this.options, 'cancelOrder', {}); + const defaultMethod = this.safeString (options, 'method', 'privateDeleteOrdersOrderId'); + let method = this.safeString (params, 'method', defaultMethod); + const type = this.safeValue (params, 'type'); + if ((type === 'stop') || (type === 'trailingStop') || (type === 'takeProfit')) { + method = 'privateDeleteConditionalOrdersOrderId'; + } + const query = this.omit (params, [ 'method', 'type' ]); + const response = await this[method] (this.extend (request, query)); // // { // "success": true, @@ -1008,7 +1066,17 @@ module.exports = class ftx extends Exchange { market = this.market (symbol); request['market'] = market['id']; } - const response = await this.privateGetOrders (this.extend (request, params)); + // support for canceling conditional orders + // https://github.com/ccxt/ccxt/issues/6669 + const options = this.safeValue (this.options, 'fetchOpenOrders', {}); + const defaultMethod = this.safeString (options, 'method', 'privateGetOrders'); + let method = this.safeString (params, 'method', defaultMethod); + const type = this.safeValue (params, 'type'); + if ((type === 'stop') || (type === 'trailingStop') || (type === 'takeProfit')) { + method = 'privateGetConditionalOrders'; + } + const query = this.omit (params, [ 'method', 'type' ]); + const response = await this[method] (this.extend (request, query)); // // { // "success": true, @@ -1052,7 +1120,17 @@ module.exports = class ftx extends Exchange { if (since !== undefined) { request['start_time'] = parseInt (since / 1000); } - const response = await this.privateGetOrdersHistory (this.extend (request, params)); + // support for canceling conditional orders + // https://github.com/ccxt/ccxt/issues/6669 + const options = this.safeValue (this.options, 'fetchOrders', {}); + const defaultMethod = this.safeString (options, 'method', 'privateGetOrdersHistory'); + let method = this.safeString (params, 'method', defaultMethod); + const type = this.safeValue (params, 'type'); + if ((type === 'stop') || (type === 'trailingStop') || (type === 'takeProfit')) { + method = 'privateGetConditionalOrdersHistory'; + } + const query = this.omit (params, [ 'method', 'type' ]); + const response = await this[method] (this.extend (request, query)); // // { // "success": true, @@ -1309,7 +1387,7 @@ module.exports = class ftx extends Exchange { sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { let request = '/api/' + this.implodeParams (path, params); const query = this.omit (params, this.extractParams (path)); - let url = this.urls['api'] + request; + let url = this.urls['api'][api] + request; if (method !== 'POST') { if (Object.keys (query).length) { const suffix = '?' + this.urlencode (query); diff --git a/TaskServer/node_modules/ccxt/js/gateio.js b/TaskServer/node_modules/ccxt/js/gateio.js index e28bd238e..dd9389e9e 100644 --- a/TaskServer/node_modules/ccxt/js/gateio.js +++ b/TaskServer/node_modules/ccxt/js/gateio.js @@ -15,6 +15,7 @@ module.exports = class gateio extends Exchange { 'countries': [ 'CN' ], 'version': '2', 'rateLimit': 1000, + 'pro': true, 'has': { 'CORS': false, 'createMarketOrder': false, @@ -68,6 +69,7 @@ module.exports = class gateio extends Exchange { 'pairs', 'marketinfo', 'marketlist', + 'coininfo', 'tickers', 'ticker/{id}', 'orderBook/{id}', @@ -89,6 +91,7 @@ module.exports = class gateio extends Exchange { 'getOrder', 'openOrders', 'tradeHistory', + 'feelist', 'withdraw', ], }, @@ -152,6 +155,10 @@ module.exports = class gateio extends Exchange { }, }, }, + 'commonCurrencies': { + 'BTCBEAR': 'BEAR', + 'BTCBULL': 'BULL', + }, }); } @@ -373,6 +380,18 @@ module.exports = class gateio extends Exchange { } parseTrade (trade, market = undefined) { + // { + // "tradeID": 3175762, + // "date": "2017-08-25 07:24:28", + // "type": "sell", + // "rate": 29011, + // "amount": 0.0019, + // "total": 55.1209, + // "fee": "0", + // "fee_coin": "btc", + // "gt_fee":"0", + // "point_fee":"0.1213", + // }, let timestamp = this.safeTimestamp2 (trade, 'timestamp', 'time_unix'); timestamp = this.safeTimestamp (trade, 'time', timestamp); const id = this.safeString2 (trade, 'tradeID', 'id'); @@ -381,6 +400,7 @@ module.exports = class gateio extends Exchange { const price = this.safeFloat2 (trade, 'rate', 'price'); const amount = this.safeFloat (trade, 'amount'); const type = this.safeString (trade, 'type'); + const takerOrMaker = this.safeString (trade, 'role'); let cost = undefined; if (price !== undefined) { if (amount !== undefined) { @@ -391,6 +411,25 @@ module.exports = class gateio extends Exchange { if (market !== undefined) { symbol = market['symbol']; } + let fee = undefined; + let feeCurrency = this.safeCurrencyCode (this.safeString (trade, 'fee_coin')); + let feeCost = this.safeFloat (trade, 'point_fee'); + if ((feeCost === undefined) || (feeCost === 0)) { + feeCost = this.safeFloat (trade, 'gt_fee'); + if ((feeCost === undefined) || (feeCost === 0)) { + feeCost = this.safeFloat (trade, 'fee'); + } else { + feeCurrency = this.safeCurrencyCode ('GT'); + } + } else { + feeCurrency = this.safeCurrencyCode ('POINT'); + } + if (feeCost !== undefined) { + fee = { + 'cost': feeCost, + 'currency': feeCurrency, + }; + } return { 'id': id, 'info': trade, @@ -400,11 +439,11 @@ module.exports = class gateio extends Exchange { 'order': orderId, 'type': undefined, 'side': type, - 'takerOrMaker': undefined, + 'takerOrMaker': takerOrMaker, 'price': price, 'amount': amount, 'cost': cost, - 'fee': undefined, + 'fee': fee, }; } @@ -496,6 +535,7 @@ module.exports = class gateio extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': lastTradeTimestamp, diff --git a/TaskServer/node_modules/ccxt/js/gemini.js b/TaskServer/node_modules/ccxt/js/gemini.js index 71ad81453..a4f58b2ca 100644 --- a/TaskServer/node_modules/ccxt/js/gemini.js +++ b/TaskServer/node_modules/ccxt/js/gemini.js @@ -45,7 +45,11 @@ module.exports = class gemini extends Exchange { 'https://docs.gemini.com/rest-api', 'https://docs.sandbox.gemini.com', ], - 'test': 'https://api.sandbox.gemini.com', + 'test': { + 'public': 'https://api.sandbox.gemini.com', + 'private': 'https://api.sandbox.gemini.com', + 'web': 'https://docs.sandbox.gemini.com', + }, 'fees': [ 'https://gemini.com/api-fee-schedule', 'https://gemini.com/trading-fees', @@ -290,6 +294,7 @@ module.exports = class gemini extends Exchange { 'max': undefined, }, }, + 'active': undefined, }); } return result; @@ -451,8 +456,10 @@ module.exports = class gemini extends Exchange { } const id = this.safeString (order, 'order_id'); const side = this.safeStringLower (order, 'side'); + const clientOrderId = this.safeString (order, 'client_order_id'); return { 'id': id, + 'clientOrderId': clientOrderId, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -468,6 +475,7 @@ module.exports = class gemini extends Exchange { 'filled': filled, 'remaining': remaining, 'fee': fee, + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/hitbtc.js b/TaskServer/node_modules/ccxt/js/hitbtc.js index 5ee42b767..6cc535b07 100644 --- a/TaskServer/node_modules/ccxt/js/hitbtc.js +++ b/TaskServer/node_modules/ccxt/js/hitbtc.js @@ -3,8 +3,8 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { BadSymbol, ExchangeError, InsufficientFunds, OrderNotFound, InvalidOrder } = require ('./base/errors'); - +const { BadSymbol, PermissionDenied, ExchangeError, ExchangeNotAvailable, OrderNotFound, InsufficientFunds, InvalidOrder, RequestTimeout, AuthenticationError } = require ('./base/errors'); +const { TRUNCATE, DECIMAL_PLACES } = require ('./base/functions/number'); // --------------------------------------------------------------------------- module.exports = class hitbtc extends Exchange { @@ -14,23 +14,52 @@ module.exports = class hitbtc extends Exchange { 'name': 'HitBTC', 'countries': [ 'HK' ], 'rateLimit': 1500, - 'version': '1', + 'version': '2', + 'pro': true, 'has': { + 'createDepositAddress': true, + 'fetchDepositAddress': true, 'CORS': false, - 'fetchTrades': true, + 'editOrder': true, + 'fetchCurrencies': true, + 'fetchOHLCV': true, 'fetchTickers': true, 'fetchOrder': true, + 'fetchOrders': false, 'fetchOpenOrders': true, 'fetchClosedOrders': true, - 'fetchOrderTrades': true, + 'fetchMyTrades': true, 'withdraw': true, + 'fetchOrderTrades': false, // not implemented yet + 'fetchDeposits': false, + 'fetchWithdrawals': false, + 'fetchTransactions': true, + 'fetchTradingFee': true, + }, + 'timeframes': { + '1m': 'M1', + '3m': 'M3', + '5m': 'M5', + '15m': 'M15', + '30m': 'M30', // default + '1h': 'H1', + '4h': 'H4', + '1d': 'D1', + '1w': 'D7', + '1M': '1M', }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/27766555-8eaec20e-5edc-11e7-9c5b-6dc69fc42f5e.jpg', - 'api': 'https://api.hitbtc.com', + 'api': { + 'public': 'https://api.hitbtc.com', + 'private': 'https://api.hitbtc.com', + }, 'www': 'https://hitbtc.com', 'referral': 'https://hitbtc.com/?ref_id=5a5d39a65d466', - 'doc': 'https://github.com/hitbtc-com/hitbtc-api/blob/master/APIv1.md', + 'doc': [ + 'https://api.hitbtc.com', + 'https://github.com/hitbtc-com/hitbtc-api/blob/master/APIv2.md', + ], 'fees': [ 'https://hitbtc.com/fees-and-limits', 'https://support.hitbtc.com/hc/en-us/articles/115005148605-Fees-and-limits', @@ -39,52 +68,58 @@ module.exports = class hitbtc extends Exchange { 'api': { 'public': { 'get': [ - '{symbol}/orderbook', - '{symbol}/ticker', - '{symbol}/trades', - '{symbol}/trades/recent', - 'symbols', - 'ticker', - 'time', + 'symbol', // Available Currency Symbols + 'symbol/{symbol}', // Get symbol info + 'currency', // Available Currencies + 'currency/{currency}', // Get currency info + 'ticker', // Ticker list for all symbols + 'ticker/{symbol}', // Ticker for symbol + 'trades/{symbol}', // Trades + 'orderbook/{symbol}', // Orderbook + 'candles/{symbol}', // Candles ], }, - 'trading': { + 'private': { 'get': [ - 'balance', - 'orders/active', - 'orders/recent', - 'order', - 'trades/by/order', - 'trades', + 'order', // List your current open orders + 'order/{clientOrderId}', // Get a single order by clientOrderId + 'trading/balance', // Get trading balance + 'trading/fee/all', // Get trading fee rate + 'trading/fee/{symbol}', // Get trading fee rate + 'history/trades', // Get historical trades + 'history/order', // Get historical orders + 'history/order/{id}/trades', // Get historical trades by specified order + 'account/balance', // Get main acccount balance + 'account/transactions', // Get account transactions + 'account/transactions/{id}', // Get account transaction by id + 'account/crypto/address/{currency}', // Get deposit crypro address ], 'post': [ - 'new_order', - 'cancel_order', - 'cancel_orders', + 'order', // Create new order + 'account/crypto/withdraw', // Withdraw crypro + 'account/crypto/address/{currency}', // Create new deposit crypro address + 'account/transfer', // Transfer amount to trading ], - }, - 'payment': { - 'get': [ - 'balance', - 'address/{currency}', - 'transactions', - 'transactions/{transaction}', + 'put': [ + 'order/{clientOrderId}', // Create new order + 'account/crypto/withdraw/{id}', // Commit withdraw crypro ], - 'post': [ - 'transfer_to_trading', - 'transfer_to_main', - 'address/{currency}', - 'payout', + 'delete': [ + 'order', // Cancel all open orders + 'order/{clientOrderId}', // Cancel order + 'account/crypto/withdraw/{id}', // Rollback withdraw crypro + ], + 'patch': [ + 'order/{clientOrderId}', // Cancel Replace order ], }, }, - // hardcoded fees are deprecated and should only be used when there's no other way to get fee info 'fees': { 'trading': { 'tierBased': false, 'percentage': true, - 'maker': 0.07 / 100, - 'taker': 0.07 / 100, + 'maker': 0.1 / 100, + 'taker': 0.2 / 100, }, 'funding': { 'tierBased': false, @@ -92,11 +127,12 @@ module.exports = class hitbtc extends Exchange { 'withdraw': { 'BTC': 0.001, 'BCC': 0.0018, - 'ETH': 0.00215, + 'ETH': 0.00958, 'BCH': 0.0018, 'USDT': 100, 'DASH': 0.03, 'BTG': 0.0005, + 'XRP': 0.509, 'LTC': 0.003, 'ZEC': 0.0001, 'XMR': 0.09, @@ -105,7 +141,8 @@ module.exports = class hitbtc extends Exchange { 'AE': 6.7, 'AEON': 0.01006, 'AIR': 565, - 'AMP': 9, + 'AMM': 14, + 'AMP': 342, 'ANT': 6.7, 'ARDR': 1, 'ARN': 18.5, @@ -117,32 +154,37 @@ module.exports = class hitbtc extends Exchange { 'AVT': 1.9, 'BAS': 113, 'BCN': 0.1, - 'DAO.Casino': 124, // id = 'BET' + 'BET': 124, 'BKB': 46, 'BMC': 32, 'BMT': 100, 'BNT': 2.57, 'BQX': 4.7, + 'BTCA': 351.21, 'BTM': 40, 'BTX': 0.04, 'BUS': 0.004, - 'CCT': 115, + 'CAPP': 97, + 'CCT': 6, 'CDT': 100, 'CDX': 30, 'CFI': 61, + 'CL': 13.85, 'CLD': 0.88, 'CND': 574, 'CNX': 0.04, 'COSS': 65, + 'CPAY': 5.487, 'CSNO': 16, 'CTR': 15, 'CTX': 146, 'CVC': 8.46, + 'DATA': 12.949, 'DBIX': 0.0168, - 'DCN': 120000, + 'DCN': 1280, 'DCT': 0.02, 'DDF': 342, - 'DENT': 6240, + 'DENT': 1000, 'DGB': 0.4, 'DGD': 0.01, 'DICE': 0.32, @@ -159,10 +201,11 @@ module.exports = class hitbtc extends Exchange { 'ECAT': 14, 'EDG': 2, 'EDO': 2.9, + 'EKO': 1136.36, 'ELE': 0.00172, 'ELM': 0.004, 'EMC': 0.03, - 'EMGO': 14, + 'MGO': 14, 'ENJ': 163, 'EOS': 1.5, 'ERO': 34, @@ -171,14 +214,17 @@ module.exports = class hitbtc extends Exchange { 'ETP': 0.004, 'EVX': 5.4, 'EXN': 456, + 'FCN': 0.000005, 'FRD': 65, 'FUEL': 123.00105, 'FUN': 202.9598309, 'FYN': 1.849, 'FYP': 66.13, + 'GAME': 0.004, 'GNO': 0.0034, 'GUP': 4, 'GVT': 1.2, + 'HSR': 0.04, 'HAC': 144, 'HDG': 7, 'HGT': 1082, @@ -188,16 +234,19 @@ module.exports = class hitbtc extends Exchange { 'ICO': 34, 'ICOS': 0.35, 'IND': 76, - 'INDI': 5913, + 'INDI': 790, 'ITS': 15.0012, 'IXT': 11, 'KBR': 143, 'KICK': 112, + 'KMD': 4, 'LA': 41, + 'LEND': 388, 'LAT': 1.44, 'LIFE': 13000, 'LRC': 27, 'LSK': 0.3, + 'LOC': 11.076, 'LUN': 0.34, 'MAID': 5, 'MANA': 143, @@ -205,12 +254,14 @@ module.exports = class hitbtc extends Exchange { 'MIPS': 43, 'MNE': 1.33, 'MSP': 121, + 'MCO': 0.357, 'MTH': 92, 'MYB': 3.9, 'NDC': 165, 'NEBL': 0.04, 'NET': 3.96, 'NTO': 998, + 'NGC': 2.368, 'NXC': 13.39, 'NXT': 3, 'OAX': 15, @@ -238,20 +289,26 @@ module.exports = class hitbtc extends Exchange { 'QVT': 64, 'REP': 0.02, 'RKC': 15, + 'RLC': 1.21, 'RVT': 14, + 'SC': 30, 'SAN': 2.24, 'SBD': 0.03, 'SCL': 2.6, 'SISA': 1640, 'SKIN': 407, + 'SWFTC': 352.94, 'SMART': 0.4, 'SMS': 0.0375, 'SNC': 36, 'SNGLS': 4, 'SNM': 48, 'SNT': 233, + 'STAR': 0.144, + 'STORM': 153.19, 'STEEM': 0.01, 'STRAT': 0.01, + 'SPF': 14.4, 'STU': 14, 'STX': 11, 'SUB': 17, @@ -263,12 +320,14 @@ module.exports = class hitbtc extends Exchange { 'TIME': 0.03, 'TIX': 7.1, 'TKN': 1, + 'TGT': 173, 'TKR': 84, 'TNT': 90, 'TRST': 1.6, - 'TRX': 1395, + 'TRX': 270, 'UET': 480, 'UGT': 15, + 'UTT': 3, 'VEN': 14, 'VERI': 0.037, 'VIB': 50, @@ -277,6 +336,7 @@ module.exports = class hitbtc extends Exchange { 'WEALTH': 0.0168, 'WINGS': 2.4, 'WTC': 0.75, + 'WRC': 48, 'XAUR': 3.23, 'XDN': 0.01, 'XEM': 15, @@ -287,8 +347,8 @@ module.exports = class hitbtc extends Exchange { 'ZSC': 191, }, 'deposit': { - 'BTC': 0.0006, - 'ETH': 0.003, + 'BTC': 0, + 'ETH': 0, 'BCH': 0, 'USDT': 0, 'BTG': 0, @@ -312,7 +372,7 @@ module.exports = class hitbtc extends Exchange { 'AVT': 0, 'BAS': 0, 'BCN': 0, - 'DAO.Casino': 0, // id = 'BET' + 'BET': 0, 'BKB': 0, 'BMC': 0, 'BMT': 0, @@ -483,6 +543,9 @@ module.exports = class hitbtc extends Exchange { }, }, }, + 'options': { + 'defaultTimeInForce': 'FOK', + }, 'commonCurrencies': { 'BET': 'DAO.Casino', 'CAT': 'BitClave', @@ -492,38 +555,51 @@ module.exports = class hitbtc extends Exchange { 'GET': 'Themis', 'HSR': 'HC', 'LNC': 'LinkerCoin', + 'PLA': 'PlayChip', 'UNC': 'Unigame', 'USD': 'USDT', 'XBT': 'BTC', }, 'exceptions': { - 'exact': { - '2001': BadSymbol, // {"error":{"code":2001,"message":"Symbol not found","description":"Try get /api/2/public/symbol, to get list of all available symbols."}} - }, - 'broad': { - }, - }, - 'options': { - 'defaultTimeInForce': 'FOK', + '504': RequestTimeout, // {"error":{"code":504,"message":"Gateway Timeout"}} + '1002': AuthenticationError, // {"error":{"code":1002,"message":"Authorization failed","description":""}} + '1003': PermissionDenied, // "Action is forbidden for this API key" + '2010': InvalidOrder, // "Quantity not a valid number" + '2001': BadSymbol, // "Symbol not found" + '2011': InvalidOrder, // "Quantity too low" + '2020': InvalidOrder, // "Price not a valid number" + '20002': OrderNotFound, // canceling non-existent order + '20001': InsufficientFunds, }, }); } + feeToPrecision (symbol, fee) { + return this.decimalToPrecision (fee, TRUNCATE, 8, DECIMAL_PLACES); + } + async fetchMarkets (params = {}) { - const response = await this.publicGetSymbols (params); - const markets = this.safeValue (response, 'symbols'); + const response = await this.publicGetSymbol (params); const result = []; - for (let i = 0; i < markets.length; i++) { - const market = markets[i]; - const id = this.safeString (market, 'symbol'); - const baseId = this.safeString (market, 'commodity'); - const quoteId = this.safeString (market, 'currency'); - const lot = this.safeFloat (market, 'lot'); - const step = this.safeFloat (market, 'step'); + for (let i = 0; i < response.length; i++) { + const market = response[i]; + const id = this.safeString (market, 'id'); + const baseId = this.safeString (market, 'baseCurrency'); + const quoteId = this.safeString (market, 'quoteCurrency'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const symbol = base + '/' + quote; - result.push ({ + const lot = this.safeFloat (market, 'quantityIncrement'); + const step = this.safeFloat (market, 'tickSize'); + const precision = { + 'price': this.precisionFromString (market['tickSize']), + // FIXME: for lots > 1 the following line returns 0 + // 'amount': this.precisionFromString (market['quantityIncrement']), + 'amount': -1 * parseInt (Math.log10 (lot)), + }; + const taker = this.safeFloat (market, 'takeLiquidityRate'); + const maker = this.safeFloat (market, 'provideLiquidityRate'); + result.push (this.extend (this.fees['trading'], { 'info': market, 'id': id, 'symbol': symbol, @@ -531,15 +607,10 @@ module.exports = class hitbtc extends Exchange { 'quote': quote, 'baseId': baseId, 'quoteId': quoteId, - 'lot': lot, - 'step': step, 'active': true, - 'maker': this.safeFloat (market, 'provideLiquidityRate'), - 'taker': this.safeFloat (market, 'takeLiquidityRate'), - 'precision': { - 'amount': this.precisionFromString (market['lot']), - 'price': this.precisionFromString (market['step']), - }, + 'taker': taker, + 'maker': maker, + 'precision': precision, 'limits': { 'amount': { 'min': lot, @@ -550,50 +621,183 @@ module.exports = class hitbtc extends Exchange { 'max': undefined, }, 'cost': { - 'min': undefined, + 'min': lot * step, 'max': undefined, }, }, - }); + })); } return result; } + async fetchCurrencies (params = {}) { + const response = await this.publicGetCurrency (params); + const result = {}; + for (let i = 0; i < response.length; i++) { + const currency = response[i]; + const id = this.safeString (currency, 'id'); + // todo: will need to rethink the fees + // to add support for multiple withdrawal/deposit methods and + // differentiated fees for each particular method + const precision = 8; // default precision, todo: fix "magic constants" + const code = this.safeCurrencyCode (id); + const payin = this.safeValue (currency, 'payinEnabled'); + const payout = this.safeValue (currency, 'payoutEnabled'); + const transfer = this.safeValue (currency, 'transferEnabled'); + let active = payin && payout && transfer; + if ('disabled' in currency) { + if (currency['disabled']) { + active = false; + } + } + let type = 'fiat'; + if (('crypto' in currency) && currency['crypto']) { + type = 'crypto'; + } + const name = this.safeString (currency, 'fullName'); + result[code] = { + 'id': id, + 'code': code, + 'type': type, + 'payin': payin, + 'payout': payout, + 'transfer': transfer, + 'info': currency, + 'name': name, + 'active': active, + 'fee': this.safeFloat (currency, 'payoutFee'), // todo: redesign + 'precision': precision, + 'limits': { + 'amount': { + 'min': Math.pow (10, -precision), + 'max': Math.pow (10, precision), + }, + 'price': { + 'min': Math.pow (10, -precision), + 'max': Math.pow (10, precision), + }, + 'cost': { + 'min': undefined, + 'max': undefined, + }, + 'withdraw': { + 'min': undefined, + 'max': Math.pow (10, precision), + }, + }, + }; + } + return result; + } + + async fetchTradingFee (symbol, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = this.extend ({ + 'symbol': market['id'], + }, this.omit (params, 'symbol')); + const response = await this.privateGetTradingFeeSymbol (request); + // + // { + // takeLiquidityRate: '0.001', + // provideLiquidityRate: '-0.0001' + // } + // + return { + 'info': response, + 'maker': this.safeFloat (response, 'provideLiquidityRate'), + 'taker': this.safeFloat (response, 'takeLiquidityRate'), + }; + } + async fetchBalance (params = {}) { await this.loadMarkets (); - let method = this.safeString (params, 'type', 'trading'); - method += 'GetBalance'; + const type = this.safeString (params, 'type', 'trading'); + const method = 'privateGet' + this.capitalize (type) + 'Balance'; const query = this.omit (params, 'type'); const response = await this[method] (query); - const balances = this.safeValue (response, 'balance', []); const result = { 'info': response }; - for (let i = 0; i < balances.length; i++) { - const balance = balances[i]; - const currencyId = this.safeString (balance, 'currency_code'); + for (let i = 0; i < response.length; i++) { + const balance = response[i]; + const currencyId = this.safeString (balance, 'currency'); const code = this.safeCurrencyCode (currencyId); const account = this.account (); - account['free'] = this.safeFloat2 (balance, 'cash', 'balance'); + account['free'] = this.safeFloat (balance, 'available'); account['used'] = this.safeFloat (balance, 'reserved'); result[code] = account; } return this.parseBalance (result); } + parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) { + const timestamp = this.parse8601 (ohlcv['timestamp']); + return [ + timestamp, + parseFloat (ohlcv['open']), + parseFloat (ohlcv['max']), + parseFloat (ohlcv['min']), + parseFloat (ohlcv['close']), + parseFloat (ohlcv['volume']), + ]; + } + + async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + 'period': this.timeframes[timeframe], + }; + if (since !== undefined) { + request['from'] = this.iso8601 (since); + } + if (limit !== undefined) { + request['limit'] = limit; + } + const response = await this.publicGetCandlesSymbol (this.extend (request, params)); + return this.parseOHLCVs (response, market, timeframe, since, limit); + } + async fetchOrderBook (symbol, limit = undefined, params = {}) { await this.loadMarkets (); - const orderbook = await this.publicGetSymbolOrderbook (this.extend ({ + const request = { 'symbol': this.marketId (symbol), - }, params)); - return this.parseOrderBook (orderbook); + }; + if (limit !== undefined) { + request['limit'] = limit; // default = 100, 0 = unlimited + } + const response = await this.publicGetOrderbookSymbol (this.extend (request, params)); + return this.parseOrderBook (response, undefined, 'bid', 'ask', 'price', 'size'); } parseTicker (ticker, market = undefined) { - const timestamp = this.safeInteger (ticker, 'timestamp'); + const timestamp = this.parse8601 (ticker['timestamp']); let symbol = undefined; - if (market) { + if (market !== undefined) { symbol = market['symbol']; } + const baseVolume = this.safeFloat (ticker, 'volume'); + const quoteVolume = this.safeFloat (ticker, 'volumeQuote'); + const open = this.safeFloat (ticker, 'open'); const last = this.safeFloat (ticker, 'last'); + let change = undefined; + let percentage = undefined; + let average = undefined; + if (last !== undefined && open !== undefined) { + change = last - open; + average = this.sum (last, open) / 2; + if (open > 0) { + percentage = change / open * 100; + } + } + let vwap = undefined; + if (quoteVolume !== undefined) { + if (baseVolume !== undefined) { + if (baseVolume > 0) { + vwap = quoteVolume / baseVolume; + } + } + } return { 'symbol': symbol, 'timestamp': timestamp, @@ -604,31 +808,36 @@ module.exports = class hitbtc extends Exchange { 'bidVolume': undefined, 'ask': this.safeFloat (ticker, 'ask'), 'askVolume': undefined, - 'vwap': undefined, - 'open': this.safeFloat (ticker, 'open'), + 'vwap': vwap, + 'open': open, 'close': last, 'last': last, 'previousClose': undefined, - 'change': undefined, - 'percentage': undefined, - 'average': undefined, - 'baseVolume': this.safeFloat (ticker, 'volume'), - 'quoteVolume': this.safeFloat (ticker, 'volume_quote'), + 'change': change, + 'percentage': percentage, + 'average': average, + 'baseVolume': baseVolume, + 'quoteVolume': quoteVolume, 'info': ticker, }; } async fetchTickers (symbols = undefined, params = {}) { await this.loadMarkets (); - const tickers = await this.publicGetTicker (params); - const ids = Object.keys (tickers); + const response = await this.publicGetTicker (params); const result = {}; - for (let i = 0; i < ids.length; i++) { - const id = ids[i]; - const market = this.markets_by_id[id]; - const symbol = market['symbol']; - const ticker = tickers[id]; - result[symbol] = this.parseTicker (ticker, market); + for (let i = 0; i < response.length; i++) { + const ticker = response[i]; + const marketId = this.safeString (ticker, 'symbol'); + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + const market = this.markets_by_id[marketId]; + const symbol = market['symbol']; + result[symbol] = this.parseTicker (ticker, market); + } else { + result[marketId] = this.parseTicker (ticker); + } + } } return result; } @@ -639,7 +848,7 @@ module.exports = class hitbtc extends Exchange { const request = { 'symbol': market['id'], }; - const response = await this.publicGetSymbolTicker (this.extend (request, params)); + const response = await this.publicGetTickerSymbol (this.extend (request, params)); if ('message' in response) { throw new ExchangeError (this.id + ' ' + response['message']); } @@ -647,65 +856,53 @@ module.exports = class hitbtc extends Exchange { } parseTrade (trade, market = undefined) { - if (Array.isArray (trade)) { - return this.parsePublicTrade (trade, market); - } - return this.parseOrderTrade (trade, market); - } - - parsePublicTrade (trade, market = undefined) { + // + // createMarketOrder + // + // { fee: "0.0004644", + // id: 386394956, + // price: "0.4644", + // quantity: "1", + // timestamp: "2018-10-25T16:41:44.780Z" } + // + // fetchTrades ... + // + // fetchMyTrades ... + // + const timestamp = this.parse8601 (trade['timestamp']); let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; + const marketId = this.safeString (trade, 'symbol'); + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + symbol = marketId; + } } - let side = undefined; - const tradeLength = trade.length; - if (tradeLength > 4) { - side = trade[4]; + if (symbol === undefined) { + if (market !== undefined) { + symbol = market['symbol']; + } } - const price = parseFloat (trade[1]); - const amount = parseFloat (trade[2]); - const cost = price * amount; - return { - 'info': trade, - 'id': trade[0].toString (), - 'timestamp': trade[3], - 'datetime': this.iso8601 (trade[3]), - 'symbol': symbol, - 'type': undefined, - 'side': side, - 'order': undefined, - 'takerOrMaker': undefined, - 'price': price, - 'amount': amount, - 'cost': cost, - 'fee': undefined, - }; - } - - parseOrderTrade (trade, market = undefined) { - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; + let fee = undefined; + const feeCost = this.safeFloat (trade, 'fee'); + if (feeCost !== undefined) { + const feeCurrency = market ? market['quote'] : undefined; + fee = { + 'cost': feeCost, + 'currency': feeCurrency, + }; } - let amount = this.safeFloat (trade, 'execQuantity'); - if (market) { - amount *= market['lot']; - } - const price = this.safeFloat (trade, 'execPrice'); - const cost = price * amount; - const fee = { - 'cost': this.safeFloat (trade, 'fee'), - 'currency': undefined, - 'rate': undefined, - }; - const timestamp = this.safeInteger (trade, 'timestamp'); - const id = this.safeString (trade, 'tradeId'); // we use clientOrderId as the order id with HitBTC intentionally // because most of their endpoints will require clientOrderId // explained here: https://github.com/ccxt/ccxt/issues/5674 const orderId = this.safeString (trade, 'clientOrderId'); + const price = this.safeFloat (trade, 'price'); + const amount = this.safeFloat (trade, 'quantity'); + const cost = price * amount; const side = this.safeString (trade, 'side'); + const id = this.safeString (trade, 'id'); return { 'info': trade, 'id': id, @@ -715,6 +912,7 @@ module.exports = class hitbtc extends Exchange { 'symbol': symbol, 'type': undefined, 'side': side, + 'takerOrMaker': undefined, 'price': price, 'amount': amount, 'cost': cost, @@ -722,53 +920,166 @@ module.exports = class hitbtc extends Exchange { }; } + async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let currency = undefined; + const request = {}; + if (code !== undefined) { + currency = this.currency (code); + request['asset'] = currency['id']; + } + if (since !== undefined) { + request['startTime'] = since; + } + const response = await this.privateGetAccountTransactions (this.extend (request, params)); + return this.parseTransactions (response, currency, since, limit); + } + + parseTransaction (transaction, currency = undefined) { + // + // { + // id: 'd53ee9df-89bf-4d09-886e-849f8be64647', + // index: 1044718371, + // type: 'payout', + // status: 'success', + // currency: 'ETH', + // amount: '4.522683200000000000000000', + // createdAt: '2018-06-07T00:43:32.426Z', + // updatedAt: '2018-06-07T00:45:36.447Z', + // hash: '0x973e5683dfdf80a1fb1e0b96e19085b6489221d2ddf864daa46903c5ec283a0f', + // address: '0xC5a59b21948C1d230c8C54f05590000Eb3e1252c', + // fee: '0.00958', + // }, + // { + // id: 'e6c63331-467e-4922-9edc-019e75d20ba3', + // index: 1044714672, + // type: 'exchangeToBank', + // status: 'success', + // currency: 'ETH', + // amount: '4.532263200000000000', + // createdAt: '2018-06-07T00:42:39.543Z', + // updatedAt: '2018-06-07T00:42:39.683Z', + // }, + // { + // id: '3b052faa-bf97-4636-a95c-3b5260015a10', + // index: 1009280164, + // type: 'bankToExchange', + // status: 'success', + // currency: 'CAS', + // amount: '104797.875800000000000000', + // createdAt: '2018-05-19T02:34:36.750Z', + // updatedAt: '2018-05-19T02:34:36.857Z', + // }, + // { + // id: 'd525249f-7498-4c81-ba7b-b6ae2037dc08', + // index: 1009279948, + // type: 'payin', + // status: 'success', + // currency: 'CAS', + // amount: '104797.875800000000000000', + // createdAt: '2018-05-19T02:30:16.698Z', + // updatedAt: '2018-05-19T02:34:28.159Z', + // hash: '0xa6530e1231de409cf1f282196ed66533b103eac1df2aa4a7739d56b02c5f0388', + // address: '0xd53ed559a6d963af7cb3f3fcd0e7ca499054db8b', + // } + // + // { + // "id": "4f351f4f-a8ee-4984-a468-189ed590ddbd", + // "index": 3112719565, + // "type": "withdraw", + // "status": "success", + // "currency": "BCHOLD", + // "amount": "0.02423133", + // "createdAt": "2019-07-16T16:52:04.494Z", + // "updatedAt": "2019-07-16T16:54:07.753Z" + // } + const id = this.safeString (transaction, 'id'); + const timestamp = this.parse8601 (this.safeString (transaction, 'createdAt')); + const updated = this.parse8601 (this.safeString (transaction, 'updatedAt')); + const currencyId = this.safeString (transaction, 'currency'); + const code = this.safeCurrencyCode (currencyId, currency); + const status = this.parseTransactionStatus (this.safeString (transaction, 'status')); + const amount = this.safeFloat (transaction, 'amount'); + const address = this.safeString (transaction, 'address'); + const txid = this.safeString (transaction, 'hash'); + let fee = undefined; + const feeCost = this.safeFloat (transaction, 'fee'); + if (feeCost !== undefined) { + fee = { + 'cost': feeCost, + 'currency': code, + }; + } + const type = this.parseTransactionType (this.safeString (transaction, 'type')); + return { + 'info': transaction, + 'id': id, + 'txid': txid, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'address': address, + 'tag': undefined, + 'type': type, + 'amount': amount, + 'currency': code, + 'status': status, + 'updated': updated, + 'fee': fee, + }; + } + + parseTransactionStatus (status) { + const statuses = { + 'pending': 'pending', + 'failed': 'failed', + 'success': 'ok', + }; + return this.safeString (statuses, status, status); + } + + parseTransactionType (type) { + const types = { + 'payin': 'deposit', + 'payout': 'withdrawal', + 'withdraw': 'withdrawal', + }; + return this.safeString (types, type, type); + } + async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = { 'symbol': market['id'], - // 'from': 0, - // 'till': 100, - // 'by': 'ts', // or by trade_id - // 'sort': 'desc', // or asc - // 'start_index': 0, - // 'max_results': 1000, - // 'format_item': 'object', - // 'format_price': 'number', - // 'format_amount': 'number', - // 'format_tid': 'string', - // 'format_timestamp': 'millisecond', - // 'format_wrap': false, - // 'side': 'true', }; - if (since !== undefined) { - request['by'] = 'ts'; - request['from'] = since; - } if (limit !== undefined) { - request['max_results'] = limit; + request['limit'] = limit; } - const response = await this.publicGetSymbolTrades (this.extend (request, params)); - return this.parseTrades (response['trades'], market, since, limit); + if (since !== undefined) { + request['sort'] = 'ASC'; + request['from'] = this.iso8601 (since); + } + const response = await this.publicGetTradesSymbol (this.extend (request, params)); + return this.parseTrades (response, market, since, limit); } async createOrder (symbol, type, side, amount, price = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); - // check if amount can be evenly divided into lots - // they want integer quantity in lot units - const quantity = parseFloat (amount) / market['lot']; - const wholeLots = Math.round (quantity); - const difference = quantity - wholeLots; - if (Math.abs (difference) > market['step']) { - throw new ExchangeError (this.id + ' order amount should be evenly divisible by lot unit size of ' + market['lot'].toString ()); - } - const clientOrderId = this.milliseconds (); + // we use clientOrderId as the order id with HitBTC intentionally + // because most of their endpoints will require clientOrderId + // explained here: https://github.com/ccxt/ccxt/issues/5674 + // their max accepted length is 32 characters + const uuid = this.uuid (); + const parts = uuid.split ('-'); + let clientOrderId = parts.join (''); + clientOrderId = clientOrderId.slice (0, 32); + amount = parseFloat (amount); const request = { - 'clientOrderId': clientOrderId.toString (), + 'clientOrderId': clientOrderId, 'symbol': market['id'], 'side': side, - 'quantity': wholeLots.toString (), // quantity in integer lot units + 'quantity': this.amountToPrecision (symbol, amount), 'type': type, }; if (type === 'limit') { @@ -776,11 +1087,39 @@ module.exports = class hitbtc extends Exchange { } else { request['timeInForce'] = this.options['defaultTimeInForce']; } - const response = await this.tradingPostNewOrder (this.extend (request, params)); - const order = this.parseOrder (response['ExecutionReport'], market); + const response = await this.privatePostOrder (this.extend (request, params)); + const order = this.parseOrder (response); if (order['status'] === 'rejected') { throw new InvalidOrder (this.id + ' order was rejected by the exchange ' + this.json (order)); } + const id = order['id']; + this.orders[id] = order; + return order; + } + + async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) { + await this.loadMarkets (); + // we use clientOrderId as the order id with HitBTC intentionally + // because most of their endpoints will require clientOrderId + // explained here: https://github.com/ccxt/ccxt/issues/5674 + // their max accepted length is 32 characters + const uuid = this.uuid (); + const parts = uuid.split ('-'); + let requestClientId = parts.join (''); + requestClientId = requestClientId.slice (0, 32); + const request = { + 'clientOrderId': id, + 'requestClientId': requestClientId, + }; + if (amount !== undefined) { + request['quantity'] = this.amountToPrecision (symbol, amount); + } + if (price !== undefined) { + request['price'] = this.priceToPrecision (symbol, price); + } + const response = await this.privatePatchOrderClientOrderId (this.extend (request, params)); + const order = this.parseOrder (response); + this.orders[order['id']] = order; return order; } @@ -792,97 +1131,140 @@ module.exports = class hitbtc extends Exchange { const request = { 'clientOrderId': id, }; - return await this.tradingPostCancelOrder (this.extend (request, params)); + const response = await this.privateDeleteOrderClientOrderId (this.extend (request, params)); + return this.parseOrder (response); } parseOrderStatus (status) { const statuses = { 'new': 'open', + 'suspended': 'open', 'partiallyFilled': 'open', 'filled': 'closed', 'canceled': 'canceled', - 'rejected': 'rejected', - 'expired': 'expired', + 'expired': 'failed', }; - return this.safeString (statuses, status); + return this.safeString (statuses, status, status); } parseOrder (order, market = undefined) { - let timestamp = this.safeInteger (order, 'lastTimestamp'); - if (timestamp === undefined) { - timestamp = this.safeInteger (order, 'timestamp'); - } + // + // createMarketOrder + // + // { clientOrderId: "fe36aa5e190149bf9985fb673bbb2ea0", + // createdAt: "2018-10-25T16:41:44.780Z", + // cumQuantity: "1", + // id: "66799540063", + // quantity: "1", + // side: "sell", + // status: "filled", + // symbol: "XRPUSDT", + // timeInForce: "FOK", + // tradesReport: [ { fee: "0.0004644", + // id: 386394956, + // price: "0.4644", + // quantity: "1", + // timestamp: "2018-10-25T16:41:44.780Z" } ], + // type: "market", + // updatedAt: "2018-10-25T16:41:44.780Z" } + // + const created = this.parse8601 (this.safeString (order, 'createdAt')); + const updated = this.parse8601 (this.safeString (order, 'updatedAt')); + const marketId = this.safeString (order, 'symbol'); let symbol = undefined; - if (market === undefined) { - market = this.markets_by_id[order['symbol']]; - } - const status = this.parseOrderStatus (this.safeString (order, 'orderStatus')); - let price = this.safeFloat (order, 'orderPrice'); - price = this.safeFloat (order, 'price', price); - price = this.safeFloat (order, 'avgPrice', price); - let amount = this.safeFloat (order, 'orderQuantity'); - amount = this.safeFloat (order, 'quantity', amount); - let remaining = this.safeFloat (order, 'quantityLeaves'); - remaining = this.safeFloat (order, 'leavesQuantity', remaining); - let filled = undefined; - let cost = undefined; - const amountDefined = (amount !== undefined); - const remainingDefined = (remaining !== undefined); - if (market !== undefined) { - symbol = market['symbol']; - if (amountDefined) { - amount *= market['lot']; - } - if (remainingDefined) { - remaining *= market['lot']; - } - } else { - const marketId = this.safeString (order, 'symbol'); + if (marketId !== undefined) { if (marketId in this.markets_by_id) { market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + symbol = marketId; } } - if (amountDefined) { - if (remainingDefined) { - filled = amount - remaining; - if (price !== undefined) { - cost = price * filled; - } + if (symbol === undefined) { + if (market !== undefined) { + symbol = market['id']; } } - const feeCost = this.safeFloat (order, 'fee'); - let feeCurrency = undefined; - if (market !== undefined) { - symbol = market['symbol']; - feeCurrency = market['quote']; - } - const fee = { - 'cost': feeCost, - 'currency': feeCurrency, - 'rate': undefined, - }; + const amount = this.safeFloat (order, 'quantity'); + const filled = this.safeFloat (order, 'cumQuantity'); + const status = this.parseOrderStatus (this.safeString (order, 'status')); // we use clientOrderId as the order id with HitBTC intentionally // because most of their endpoints will require clientOrderId // explained here: https://github.com/ccxt/ccxt/issues/5674 const id = this.safeString (order, 'clientOrderId'); + const clientOrderId = id; + let price = this.safeFloat (order, 'price'); + if (price === undefined) { + if (id in this.orders) { + price = this.orders[id]['price']; + } + } + let remaining = undefined; + let cost = undefined; + if (amount !== undefined) { + if (filled !== undefined) { + remaining = amount - filled; + if (price !== undefined) { + cost = filled * price; + } + } + } const type = this.safeString (order, 'type'); const side = this.safeString (order, 'side'); + let trades = this.safeValue (order, 'tradesReport'); + let fee = undefined; + let average = undefined; + if (trades !== undefined) { + trades = this.parseTrades (trades, market); + let feeCost = undefined; + const numTrades = trades.length; + let tradesCost = 0; + for (let i = 0; i < numTrades; i++) { + if (feeCost === undefined) { + feeCost = 0; + } + tradesCost = this.sum (tradesCost, trades[i]['cost']); + const tradeFee = this.safeValue (trades[i], 'fee', {}); + const tradeFeeCost = this.safeFloat (tradeFee, 'cost'); + if (tradeFeeCost !== undefined) { + feeCost = this.sum (feeCost, tradeFeeCost); + } + } + cost = tradesCost; + if ((filled !== undefined) && (filled > 0)) { + average = cost / filled; + if (type === 'market') { + if (price === undefined) { + price = average; + } + } + } + if (feeCost !== undefined) { + fee = { + 'cost': feeCost, + 'currency': market['quote'], + }; + } + } return { 'id': id, - 'info': order, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'lastTradeTimestamp': undefined, + 'clientOrderId': clientOrderId, // https://github.com/ccxt/ccxt/issues/5674 + 'timestamp': created, + 'datetime': this.iso8601 (created), + 'lastTradeTimestamp': updated, 'status': status, 'symbol': symbol, 'type': type, 'side': side, 'price': price, - 'cost': cost, + 'average': average, 'amount': amount, + 'cost': cost, 'filled': filled, 'remaining': remaining, 'fee': fee, + 'trades': trades, + 'info': order, }; } @@ -894,78 +1276,189 @@ module.exports = class hitbtc extends Exchange { const request = { 'clientOrderId': id, }; - const response = await this.tradingGetOrder (this.extend (request, params)); - if (response['orders'][0]) { - return this.parseOrder (response['orders'][0]); + const response = await this.privateGetHistoryOrder (this.extend (request, params)); + const numOrders = response.length; + if (numOrders > 0) { + return this.parseOrder (response[0]); } - throw new OrderNotFound (this.id + ' fetchOrder() error: ' + this.response); + throw new OrderNotFound (this.id + ' order ' + id + ' not found'); } - async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + async fetchOpenOrder (id, symbol = undefined, params = {}) { await this.loadMarkets (); - const statuses = [ 'new', 'partiallyFiiled' ]; - let market = undefined; - const request = { - 'sort': 'desc', - 'statuses': statuses.join (','), - }; - if (symbol !== undefined) { - market = this.market (symbol); - request['symbols'] = market['id']; - } - const response = await this.tradingGetOrdersActive (this.extend (request, params)); - return this.parseOrders (response['orders'], market, since, limit); - } - - async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - let market = undefined; - const statuses = [ 'filled', 'canceled', 'rejected', 'expired' ]; - const request = { - 'sort': 'desc', - 'statuses': statuses.join (','), - 'max_results': 1000, - }; - if (symbol !== undefined) { - market = this.market (symbol); - request['symbols'] = market['id']; - } - const response = await this.tradingGetOrdersRecent (this.extend (request, params)); - return this.parseOrders (response['orders'], market, since, limit); - } - - async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - let market = undefined; - if (symbol !== undefined) { - market = this.market (symbol); - } // we use clientOrderId as the order id with HitBTC intentionally // because most of their endpoints will require clientOrderId // explained here: https://github.com/ccxt/ccxt/issues/5674 const request = { 'clientOrderId': id, }; - const response = await this.tradingGetTradesByOrder (this.extend (request, params)); - return this.parseTrades (response['trades'], market, since, limit); + const response = await this.privateGetOrderClientOrderId (this.extend (request, params)); + return this.parseOrder (response); } - async withdraw (code, amount, address, tag = undefined, params = {}) { - this.checkAddress (address); + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let market = undefined; + const request = {}; + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + } + const response = await this.privateGetOrder (this.extend (request, params)); + return this.parseOrders (response, market, since, limit); + } + + async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let market = undefined; + const request = {}; + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + } + if (limit !== undefined) { + request['limit'] = limit; + } + if (since !== undefined) { + request['from'] = this.iso8601 (since); + } + const response = await this.privateGetHistoryOrder (this.extend (request, params)); + const parsedOrders = this.parseOrders (response, market); + const orders = []; + for (let i = 0; i < parsedOrders.length; i++) { + const order = parsedOrders[i]; + const status = order['status']; + if ((status === 'closed') || (status === 'canceled')) { + orders.push (order); + } + } + return this.filterBySinceLimit (orders, since, limit); + } + + async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'symbol': 'BTC/USD', // optional + // 'sort': 'DESC', // or 'ASC' + // 'by': 'timestamp', // or 'id' String timestamp by default, or id + // 'from': 'Datetime or Number', // ISO 8601 + // 'till': 'Datetime or Number', + // 'limit': 100, + // 'offset': 0, + }; + let market = undefined; + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + } + if (since !== undefined) { + request['from'] = this.iso8601 (since); + } + if (limit !== undefined) { + request['limit'] = limit; + } + const response = await this.privateGetHistoryTrades (this.extend (request, params)); + // + // [ + // { + // "id": 9535486, + // "clientOrderId": "f8dbaab336d44d5ba3ff578098a68454", + // "orderId": 816088377, + // "symbol": "ETHBTC", + // "side": "sell", + // "quantity": "0.061", + // "price": "0.045487", + // "fee": "0.000002775", + // "timestamp": "2017-05-17T12:32:57.848Z" + // }, + // { + // "id": 9535437, + // "clientOrderId": "27b9bfc068b44194b1f453c7af511ed6", + // "orderId": 816088021, + // "symbol": "ETHBTC", + // "side": "buy", + // "quantity": "0.038", + // "price": "0.046000", + // "fee": "-0.000000174", + // "timestamp": "2017-05-17T12:30:57.848Z" + // } + // ] + // + return this.parseTrades (response, market, since, limit); + } + + async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { + // The id needed here is the exchange's id, and not the clientOrderID, + // which is the id that is stored in the unified order id + // To get the exchange's id you need to grab it from order['info']['id'] + await this.loadMarkets (); + let market = undefined; + if (symbol !== undefined) { + market = this.market (symbol); + } + const request = { + 'id': id, + }; + const response = await this.privateGetHistoryOrderIdTrades (this.extend (request, params)); + const numOrders = response.length; + if (numOrders > 0) { + return this.parseTrades (response, market, since, limit); + } + throw new OrderNotFound (this.id + ' order ' + id + ' not found, ' + this.id + '.fetchOrderTrades() requires an exchange-specific order id, you need to grab it from order["info"]["id"]'); + } + + async createDepositAddress (code, params = {}) { await this.loadMarkets (); const currency = this.currency (code); const request = { - 'currency_code': currency['id'], - 'amount': amount, + 'currency': currency['id'], + }; + const response = await this.privatePostAccountCryptoAddressCurrency (this.extend (request, params)); + const address = this.safeString (response, 'address'); + this.checkAddress (address); + const tag = this.safeString (response, 'paymentId'); + return { + 'currency': currency, + 'address': address, + 'tag': tag, + 'info': response, + }; + } + + async fetchDepositAddress (code, params = {}) { + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + }; + const response = await this.privateGetAccountCryptoAddressCurrency (this.extend (request, params)); + const address = this.safeString (response, 'address'); + this.checkAddress (address); + const tag = this.safeString (response, 'paymentId'); + return { + 'currency': currency['code'], + 'address': address, + 'tag': tag, + 'info': response, + }; + } + + async withdraw (code, amount, address, tag = undefined, params = {}) { + await this.loadMarkets (); + this.checkAddress (address); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + 'amount': parseFloat (amount), 'address': address, }; - if (tag !== undefined) { - request['extra_id'] = tag; + if (tag) { + request['paymentId'] = tag; } - const response = await this.paymentPostPayout (this.extend (request, params)); + const response = await this.privatePostAccountCryptoWithdraw (this.extend (request, params)); return { 'info': response, - 'id': response['transaction'], + 'id': response['id'], }; } @@ -974,62 +1467,61 @@ module.exports = class hitbtc extends Exchange { } sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = '/' + 'api' + '/' + this.version + '/' + api + '/' + this.implodeParams (path, params); - let query = this.omit (params, this.extractParams (path)); + let url = '/api/' + this.version + '/'; + const query = this.omit (params, this.extractParams (path)); if (api === 'public') { + url += api + '/' + this.implodeParams (path, params); if (Object.keys (query).length) { url += '?' + this.urlencode (query); } } else { this.checkRequiredCredentials (); - const nonce = this.nonce (); - const payload = { 'nonce': nonce, 'apikey': this.apiKey }; - query = this.extend (payload, query); + url += this.implodeParams (path, params); if (method === 'GET') { - url += '?' + this.urlencode (query); - } else { - url += '?' + this.urlencode (payload); - } - let auth = url; - if (method === 'POST') { if (Object.keys (query).length) { - body = this.urlencode (query); - auth += body; + url += '?' + this.urlencode (query); } + } else if (Object.keys (query).length) { + body = this.json (query); } + const payload = this.encode (this.apiKey + ':' + this.secret); + const auth = this.stringToBase64 (payload); headers = { - 'Content-Type': 'application/x-www-form-urlencoded', - 'X-Signature': this.hmac (this.encode (auth), this.encode (this.secret), 'sha512').toLowerCase (), + 'Authorization': 'Basic ' + this.decode (auth), + 'Content-Type': 'application/json', }; } - url = this.urls['api'] + url; + url = this.urls['api'][api] + url; return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } - async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - const response = await this.fetch2 (path, api, method, params, headers, body); - if ('code' in response) { - if ('ExecutionReport' in response) { - if (response['ExecutionReport']['orderRejectReason'] === 'orderExceedsLimit') { - throw new InsufficientFunds (this.id + ' ' + this.json (response)); + handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (response === undefined) { + return; + } + if (code >= 400) { + const feedback = this.id + ' ' + body; + // {"code":504,"message":"Gateway Timeout","description":""} + if ((code === 503) || (code === 504)) { + throw new ExchangeNotAvailable (feedback); + } + // fallback to default error handler on rate limit errors + // {"code":429,"message":"Too many requests","description":"Too many requests"} + if (code === 429) { + return; + } + // {"error":{"code":20002,"message":"Order not found","description":""}} + if (body[0] === '{') { + if ('error' in response) { + const errorCode = this.safeString (response['error'], 'code'); + this.throwExactlyMatchedException (this.exceptions, errorCode, feedback); + const message = this.safeString (response['error'], 'message'); + if (message === 'Duplicate clientOrderId') { + throw new InvalidOrder (feedback); + } } } - throw new ExchangeError (this.id + ' ' + this.json (response)); - } - return response; - } - - handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) { - if (!response) { - return; // fallback to default error handler - } - const error = this.safeValue (response, 'error'); - if (error) { - const code = this.safeValue (error, 'code'); - const feedback = this.id + ' ' + body; - this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback); - this.throwBroadlyMatchedException (this.exceptions['broad'], error, feedback); - throw new ExchangeError (feedback); // unknown error + throw new ExchangeError (feedback); } } }; diff --git a/TaskServer/node_modules/ccxt/js/hitbtc2.js b/TaskServer/node_modules/ccxt/js/hitbtc2.js index 502024ec2..145d70a92 100644 --- a/TaskServer/node_modules/ccxt/js/hitbtc2.js +++ b/TaskServer/node_modules/ccxt/js/hitbtc2.js @@ -3,1501 +3,15 @@ // --------------------------------------------------------------------------- const hitbtc = require ('./hitbtc'); -const { BadSymbol, PermissionDenied, ExchangeError, ExchangeNotAvailable, OrderNotFound, InsufficientFunds, InvalidOrder, RequestTimeout, AuthenticationError } = require ('./base/errors'); -const { TRUNCATE, DECIMAL_PLACES } = require ('./base/functions/number'); + // --------------------------------------------------------------------------- module.exports = class hitbtc2 extends hitbtc { describe () { + // this is a temporary stub for backward compatibility + // https://github.com/ccxt/ccxt/issues/6678 return this.deepExtend (super.describe (), { 'id': 'hitbtc2', - 'name': 'HitBTC', - 'countries': [ 'HK' ], - 'rateLimit': 1500, - 'version': '2', - 'has': { - 'createDepositAddress': true, - 'fetchDepositAddress': true, - 'CORS': true, - 'editOrder': true, - 'fetchCurrencies': true, - 'fetchOHLCV': true, - 'fetchTickers': true, - 'fetchOrder': true, - 'fetchOrders': false, - 'fetchOpenOrders': true, - 'fetchClosedOrders': true, - 'fetchMyTrades': true, - 'withdraw': true, - 'fetchOrderTrades': false, // not implemented yet - 'fetchDeposits': false, - 'fetchWithdrawals': false, - 'fetchTransactions': true, - 'fetchTradingFee': true, - }, - 'timeframes': { - '1m': 'M1', - '3m': 'M3', - '5m': 'M5', - '15m': 'M15', - '30m': 'M30', // default - '1h': 'H1', - '4h': 'H4', - '1d': 'D1', - '1w': 'D7', - '1M': '1M', - }, - 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/27766555-8eaec20e-5edc-11e7-9c5b-6dc69fc42f5e.jpg', - 'api': 'https://api.hitbtc.com', - 'www': 'https://hitbtc.com', - 'referral': 'https://hitbtc.com/?ref_id=5a5d39a65d466', - 'doc': [ - 'https://api.hitbtc.com', - 'https://github.com/hitbtc-com/hitbtc-api/blob/master/APIv2.md', - ], - 'fees': [ - 'https://hitbtc.com/fees-and-limits', - 'https://support.hitbtc.com/hc/en-us/articles/115005148605-Fees-and-limits', - ], - }, - 'api': { - 'public': { - 'get': [ - 'symbol', // Available Currency Symbols - 'symbol/{symbol}', // Get symbol info - 'currency', // Available Currencies - 'currency/{currency}', // Get currency info - 'ticker', // Ticker list for all symbols - 'ticker/{symbol}', // Ticker for symbol - 'trades/{symbol}', // Trades - 'orderbook/{symbol}', // Orderbook - 'candles/{symbol}', // Candles - ], - }, - 'private': { - 'get': [ - 'order', // List your current open orders - 'order/{clientOrderId}', // Get a single order by clientOrderId - 'trading/balance', // Get trading balance - 'trading/fee/all', // Get trading fee rate - 'trading/fee/{symbol}', // Get trading fee rate - 'history/trades', // Get historical trades - 'history/order', // Get historical orders - 'history/order/{id}/trades', // Get historical trades by specified order - 'account/balance', // Get main acccount balance - 'account/transactions', // Get account transactions - 'account/transactions/{id}', // Get account transaction by id - 'account/crypto/address/{currency}', // Get deposit crypro address - ], - 'post': [ - 'order', // Create new order - 'account/crypto/withdraw', // Withdraw crypro - 'account/crypto/address/{currency}', // Create new deposit crypro address - 'account/transfer', // Transfer amount to trading - ], - 'put': [ - 'order/{clientOrderId}', // Create new order - 'account/crypto/withdraw/{id}', // Commit withdraw crypro - ], - 'delete': [ - 'order', // Cancel all open orders - 'order/{clientOrderId}', // Cancel order - 'account/crypto/withdraw/{id}', // Rollback withdraw crypro - ], - 'patch': [ - 'order/{clientOrderId}', // Cancel Replace order - ], - }, - }, - 'fees': { - 'trading': { - 'tierBased': false, - 'percentage': true, - 'maker': 0.1 / 100, - 'taker': 0.2 / 100, - }, - 'funding': { - 'tierBased': false, - 'percentage': false, - 'withdraw': { - 'BTC': 0.001, - 'BCC': 0.0018, - 'ETH': 0.00958, - 'BCH': 0.0018, - 'USDT': 100, - 'DASH': 0.03, - 'BTG': 0.0005, - 'XRP': 0.509, - 'LTC': 0.003, - 'ZEC': 0.0001, - 'XMR': 0.09, - '1ST': 0.84, - 'ADX': 5.7, - 'AE': 6.7, - 'AEON': 0.01006, - 'AIR': 565, - 'AMM': 14, - 'AMP': 342, - 'ANT': 6.7, - 'ARDR': 1, - 'ARN': 18.5, - 'ART': 26, - 'ATB': 0.0004, - 'ATL': 27, - 'ATM': 504, - 'ATS': 860, - 'AVT': 1.9, - 'BAS': 113, - 'BCN': 0.1, - 'BET': 124, - 'BKB': 46, - 'BMC': 32, - 'BMT': 100, - 'BNT': 2.57, - 'BQX': 4.7, - 'BTCA': 351.21, - 'BTM': 40, - 'BTX': 0.04, - 'BUS': 0.004, - 'CAPP': 97, - 'CCT': 6, - 'CDT': 100, - 'CDX': 30, - 'CFI': 61, - 'CL': 13.85, - 'CLD': 0.88, - 'CND': 574, - 'CNX': 0.04, - 'COSS': 65, - 'CPAY': 5.487, - 'CSNO': 16, - 'CTR': 15, - 'CTX': 146, - 'CVC': 8.46, - 'DATA': 12.949, - 'DBIX': 0.0168, - 'DCN': 1280, - 'DCT': 0.02, - 'DDF': 342, - 'DENT': 1000, - 'DGB': 0.4, - 'DGD': 0.01, - 'DICE': 0.32, - 'DLT': 0.26, - 'DNT': 0.21, - 'DOGE': 2, - 'DOV': 34, - 'DRPU': 24, - 'DRT': 240, - 'DSH': 0.017, - 'EBET': 84, - 'EBTC': 20, - 'EBTCOLD': 6.6, - 'ECAT': 14, - 'EDG': 2, - 'EDO': 2.9, - 'EKO': 1136.36, - 'ELE': 0.00172, - 'ELM': 0.004, - 'EMC': 0.03, - 'MGO': 14, - 'ENJ': 163, - 'EOS': 1.5, - 'ERO': 34, - 'ETBS': 15, - 'ETC': 0.002, - 'ETP': 0.004, - 'EVX': 5.4, - 'EXN': 456, - 'FCN': 0.000005, - 'FRD': 65, - 'FUEL': 123.00105, - 'FUN': 202.9598309, - 'FYN': 1.849, - 'FYP': 66.13, - 'GAME': 0.004, - 'GNO': 0.0034, - 'GUP': 4, - 'GVT': 1.2, - 'HSR': 0.04, - 'HAC': 144, - 'HDG': 7, - 'HGT': 1082, - 'HPC': 0.4, - 'HVN': 120, - 'ICN': 0.55, - 'ICO': 34, - 'ICOS': 0.35, - 'IND': 76, - 'INDI': 790, - 'ITS': 15.0012, - 'IXT': 11, - 'KBR': 143, - 'KICK': 112, - 'KMD': 4, - 'LA': 41, - 'LEND': 388, - 'LAT': 1.44, - 'LIFE': 13000, - 'LRC': 27, - 'LSK': 0.3, - 'LOC': 11.076, - 'LUN': 0.34, - 'MAID': 5, - 'MANA': 143, - 'MCAP': 5.44, - 'MIPS': 43, - 'MNE': 1.33, - 'MSP': 121, - 'MCO': 0.357, - 'MTH': 92, - 'MYB': 3.9, - 'NDC': 165, - 'NEBL': 0.04, - 'NET': 3.96, - 'NTO': 998, - 'NGC': 2.368, - 'NXC': 13.39, - 'NXT': 3, - 'OAX': 15, - 'ODN': 0.004, - 'OMG': 2, - 'OPT': 335, - 'ORME': 2.8, - 'OTN': 0.57, - 'PAY': 3.1, - 'PIX': 96, - 'PLBT': 0.33, - 'PLR': 114, - 'PLU': 0.87, - 'POE': 784, - 'POLL': 3.5, - 'PPT': 2, - 'PRE': 32, - 'PRG': 39, - 'PRO': 41, - 'PRS': 60, - 'PTOY': 0.5, - 'QAU': 63, - 'QCN': 0.03, - 'QTUM': 0.04, - 'QVT': 64, - 'REP': 0.02, - 'RKC': 15, - 'RLC': 1.21, - 'RVT': 14, - 'SC': 30, - 'SAN': 2.24, - 'SBD': 0.03, - 'SCL': 2.6, - 'SISA': 1640, - 'SKIN': 407, - 'SWFTC': 352.94, - 'SMART': 0.4, - 'SMS': 0.0375, - 'SNC': 36, - 'SNGLS': 4, - 'SNM': 48, - 'SNT': 233, - 'STAR': 0.144, - 'STORM': 153.19, - 'STEEM': 0.01, - 'STRAT': 0.01, - 'SPF': 14.4, - 'STU': 14, - 'STX': 11, - 'SUB': 17, - 'SUR': 3, - 'SWT': 0.51, - 'TAAS': 0.91, - 'TBT': 2.37, - 'TFL': 15, - 'TIME': 0.03, - 'TIX': 7.1, - 'TKN': 1, - 'TGT': 173, - 'TKR': 84, - 'TNT': 90, - 'TRST': 1.6, - 'TRX': 270, - 'UET': 480, - 'UGT': 15, - 'UTT': 3, - 'VEN': 14, - 'VERI': 0.037, - 'VIB': 50, - 'VIBE': 145, - 'VOISE': 618, - 'WEALTH': 0.0168, - 'WINGS': 2.4, - 'WTC': 0.75, - 'WRC': 48, - 'XAUR': 3.23, - 'XDN': 0.01, - 'XEM': 15, - 'XUC': 0.9, - 'YOYOW': 140, - 'ZAP': 24, - 'ZRX': 23, - 'ZSC': 191, - }, - 'deposit': { - 'BTC': 0, - 'ETH': 0, - 'BCH': 0, - 'USDT': 0, - 'BTG': 0, - 'LTC': 0, - 'ZEC': 0, - 'XMR': 0, - '1ST': 0, - 'ADX': 0, - 'AE': 0, - 'AEON': 0, - 'AIR': 0, - 'AMP': 0, - 'ANT': 0, - 'ARDR': 0, - 'ARN': 0, - 'ART': 0, - 'ATB': 0, - 'ATL': 0, - 'ATM': 0, - 'ATS': 0, - 'AVT': 0, - 'BAS': 0, - 'BCN': 0, - 'BET': 0, - 'BKB': 0, - 'BMC': 0, - 'BMT': 0, - 'BNT': 0, - 'BQX': 0, - 'BTM': 0, - 'BTX': 0, - 'BUS': 0, - 'CCT': 0, - 'CDT': 0, - 'CDX': 0, - 'CFI': 0, - 'CLD': 0, - 'CND': 0, - 'CNX': 0, - 'COSS': 0, - 'CSNO': 0, - 'CTR': 0, - 'CTX': 0, - 'CVC': 0, - 'DBIX': 0, - 'DCN': 0, - 'DCT': 0, - 'DDF': 0, - 'DENT': 0, - 'DGB': 0, - 'DGD': 0, - 'DICE': 0, - 'DLT': 0, - 'DNT': 0, - 'DOGE': 0, - 'DOV': 0, - 'DRPU': 0, - 'DRT': 0, - 'DSH': 0, - 'EBET': 0, - 'EBTC': 0, - 'EBTCOLD': 0, - 'ECAT': 0, - 'EDG': 0, - 'EDO': 0, - 'ELE': 0, - 'ELM': 0, - 'EMC': 0, - 'EMGO': 0, - 'ENJ': 0, - 'EOS': 0, - 'ERO': 0, - 'ETBS': 0, - 'ETC': 0, - 'ETP': 0, - 'EVX': 0, - 'EXN': 0, - 'FRD': 0, - 'FUEL': 0, - 'FUN': 0, - 'FYN': 0, - 'FYP': 0, - 'GNO': 0, - 'GUP': 0, - 'GVT': 0, - 'HAC': 0, - 'HDG': 0, - 'HGT': 0, - 'HPC': 0, - 'HVN': 0, - 'ICN': 0, - 'ICO': 0, - 'ICOS': 0, - 'IND': 0, - 'INDI': 0, - 'ITS': 0, - 'IXT': 0, - 'KBR': 0, - 'KICK': 0, - 'LA': 0, - 'LAT': 0, - 'LIFE': 0, - 'LRC': 0, - 'LSK': 0, - 'LUN': 0, - 'MAID': 0, - 'MANA': 0, - 'MCAP': 0, - 'MIPS': 0, - 'MNE': 0, - 'MSP': 0, - 'MTH': 0, - 'MYB': 0, - 'NDC': 0, - 'NEBL': 0, - 'NET': 0, - 'NTO': 0, - 'NXC': 0, - 'NXT': 0, - 'OAX': 0, - 'ODN': 0, - 'OMG': 0, - 'OPT': 0, - 'ORME': 0, - 'OTN': 0, - 'PAY': 0, - 'PIX': 0, - 'PLBT': 0, - 'PLR': 0, - 'PLU': 0, - 'POE': 0, - 'POLL': 0, - 'PPT': 0, - 'PRE': 0, - 'PRG': 0, - 'PRO': 0, - 'PRS': 0, - 'PTOY': 0, - 'QAU': 0, - 'QCN': 0, - 'QTUM': 0, - 'QVT': 0, - 'REP': 0, - 'RKC': 0, - 'RVT': 0, - 'SAN': 0, - 'SBD': 0, - 'SCL': 0, - 'SISA': 0, - 'SKIN': 0, - 'SMART': 0, - 'SMS': 0, - 'SNC': 0, - 'SNGLS': 0, - 'SNM': 0, - 'SNT': 0, - 'STEEM': 0, - 'STRAT': 0, - 'STU': 0, - 'STX': 0, - 'SUB': 0, - 'SUR': 0, - 'SWT': 0, - 'TAAS': 0, - 'TBT': 0, - 'TFL': 0, - 'TIME': 0, - 'TIX': 0, - 'TKN': 0, - 'TKR': 0, - 'TNT': 0, - 'TRST': 0, - 'TRX': 0, - 'UET': 0, - 'UGT': 0, - 'VEN': 0, - 'VERI': 0, - 'VIB': 0, - 'VIBE': 0, - 'VOISE': 0, - 'WEALTH': 0, - 'WINGS': 0, - 'WTC': 0, - 'XAUR': 0, - 'XDN': 0, - 'XEM': 0, - 'XUC': 0, - 'YOYOW': 0, - 'ZAP': 0, - 'ZRX': 0, - 'ZSC': 0, - }, - }, - }, - 'options': { - 'defaultTimeInForce': 'FOK', - }, - 'exceptions': { - '504': RequestTimeout, // {"error":{"code":504,"message":"Gateway Timeout"}} - '1002': AuthenticationError, // {"error":{"code":1002,"message":"Authorization failed","description":""}} - '1003': PermissionDenied, // "Action is forbidden for this API key" - '2010': InvalidOrder, // "Quantity not a valid number" - '2001': BadSymbol, // "Symbol not found" - '2011': InvalidOrder, // "Quantity too low" - '2020': InvalidOrder, // "Price not a valid number" - '20002': OrderNotFound, // canceling non-existent order - '20001': InsufficientFunds, - }, }); } - - feeToPrecision (symbol, fee) { - return this.decimalToPrecision (fee, TRUNCATE, 8, DECIMAL_PLACES); - } - - async fetchMarkets (params = {}) { - const response = await this.publicGetSymbol (params); - const result = []; - for (let i = 0; i < response.length; i++) { - const market = response[i]; - const id = this.safeString (market, 'id'); - const baseId = this.safeString (market, 'baseCurrency'); - const quoteId = this.safeString (market, 'quoteCurrency'); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - const symbol = base + '/' + quote; - const lot = this.safeFloat (market, 'quantityIncrement'); - const step = this.safeFloat (market, 'tickSize'); - const precision = { - 'price': this.precisionFromString (market['tickSize']), - // FIXME: for lots > 1 the following line returns 0 - // 'amount': this.precisionFromString (market['quantityIncrement']), - 'amount': -1 * parseInt (Math.log10 (lot)), - }; - const taker = this.safeFloat (market, 'takeLiquidityRate'); - const maker = this.safeFloat (market, 'provideLiquidityRate'); - result.push (this.extend (this.fees['trading'], { - 'info': market, - 'id': id, - 'symbol': symbol, - 'base': base, - 'quote': quote, - 'baseId': baseId, - 'quoteId': quoteId, - 'active': true, - 'taker': taker, - 'maker': maker, - 'precision': precision, - 'limits': { - 'amount': { - 'min': lot, - 'max': undefined, - }, - 'price': { - 'min': step, - 'max': undefined, - }, - 'cost': { - 'min': lot * step, - 'max': undefined, - }, - }, - })); - } - return result; - } - - async fetchCurrencies (params = {}) { - const response = await this.publicGetCurrency (params); - const result = {}; - for (let i = 0; i < response.length; i++) { - const currency = response[i]; - const id = this.safeString (currency, 'id'); - // todo: will need to rethink the fees - // to add support for multiple withdrawal/deposit methods and - // differentiated fees for each particular method - const precision = 8; // default precision, todo: fix "magic constants" - const code = this.safeCurrencyCode (id); - const payin = this.safeValue (currency, 'payinEnabled'); - const payout = this.safeValue (currency, 'payoutEnabled'); - const transfer = this.safeValue (currency, 'transferEnabled'); - let active = payin && payout && transfer; - if ('disabled' in currency) { - if (currency['disabled']) { - active = false; - } - } - let type = 'fiat'; - if (('crypto' in currency) && currency['crypto']) { - type = 'crypto'; - } - const name = this.safeString (currency, 'fullName'); - result[code] = { - 'id': id, - 'code': code, - 'type': type, - 'payin': payin, - 'payout': payout, - 'transfer': transfer, - 'info': currency, - 'name': name, - 'active': active, - 'fee': this.safeFloat (currency, 'payoutFee'), // todo: redesign - 'precision': precision, - 'limits': { - 'amount': { - 'min': Math.pow (10, -precision), - 'max': Math.pow (10, precision), - }, - 'price': { - 'min': Math.pow (10, -precision), - 'max': Math.pow (10, precision), - }, - 'cost': { - 'min': undefined, - 'max': undefined, - }, - 'withdraw': { - 'min': undefined, - 'max': Math.pow (10, precision), - }, - }, - }; - } - return result; - } - - async fetchTradingFee (symbol, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const request = this.extend ({ - 'symbol': market['id'], - }, this.omit (params, 'symbol')); - const response = await this.privateGetTradingFeeSymbol (request); - // - // { - // takeLiquidityRate: '0.001', - // provideLiquidityRate: '-0.0001' - // } - // - return { - 'info': response, - 'maker': this.safeFloat (response, 'provideLiquidityRate'), - 'taker': this.safeFloat (response, 'takeLiquidityRate'), - }; - } - - async fetchBalance (params = {}) { - await this.loadMarkets (); - const type = this.safeString (params, 'type', 'trading'); - const method = 'privateGet' + this.capitalize (type) + 'Balance'; - const query = this.omit (params, 'type'); - const response = await this[method] (query); - const result = { 'info': response }; - for (let i = 0; i < response.length; i++) { - const balance = response[i]; - const currencyId = this.safeString (balance, 'currency'); - const code = this.safeCurrencyCode (currencyId); - const account = this.account (); - account['free'] = this.safeFloat (balance, 'available'); - account['used'] = this.safeFloat (balance, 'reserved'); - result[code] = account; - } - return this.parseBalance (result); - } - - parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) { - const timestamp = this.parse8601 (ohlcv['timestamp']); - return [ - timestamp, - parseFloat (ohlcv['open']), - parseFloat (ohlcv['max']), - parseFloat (ohlcv['min']), - parseFloat (ohlcv['close']), - parseFloat (ohlcv['volume']), - ]; - } - - async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'symbol': market['id'], - 'period': this.timeframes[timeframe], - }; - if (since !== undefined) { - request['from'] = this.iso8601 (since); - } - if (limit !== undefined) { - request['limit'] = limit; - } - const response = await this.publicGetCandlesSymbol (this.extend (request, params)); - return this.parseOHLCVs (response, market, timeframe, since, limit); - } - - async fetchOrderBook (symbol, limit = undefined, params = {}) { - await this.loadMarkets (); - const request = { - 'symbol': this.marketId (symbol), - }; - if (limit !== undefined) { - request['limit'] = limit; // default = 100, 0 = unlimited - } - const response = await this.publicGetOrderbookSymbol (this.extend (request, params)); - return this.parseOrderBook (response, undefined, 'bid', 'ask', 'price', 'size'); - } - - parseTicker (ticker, market = undefined) { - const timestamp = this.parse8601 (ticker['timestamp']); - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; - } - const baseVolume = this.safeFloat (ticker, 'volume'); - const quoteVolume = this.safeFloat (ticker, 'volumeQuote'); - const open = this.safeFloat (ticker, 'open'); - const last = this.safeFloat (ticker, 'last'); - let change = undefined; - let percentage = undefined; - let average = undefined; - if (last !== undefined && open !== undefined) { - change = last - open; - average = this.sum (last, open) / 2; - if (open > 0) { - percentage = change / open * 100; - } - } - let vwap = undefined; - if (quoteVolume !== undefined) { - if (baseVolume !== undefined) { - if (baseVolume > 0) { - vwap = quoteVolume / baseVolume; - } - } - } - return { - 'symbol': symbol, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'high': this.safeFloat (ticker, 'high'), - 'low': this.safeFloat (ticker, 'low'), - 'bid': this.safeFloat (ticker, 'bid'), - 'bidVolume': undefined, - 'ask': this.safeFloat (ticker, 'ask'), - 'askVolume': undefined, - 'vwap': vwap, - 'open': open, - 'close': last, - 'last': last, - 'previousClose': undefined, - 'change': change, - 'percentage': percentage, - 'average': average, - 'baseVolume': baseVolume, - 'quoteVolume': quoteVolume, - 'info': ticker, - }; - } - - async fetchTickers (symbols = undefined, params = {}) { - await this.loadMarkets (); - const response = await this.publicGetTicker (params); - const result = {}; - for (let i = 0; i < response.length; i++) { - const ticker = response[i]; - const marketId = this.safeString (ticker, 'symbol'); - if (marketId !== undefined) { - if (marketId in this.markets_by_id) { - const market = this.markets_by_id[marketId]; - const symbol = market['symbol']; - result[symbol] = this.parseTicker (ticker, market); - } else { - result[marketId] = this.parseTicker (ticker); - } - } - } - return result; - } - - async fetchTicker (symbol, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'symbol': market['id'], - }; - const response = await this.publicGetTickerSymbol (this.extend (request, params)); - if ('message' in response) { - throw new ExchangeError (this.id + ' ' + response['message']); - } - return this.parseTicker (response, market); - } - - parseTrade (trade, market = undefined) { - // - // createMarketOrder - // - // { fee: "0.0004644", - // id: 386394956, - // price: "0.4644", - // quantity: "1", - // timestamp: "2018-10-25T16:41:44.780Z" } - // - // fetchTrades ... - // - // fetchMyTrades ... - // - const timestamp = this.parse8601 (trade['timestamp']); - let symbol = undefined; - const marketId = this.safeString (trade, 'symbol'); - if (marketId !== undefined) { - if (marketId in this.markets_by_id) { - market = this.markets_by_id[marketId]; - symbol = market['symbol']; - } else { - symbol = marketId; - } - } - if (symbol === undefined) { - if (market !== undefined) { - symbol = market['symbol']; - } - } - let fee = undefined; - const feeCost = this.safeFloat (trade, 'fee'); - if (feeCost !== undefined) { - const feeCurrency = market ? market['quote'] : undefined; - fee = { - 'cost': feeCost, - 'currency': feeCurrency, - }; - } - // we use clientOrderId as the order id with HitBTC intentionally - // because most of their endpoints will require clientOrderId - // explained here: https://github.com/ccxt/ccxt/issues/5674 - const orderId = this.safeString (trade, 'clientOrderId'); - const price = this.safeFloat (trade, 'price'); - const amount = this.safeFloat (trade, 'quantity'); - const cost = price * amount; - const side = this.safeString (trade, 'side'); - const id = this.safeString (trade, 'id'); - return { - 'info': trade, - 'id': id, - 'order': orderId, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': symbol, - 'type': undefined, - 'side': side, - 'takerOrMaker': undefined, - 'price': price, - 'amount': amount, - 'cost': cost, - 'fee': fee, - }; - } - - async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - let currency = undefined; - const request = {}; - if (code !== undefined) { - currency = this.currency (code); - request['asset'] = currency['id']; - } - if (since !== undefined) { - request['startTime'] = since; - } - const response = await this.privateGetAccountTransactions (this.extend (request, params)); - return this.parseTransactions (response, currency, since, limit); - } - - parseTransaction (transaction, currency = undefined) { - // - // { - // id: 'd53ee9df-89bf-4d09-886e-849f8be64647', - // index: 1044718371, - // type: 'payout', - // status: 'success', - // currency: 'ETH', - // amount: '4.522683200000000000000000', - // createdAt: '2018-06-07T00:43:32.426Z', - // updatedAt: '2018-06-07T00:45:36.447Z', - // hash: '0x973e5683dfdf80a1fb1e0b96e19085b6489221d2ddf864daa46903c5ec283a0f', - // address: '0xC5a59b21948C1d230c8C54f05590000Eb3e1252c', - // fee: '0.00958', - // }, - // { - // id: 'e6c63331-467e-4922-9edc-019e75d20ba3', - // index: 1044714672, - // type: 'exchangeToBank', - // status: 'success', - // currency: 'ETH', - // amount: '4.532263200000000000', - // createdAt: '2018-06-07T00:42:39.543Z', - // updatedAt: '2018-06-07T00:42:39.683Z', - // }, - // { - // id: '3b052faa-bf97-4636-a95c-3b5260015a10', - // index: 1009280164, - // type: 'bankToExchange', - // status: 'success', - // currency: 'CAS', - // amount: '104797.875800000000000000', - // createdAt: '2018-05-19T02:34:36.750Z', - // updatedAt: '2018-05-19T02:34:36.857Z', - // }, - // { - // id: 'd525249f-7498-4c81-ba7b-b6ae2037dc08', - // index: 1009279948, - // type: 'payin', - // status: 'success', - // currency: 'CAS', - // amount: '104797.875800000000000000', - // createdAt: '2018-05-19T02:30:16.698Z', - // updatedAt: '2018-05-19T02:34:28.159Z', - // hash: '0xa6530e1231de409cf1f282196ed66533b103eac1df2aa4a7739d56b02c5f0388', - // address: '0xd53ed559a6d963af7cb3f3fcd0e7ca499054db8b', - // } - // - // { - // "id": "4f351f4f-a8ee-4984-a468-189ed590ddbd", - // "index": 3112719565, - // "type": "withdraw", - // "status": "success", - // "currency": "BCHOLD", - // "amount": "0.02423133", - // "createdAt": "2019-07-16T16:52:04.494Z", - // "updatedAt": "2019-07-16T16:54:07.753Z" - // } - const id = this.safeString (transaction, 'id'); - const timestamp = this.parse8601 (this.safeString (transaction, 'createdAt')); - const updated = this.parse8601 (this.safeString (transaction, 'updatedAt')); - const currencyId = this.safeString (transaction, 'currency'); - const code = this.safeCurrencyCode (currencyId, currency); - const status = this.parseTransactionStatus (this.safeString (transaction, 'status')); - const amount = this.safeFloat (transaction, 'amount'); - const address = this.safeString (transaction, 'address'); - const txid = this.safeString (transaction, 'hash'); - let fee = undefined; - const feeCost = this.safeFloat (transaction, 'fee'); - if (feeCost !== undefined) { - fee = { - 'cost': feeCost, - 'currency': code, - }; - } - const type = this.parseTransactionType (this.safeString (transaction, 'type')); - return { - 'info': transaction, - 'id': id, - 'txid': txid, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'address': address, - 'tag': undefined, - 'type': type, - 'amount': amount, - 'currency': code, - 'status': status, - 'updated': updated, - 'fee': fee, - }; - } - - parseTransactionStatus (status) { - const statuses = { - 'pending': 'pending', - 'failed': 'failed', - 'success': 'ok', - }; - return this.safeString (statuses, status, status); - } - - parseTransactionType (type) { - const types = { - 'payin': 'deposit', - 'payout': 'withdrawal', - 'withdraw': 'withdrawal', - }; - return this.safeString (types, type, type); - } - - async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'symbol': market['id'], - }; - if (limit !== undefined) { - request['limit'] = limit; - } - if (since !== undefined) { - request['sort'] = 'ASC'; - request['from'] = this.iso8601 (since); - } - const response = await this.publicGetTradesSymbol (this.extend (request, params)); - return this.parseTrades (response, market, since, limit); - } - - async createOrder (symbol, type, side, amount, price = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - // we use clientOrderId as the order id with HitBTC intentionally - // because most of their endpoints will require clientOrderId - // explained here: https://github.com/ccxt/ccxt/issues/5674 - // their max accepted length is 32 characters - const uuid = this.uuid (); - const parts = uuid.split ('-'); - let clientOrderId = parts.join (''); - clientOrderId = clientOrderId.slice (0, 32); - amount = parseFloat (amount); - const request = { - 'clientOrderId': clientOrderId, - 'symbol': market['id'], - 'side': side, - 'quantity': this.amountToPrecision (symbol, amount), - 'type': type, - }; - if (type === 'limit') { - request['price'] = this.priceToPrecision (symbol, price); - } else { - request['timeInForce'] = this.options['defaultTimeInForce']; - } - const response = await this.privatePostOrder (this.extend (request, params)); - const order = this.parseOrder (response); - if (order['status'] === 'rejected') { - throw new InvalidOrder (this.id + ' order was rejected by the exchange ' + this.json (order)); - } - const id = order['id']; - this.orders[id] = order; - return order; - } - - async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) { - await this.loadMarkets (); - // we use clientOrderId as the order id with HitBTC intentionally - // because most of their endpoints will require clientOrderId - // explained here: https://github.com/ccxt/ccxt/issues/5674 - // their max accepted length is 32 characters - const uuid = this.uuid (); - const parts = uuid.split ('-'); - let requestClientId = parts.join (''); - requestClientId = requestClientId.slice (0, 32); - const request = { - 'clientOrderId': id, - 'requestClientId': requestClientId, - }; - if (amount !== undefined) { - request['quantity'] = this.amountToPrecision (symbol, amount); - } - if (price !== undefined) { - request['price'] = this.priceToPrecision (symbol, price); - } - const response = await this.privatePatchOrderClientOrderId (this.extend (request, params)); - const order = this.parseOrder (response); - this.orders[order['id']] = order; - return order; - } - - async cancelOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - // we use clientOrderId as the order id with HitBTC intentionally - // because most of their endpoints will require clientOrderId - // explained here: https://github.com/ccxt/ccxt/issues/5674 - const request = { - 'clientOrderId': id, - }; - const response = await this.privateDeleteOrderClientOrderId (this.extend (request, params)); - return this.parseOrder (response); - } - - parseOrderStatus (status) { - const statuses = { - 'new': 'open', - 'suspended': 'open', - 'partiallyFilled': 'open', - 'filled': 'closed', - 'canceled': 'canceled', - 'expired': 'failed', - }; - return this.safeString (statuses, status, status); - } - - parseOrder (order, market = undefined) { - // - // createMarketOrder - // - // { clientOrderId: "fe36aa5e190149bf9985fb673bbb2ea0", - // createdAt: "2018-10-25T16:41:44.780Z", - // cumQuantity: "1", - // id: "66799540063", - // quantity: "1", - // side: "sell", - // status: "filled", - // symbol: "XRPUSDT", - // timeInForce: "FOK", - // tradesReport: [ { fee: "0.0004644", - // id: 386394956, - // price: "0.4644", - // quantity: "1", - // timestamp: "2018-10-25T16:41:44.780Z" } ], - // type: "market", - // updatedAt: "2018-10-25T16:41:44.780Z" } - // - const created = this.parse8601 (this.safeString (order, 'createdAt')); - const updated = this.parse8601 (this.safeString (order, 'updatedAt')); - const marketId = this.safeString (order, 'symbol'); - let symbol = undefined; - if (marketId !== undefined) { - if (marketId in this.markets_by_id) { - market = this.markets_by_id[marketId]; - symbol = market['symbol']; - } else { - symbol = marketId; - } - } - if (symbol === undefined) { - if (market !== undefined) { - symbol = market['id']; - } - } - const amount = this.safeFloat (order, 'quantity'); - const filled = this.safeFloat (order, 'cumQuantity'); - const status = this.parseOrderStatus (this.safeString (order, 'status')); - // we use clientOrderId as the order id with HitBTC intentionally - // because most of their endpoints will require clientOrderId - // explained here: https://github.com/ccxt/ccxt/issues/5674 - const id = this.safeString (order, 'clientOrderId'); - let price = this.safeFloat (order, 'price'); - if (price === undefined) { - if (id in this.orders) { - price = this.orders[id]['price']; - } - } - let remaining = undefined; - let cost = undefined; - if (amount !== undefined) { - if (filled !== undefined) { - remaining = amount - filled; - if (price !== undefined) { - cost = filled * price; - } - } - } - const type = this.safeString (order, 'type'); - const side = this.safeString (order, 'side'); - let trades = this.safeValue (order, 'tradesReport'); - let fee = undefined; - let average = undefined; - if (trades !== undefined) { - trades = this.parseTrades (trades, market); - let feeCost = undefined; - const numTrades = trades.length; - let tradesCost = 0; - for (let i = 0; i < numTrades; i++) { - if (feeCost === undefined) { - feeCost = 0; - } - tradesCost = this.sum (tradesCost, trades[i]['cost']); - const tradeFee = this.safeValue (trades[i], 'fee', {}); - const tradeFeeCost = this.safeFloat (tradeFee, 'cost'); - if (tradeFeeCost !== undefined) { - feeCost = this.sum (feeCost, tradeFeeCost); - } - } - cost = tradesCost; - if ((filled !== undefined) && (filled > 0)) { - average = cost / filled; - if (type === 'market') { - if (price === undefined) { - price = average; - } - } - } - if (feeCost !== undefined) { - fee = { - 'cost': feeCost, - 'currency': market['quote'], - }; - } - } - return { - 'id': id, - 'timestamp': created, - 'datetime': this.iso8601 (created), - 'lastTradeTimestamp': updated, - 'status': status, - 'symbol': symbol, - 'type': type, - 'side': side, - 'price': price, - 'average': average, - 'amount': amount, - 'cost': cost, - 'filled': filled, - 'remaining': remaining, - 'fee': fee, - 'trades': trades, - 'info': order, - }; - } - - async fetchOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - // we use clientOrderId as the order id with HitBTC intentionally - // because most of their endpoints will require clientOrderId - // explained here: https://github.com/ccxt/ccxt/issues/5674 - const request = { - 'clientOrderId': id, - }; - const response = await this.privateGetHistoryOrder (this.extend (request, params)); - const numOrders = response.length; - if (numOrders > 0) { - return this.parseOrder (response[0]); - } - throw new OrderNotFound (this.id + ' order ' + id + ' not found'); - } - - async fetchOpenOrder (id, symbol = undefined, params = {}) { - await this.loadMarkets (); - // we use clientOrderId as the order id with HitBTC intentionally - // because most of their endpoints will require clientOrderId - // explained here: https://github.com/ccxt/ccxt/issues/5674 - const request = { - 'clientOrderId': id, - }; - const response = await this.privateGetOrderClientOrderId (this.extend (request, params)); - return this.parseOrder (response); - } - - async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - let market = undefined; - const request = {}; - if (symbol !== undefined) { - market = this.market (symbol); - request['symbol'] = market['id']; - } - const response = await this.privateGetOrder (this.extend (request, params)); - return this.parseOrders (response, market, since, limit); - } - - async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - let market = undefined; - const request = {}; - if (symbol !== undefined) { - market = this.market (symbol); - request['symbol'] = market['id']; - } - if (limit !== undefined) { - request['limit'] = limit; - } - if (since !== undefined) { - request['from'] = this.iso8601 (since); - } - const response = await this.privateGetHistoryOrder (this.extend (request, params)); - const parsedOrders = this.parseOrders (response, market); - const orders = []; - for (let i = 0; i < parsedOrders.length; i++) { - const order = parsedOrders[i]; - const status = order['status']; - if ((status === 'closed') || (status === 'canceled')) { - orders.push (order); - } - } - return this.filterBySinceLimit (orders, since, limit); - } - - async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const request = { - // 'symbol': 'BTC/USD', // optional - // 'sort': 'DESC', // or 'ASC' - // 'by': 'timestamp', // or 'id' String timestamp by default, or id - // 'from': 'Datetime or Number', // ISO 8601 - // 'till': 'Datetime or Number', - // 'limit': 100, - // 'offset': 0, - }; - let market = undefined; - if (symbol !== undefined) { - market = this.market (symbol); - request['symbol'] = market['id']; - } - if (since !== undefined) { - request['from'] = this.iso8601 (since); - } - if (limit !== undefined) { - request['limit'] = limit; - } - const response = await this.privateGetHistoryTrades (this.extend (request, params)); - // - // [ - // { - // "id": 9535486, - // "clientOrderId": "f8dbaab336d44d5ba3ff578098a68454", - // "orderId": 816088377, - // "symbol": "ETHBTC", - // "side": "sell", - // "quantity": "0.061", - // "price": "0.045487", - // "fee": "0.000002775", - // "timestamp": "2017-05-17T12:32:57.848Z" - // }, - // { - // "id": 9535437, - // "clientOrderId": "27b9bfc068b44194b1f453c7af511ed6", - // "orderId": 816088021, - // "symbol": "ETHBTC", - // "side": "buy", - // "quantity": "0.038", - // "price": "0.046000", - // "fee": "-0.000000174", - // "timestamp": "2017-05-17T12:30:57.848Z" - // } - // ] - // - return this.parseTrades (response, market, since, limit); - } - - async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { - // The id needed here is the exchange's id, and not the clientOrderID, - // which is the id that is stored in the unified order id - // To get the exchange's id you need to grab it from order['info']['id'] - await this.loadMarkets (); - let market = undefined; - if (symbol !== undefined) { - market = this.market (symbol); - } - const request = { - 'id': id, - }; - const response = await this.privateGetHistoryOrderIdTrades (this.extend (request, params)); - const numOrders = response.length; - if (numOrders > 0) { - return this.parseTrades (response, market, since, limit); - } - throw new OrderNotFound (this.id + ' order ' + id + ' not found, ' + this.id + '.fetchOrderTrades() requires an exchange-specific order id, you need to grab it from order["info"]["id"]'); - } - - async createDepositAddress (code, params = {}) { - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'currency': currency['id'], - }; - const response = await this.privatePostAccountCryptoAddressCurrency (this.extend (request, params)); - const address = this.safeString (response, 'address'); - this.checkAddress (address); - const tag = this.safeString (response, 'paymentId'); - return { - 'currency': currency, - 'address': address, - 'tag': tag, - 'info': response, - }; - } - - async fetchDepositAddress (code, params = {}) { - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'currency': currency['id'], - }; - const response = await this.privateGetAccountCryptoAddressCurrency (this.extend (request, params)); - const address = this.safeString (response, 'address'); - this.checkAddress (address); - const tag = this.safeString (response, 'paymentId'); - return { - 'currency': currency['code'], - 'address': address, - 'tag': tag, - 'info': response, - }; - } - - async withdraw (code, amount, address, tag = undefined, params = {}) { - await this.loadMarkets (); - this.checkAddress (address); - const currency = this.currency (code); - const request = { - 'currency': currency['id'], - 'amount': parseFloat (amount), - 'address': address, - }; - if (tag) { - request['paymentId'] = tag; - } - const response = await this.privatePostAccountCryptoWithdraw (this.extend (request, params)); - return { - 'info': response, - 'id': response['id'], - }; - } - - sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = '/api/' + this.version + '/'; - const query = this.omit (params, this.extractParams (path)); - if (api === 'public') { - url += api + '/' + this.implodeParams (path, params); - if (Object.keys (query).length) { - url += '?' + this.urlencode (query); - } - } else { - this.checkRequiredCredentials (); - url += this.implodeParams (path, params); - if (method === 'GET') { - if (Object.keys (query).length) { - url += '?' + this.urlencode (query); - } - } else if (Object.keys (query).length) { - body = this.json (query); - } - const payload = this.encode (this.apiKey + ':' + this.secret); - const auth = this.stringToBase64 (payload); - headers = { - 'Authorization': 'Basic ' + this.decode (auth), - 'Content-Type': 'application/json', - }; - } - url = this.urls['api'] + url; - return { 'url': url, 'method': method, 'body': body, 'headers': headers }; - } - - handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { - if (response === undefined) { - return; - } - if (code >= 400) { - const feedback = this.id + ' ' + body; - // {"code":504,"message":"Gateway Timeout","description":""} - if ((code === 503) || (code === 504)) { - throw new ExchangeNotAvailable (feedback); - } - // fallback to default error handler on rate limit errors - // {"code":429,"message":"Too many requests","description":"Too many requests"} - if (code === 429) { - return; - } - // {"error":{"code":20002,"message":"Order not found","description":""}} - if (body[0] === '{') { - if ('error' in response) { - const errorCode = this.safeString (response['error'], 'code'); - this.throwExactlyMatchedException (this.exceptions, errorCode, feedback); - const message = this.safeString (response['error'], 'message'); - if (message === 'Duplicate clientOrderId') { - throw new InvalidOrder (feedback); - } - } - } - throw new ExchangeError (feedback); - } - } }; diff --git a/TaskServer/node_modules/ccxt/js/hollaex.js b/TaskServer/node_modules/ccxt/js/hollaex.js new file mode 100644 index 000000000..a4d080c94 --- /dev/null +++ b/TaskServer/node_modules/ccxt/js/hollaex.js @@ -0,0 +1,1230 @@ +'use strict'; + +// --------------------------------------------------------------------------- + +const Exchange = require ('./base/Exchange'); +const { BadRequest, AuthenticationError, NetworkError, ArgumentsRequired, OrderNotFound, InsufficientFunds } = require ('./base/errors'); +const { TICK_SIZE } = require ('./base/functions/number'); + +// --------------------------------------------------------------------------- + +module.exports = class hollaex extends Exchange { + describe () { + return this.deepExtend (super.describe (), { + 'id': 'hollaex', + 'name': 'HollaEx', + 'countries': [ 'KR' ], + 'rateLimit': 333, + 'version': 'v1', + 'has': { + 'CORS': false, + 'fetchMarkets': true, + 'fetchCurrencies': true, + 'fetchTicker': true, + 'fetchTickers': true, + 'fetchOrderBook': true, + 'fetchOrderBooks': true, + 'fetchTrades': true, + 'fetchOHLCV': true, + 'fetchBalance': true, + 'createOrder': true, + 'createLimitBuyOrder': true, + 'createLimitSellOrder': true, + 'createMarketBuyOrder': true, + 'createMarketSellOrder': true, + 'cancelOrder': true, + 'cancelAllOrders': true, + 'fetchOpenOrders': true, + 'fetchClosedOrders': false, + 'fetchOpenOrder': true, + 'fetchOrder': false, + 'fetchDeposits': true, + 'fetchWithdrawals': true, + 'fetchTransactions': false, + 'fetchOrders': false, + 'fetchMyTrades': true, + 'withdraw': true, + 'fetchDepositAddress': true, + }, + 'timeframes': { + '1h': '1h', + '1d': '1d', + }, + 'urls': { + 'logo': 'https://user-images.githubusercontent.com/1294454/75841031-ca375180-5ddd-11ea-8417-b975674c23cb.jpg', + 'api': 'https://api.hollaex.com', + 'www': 'https://hollaex.com', + 'doc': 'https://apidocs.hollaex.com', + 'referral': 'https://pro.hollaex.com/signup?affiliation_code=QSWA6G', + }, + 'precisionMode': TICK_SIZE, + 'requiredCredentials': { + 'apiKey': true, + 'secret': true, + }, + 'api': { + 'public': { + 'get': [ + 'health', + 'constant', + 'ticker', + 'ticker/all', + 'orderbooks', + 'trades', + 'chart', + // TradingView data + 'udf/config', + 'udf/history', + 'udf/symbols', + ], + }, + 'private': { + 'get': [ + 'user', + 'user/balance', + 'user/trades', + 'user/orders', + 'user/orders/{order_id}', + 'user/deposits', + 'user/withdrawals', + 'user/withdraw/{currency}/fee', + ], + 'post': [ + 'user/request-withdrawal', + 'order', + ], + 'delete': [ + 'user/orders', + 'user/orders/{order_id}', + ], + }, + }, + 'fees': { + 'trading': { + 'tierBased': true, + 'percentage': true, + }, + }, + 'exceptions': { + 'broad': { + 'Invalid token': AuthenticationError, + 'Order not found': OrderNotFound, + 'Insufficient balance': InsufficientFunds, + }, + 'exact': { + '400': BadRequest, + '403': AuthenticationError, + '404': BadRequest, + '405': BadRequest, + '410': BadRequest, + '429': BadRequest, + '500': NetworkError, + '503': NetworkError, + }, + }, + 'options': { + // how many seconds before the authenticated request expires + 'api-expires': parseInt (this.timeout / 1000), + }, + }); + } + + async fetchMarkets (params = {}) { + const response = await this.publicGetConstant (params); + // + // { + // coins: { + // xmr: { + // id: 7, + // fullname: "Monero", + // symbol: "xmr", + // active: true, + // allow_deposit: true, + // allow_withdrawal: true, + // withdrawal_fee: 0.02, + // min: 0.001, + // max: 100000, + // increment_unit: 0.001, + // deposit_limits: { '1': 0, '2': 0, '3': 0, '4': 0, '5': 0, '6': 0 }, + // withdrawal_limits: { '1': 10, '2': 15, '3': 100, '4': 100, '5': 200, '6': 300, '7': 350, '8': 400, '9': 500, '10': -1 }, + // created_at: "2019-12-09T07:14:02.720Z", + // updated_at: "2020-01-16T12:12:53.162Z" + // }, + // // ... + // }, + // pairs: { + // 'btc-usdt': { + // id: 2, + // name: "btc-usdt", + // pair_base: "btc", + // pair_2: "usdt", + // taker_fees: { '1': 0.3, '2': 0.25, '3': 0.2, '4': 0.18, '5': 0.1, '6': 0.09, '7': 0.08, '8': 0.06, '9': 0.04, '10': 0 }, + // maker_fees: { '1': 0.1, '2': 0.08, '3': 0.05, '4': 0.03, '5': 0, '6': 0, '7': 0, '8': 0, '9': 0, '10': 0 }, + // min_size: 0.0001, + // max_size: 1000, + // min_price: 100, + // max_price: 100000, + // increment_size: 0.0001, + // increment_price: 0.05, + // active: true, + // created_at: "2019-12-09T07:15:54.537Z", + // updated_at: "2019-12-09T07:15:54.537Z" + // }, + // }, + // config: { tiers: 10 }, + // status: true + // } + // + const pairs = this.safeValue (response, 'pairs', {}); + const keys = Object.keys (pairs); + const result = []; + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const market = pairs[key]; + const id = this.safeString (market, 'name'); + const baseId = this.safeString (market, 'pair_base'); + const quoteId = this.safeString (market, 'pair_2'); + const base = this.commonCurrencyCode (baseId.toUpperCase ()); + const quote = this.commonCurrencyCode (quoteId.toUpperCase ()); + const symbol = base + '/' + quote; + const active = this.safeValue (market, 'active'); + result.push ({ + 'id': id, + 'symbol': symbol, + 'base': base, + 'quote': quote, + 'baseId': baseId, + 'quoteId': quoteId, + 'active': active, + 'precision': { + 'price': this.safeFloat (market, 'increment_price'), + 'amount': this.safeFloat (market, 'increment_size'), + }, + 'limits': { + 'amount': { + 'min': this.safeFloat (market, 'min_size'), + 'max': this.safeFloat (market, 'max_size'), + }, + 'price': { + 'min': this.safeFloat (market, 'min_price'), + 'max': this.safeFloat (market, 'max_price'), + }, + 'cost': { 'min': undefined, 'max': undefined }, + }, + 'info': market, + }); + } + return result; + } + + async fetchCurrencies (params = {}) { + const response = await this.publicGetConstant (params); + const coins = this.safeValue (response, 'coins', {}); + const keys = Object.keys (coins); + const result = {}; + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const currency = coins[key]; + const id = this.safeString (currency, 'symbol'); + const numericId = this.safeInteger (currency, 'id'); + const code = this.safeCurrencyCode (id); + const name = this.safeString (currency, 'fullname'); + const active = this.safeValue (currency, 'active'); + const fee = this.safeFloat (currency, 'withdrawal_fee'); + const precision = this.safeFloat (currency, 'increment_unit'); + const withdrawalLimits = this.safeValue (currency, 'withdrawal_limits', []); + result[code] = { + 'id': id, + 'numericId': numericId, + 'code': code, + 'info': currency, + 'name': name, + 'active': active, + 'fee': fee, + 'precision': precision, + 'limits': { + 'amount': { + 'min': this.safeFloat (currency, 'min'), + 'max': this.safeFloat (currency, 'max'), + }, + 'price': { + 'min': undefined, + 'max': undefined, + }, + 'cost': { + 'min': undefined, + 'max': undefined, + }, + 'withdraw': { + 'min': undefined, + 'max': this.safeValue (withdrawalLimits, 0), + }, + }, + }; + } + return result; + } + + async fetchOrderBooks (symbols = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const response = await this.publicGetOrderbooks (params); + const result = {}; + const marketIds = Object.keys (response); + for (let i = 0; i < marketIds.length; i++) { + const marketId = marketIds[i]; + const orderbook = response[marketId]; + let symbol = marketId; + if (marketId in this.markets_by_id) { + const market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + const [ baseId, quoteId ] = marketId.split ('-'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + const timestamp = this.parse8601 (this.safeString (orderbook, 'timestamp')); + result[symbol] = this.parseOrderBook (response[marketId], timestamp); + } + return result; + } + + async fetchOrderBook (symbol, limit = undefined, params = {}) { + await this.loadMarkets (); + const marketId = this.marketId (symbol); + const request = { + 'symbol': marketId, + }; + const response = await this.publicGetOrderbooks (this.extend (request, params)); + // + // { + // "btc-usdt": { + // "bids": [ + // [ 8836.4, 1.022 ], + // [ 8800, 0.0668 ], + // [ 8797.75, 0.2398 ], + // ], + // "asks": [ + // [ 8839.35, 1.5334 ], + // [ 8852.6, 0.0579 ], + // [ 8860.45, 0.1815 ], + // ], + // "timestamp": "2020-03-03T02:27:25.147Z" + // }, + // "eth-usdt": {}, + // // ... + // } + // + const orderbook = this.safeValue (response, marketId); + const timestamp = this.parse8601 (this.safeString (orderbook, 'timestamp')); + return this.parseOrderBook (orderbook, timestamp); + } + + async fetchTicker (symbol, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.publicGetTicker (this.extend (request, params)); + // + // { + // open: 8615.55, + // close: 8841.05, + // high: 8921.1, + // low: 8607, + // last: 8841.05, + // volume: 20.2802, + // timestamp: '2020-03-03T03:11:18.964Z' + // } + // + return this.parseTicker (response, market); + } + + async fetchTickers (symbols = undefined, params = {}) { + await this.loadMarkets (); + const response = await this.publicGetTickerAll (this.extend (params)); + // + // { + // "bch-usdt": { + // "time": "2020-03-02T04:29:45.011Z", + // "open": 341.65, + // "close":337.9, + // "high":341.65, + // "low":337.3, + // "last":337.9, + // "volume":0.054, + // "symbol":"bch-usdt" + // }, + // // ... + // } + // + return this.parseTickers (response, symbols); + } + + parseTickers (response, symbols = undefined) { + const result = {}; + const keys = Object.keys (response); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const ticker = response[key]; + let symbol = key; + let market = undefined; + const marketId = this.safeString (ticker, 'symbol', key); + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + const [ baseId, quoteId ] = marketId.split ('-'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + result[symbol] = this.parseTicker (ticker, market); + } + return this.filterByArray (result, 'symbol', symbols); + } + + parseTicker (ticker, market = undefined) { + // + // fetchTicker + // + // { + // open: 8615.55, + // close: 8841.05, + // high: 8921.1, + // low: 8607, + // last: 8841.05, + // volume: 20.2802, + // timestamp: '2020-03-03T03:11:18.964Z', + // } + // + // fetchTickers + // + // { + // "time": "2020-03-02T04:29:45.011Z", + // "open": 341.65, + // "close": 337.9, + // "high": 341.65, + // "low": 337.3, + // "last": 337.9, + // "volume": 0.054, + // "symbol": "bch-usdt" + // } + // + let symbol = undefined; + const marketId = this.safeString (ticker, 'symbol'); + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + const [ baseId, quoteId ] = marketId.split ('-'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const timestamp = this.parse8601 (this.safeString2 (ticker, 'time', 'timestamp')); + const close = this.safeFloat (ticker, 'close'); + const result = { + 'symbol': symbol, + 'info': ticker, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'high': this.safeFloat (ticker, 'high'), + 'low': this.safeFloat (ticker, 'low'), + 'bid': undefined, + 'bidVolume': undefined, + 'ask': undefined, + 'askVolume': undefined, + 'vwap': undefined, + 'open': this.safeFloat (ticker, 'open'), + 'close': close, + 'last': this.safeFloat (ticker, 'last', close), + 'previousClose': undefined, + 'change': undefined, + 'percentage': undefined, + 'average': undefined, + 'baseVolume': this.safeFloat (ticker, 'volume'), + 'quoteVolume': undefined, + }; + return result; + } + + async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.publicGetTrades (this.extend (request, params)); + // + // { + // "btc-usdt": [ + // { + // "size": 0.5, + // "price": 8830, + // "side": "buy", + // "timestamp": "2020-03-03T04:44:33.034Z" + // }, + // // ... + // ] + // } + // + const trades = await this.safeValue (response, market['id'], []); + return this.parseTrades (trades, market, since, limit); + } + + parseTrade (trade, market = undefined) { + // + // fetchTrades (public) + // + // { + // "size": 0.5, + // "price": 8830, + // "side": "buy", + // "timestamp": "2020-03-03T04:44:33.034Z" + // } + // + // fetchMyTrades (private) + // + // { + // "side": "buy", + // "symbol": "eth-usdt", + // "size": 0.086, + // "price": 226.19, + // "timestamp": "2020-03-03T08:03:55.459Z", + // "fee": 0.1 + // } + // + let symbol = undefined; + const marketId = this.safeString (trade, 'symbol'); + let quote = undefined; + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + const [ baseId, quoteId ] = marketId.split ('-'); + const base = this.safeCurrencyCode (baseId); + quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const datetime = this.safeString (trade, 'timestamp'); + const timestamp = this.parse8601 (datetime); + const side = this.safeString (trade, 'side'); + const price = this.safeFloat (trade, 'price'); + const amount = this.safeFloat (trade, 'size'); + let cost = undefined; + if (price !== undefined) { + if (amount !== undefined) { + cost = price * amount; + } + } + const feeCost = this.safeFloat (trade, 'fee'); + let fee = undefined; + if (feeCost !== undefined) { + const feeCurrencyCode = (market !== undefined) ? market['quote'] : quote; + fee = { + 'cost': feeCost, + 'currency': feeCurrencyCode, + }; + } + const result = { + 'info': trade, + 'id': undefined, + 'timestamp': timestamp, + 'datetime': datetime, + 'symbol': symbol, + 'order': undefined, + 'type': undefined, + 'side': side, + 'takerOrMaker': undefined, + 'price': price, + 'amount': amount, + 'cost': cost, + 'fee': fee, + }; + return result; + } + + async fetchOHLCV (symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + 'resolution': this.timeframes[timeframe], + }; + const duration = this.parseTimeframe (timeframe); + if (since === undefined) { + if (limit === undefined) { + throw new ArgumentsRequired (this.id + " fetchOHLCV requires a 'since' or a 'limit' argument"); + } else { + const end = this.seconds (); + const start = end - duration * limit; + request['to'] = end; + request['from'] = start; + } + } else { + if (limit === undefined) { + request['from'] = parseInt (since / 1000); + request['to'] = this.seconds (); + } else { + const start = parseInt (since / 1000); + request['from'] = start; + request['to'] = this.sum (start, duration * limit); + } + } + const response = await this.publicGetChart (this.extend (request, params)); + // + // [ + // { + // "time":"2020-03-02T20:00:00.000Z", + // "close":8872.1, + // "high":8872.1, + // "low":8858.6, + // "open":8858.6, + // "symbol":"btc-usdt", + // "volume":1.2922 + // }, + // ] + // + return this.parseOHLCVs (response, market, timeframe, since, limit); + } + + parseOHLCV (response, market = undefined, timeframe = '1h', since = undefined, limit = undefined) { + // + // { + // "time":"2020-03-02T20:00:00.000Z", + // "close":8872.1, + // "high":8872.1, + // "low":8858.6, + // "open":8858.6, + // "symbol":"btc-usdt", + // "volume":1.2922 + // } + // + return [ + this.parse8601 (this.safeString (response, 'time')), + this.safeFloat (response, 'open'), + this.safeFloat (response, 'high'), + this.safeFloat (response, 'low'), + this.safeFloat (response, 'close'), + this.safeFloat (response, 'volume'), + ]; + } + + async fetchBalance (params = {}) { + await this.loadMarkets (); + const response = await this.privateGetUserBalance (params); + // + // { + // "updated_at": "2020-03-02T22:27:38.428Z", + // "btc_balance": 0, + // "btc_pending": 0, + // "btc_available": 0, + // "eth_balance": 0, + // "eth_pending": 0, + // "eth_available": 0, + // // ... + // } + // + const result = { 'info': response }; + const currencyIds = Object.keys (this.currencies_by_id); + for (let i = 0; i < currencyIds.length; i++) { + const currencyId = currencyIds[i]; + const code = this.safeCurrencyCode (currencyId); + const account = this.account (); + account['free'] = this.safeFloat (response, currencyId + '_available'); + account['total'] = this.safeFloat (response, currencyId + '_balance'); + result[code] = account; + } + return this.parseBalance (result); + } + + async fetchOpenOrder (id, symbol = undefined, params = {}) { + await this.loadMarkets (); + const request = { + 'order_id': id, + }; + const response = await this.privateGetUserOrdersOrderId (this.extend (request, params)); + // + // { + // "created_at": "2018-03-23T04:14:08.663Z", + // "title": "string", + // "side": "sell", + // "type": "limit", + // "price": 0, + // "size": 0, + // "symbol": "xht-usdt", + // "id": "string", + // "created_by": 1, + // "filled": 0 + // } + // + return this.parseOrder (response); + } + + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + let market = undefined; + const request = {}; + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + } + const response = await this.privateGetUserOrders (this.extend (request, params)); + // + // [ + // { + // "created_at":"2020-03-03T08:02:18.639Z", + // "title":"5419ff3f-9d25-4af7-bcc2-803926518d76", + // "side":"buy", + // "type":"limit", + // "price":226.19, + // "size":0.086, + // "symbol":"eth-usdt", + // "id":"5419ff3f-9d25-4af7-bcc2-803926518d76", + // "created_by":620, + // "filled":0 + // } + // ] + // + return this.parseOrders (response, market); + } + + parseOrder (order, market = undefined) { + // + // fetchOpenOrder, fetchOpenOrders + // + // { + // "created_at":"2020-03-03T08:02:18.639Z", + // "title":"5419ff3f-9d25-4af7-bcc2-803926518d76", + // "side":"buy", + // "type":"limit", + // "price":226.19, + // "size":0.086, + // "symbol":"eth-usdt", + // "id":"5419ff3f-9d25-4af7-bcc2-803926518d76", + // "created_by":620, + // "filled":0 + // } + // + let symbol = undefined; + const marketId = this.safeString (order, 'symbol'); + if (marketId !== undefined) { + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + const [ baseId, quoteId ] = marketId.split ('-'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const id = this.safeString (order, 'id'); + const timestamp = this.parse8601 (this.safeString (order, 'created_at')); + const type = this.safeString (order, 'type'); + const side = this.safeString (order, 'side'); + const price = this.safeFloat (order, 'price'); + const amount = this.safeFloat (order, 'size'); + const filled = this.safeFloat (order, 'filled'); + let cost = undefined; + let remaining = undefined; + if (filled !== undefined) { + if (amount !== undefined) { + remaining = amount - filled; + } + if (price !== undefined) { + cost = filled * price; + } + } + const status = (type === 'market') ? 'closed' : 'open'; + const result = { + 'id': id, + 'clientOrderId': undefined, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': undefined, + 'status': status, + 'symbol': symbol, + 'type': type, + 'side': side, + 'price': price, + 'amount': amount, + 'filled': filled, + 'remaining': remaining, + 'cost': cost, + 'trades': undefined, + 'fee': undefined, + 'info': order, + 'average': undefined, + }; + return result; + } + + async createOrder (symbol, type, side, amount, price = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const order = { + 'symbol': market['id'], + 'side': side, + 'size': amount, + 'type': type, + }; + if (type !== 'market') { + order['price'] = price; + } + const response = await this.privatePostOrder (this.extend (order, params)); + // + // { + // "symbol": "xht-usdt", + // "side": "sell", + // "size": 1, + // "type": "limit", + // "price": 0.1, + // "id": "string", + // "created_by": 34, + // "filled": 0, + // "status": "pending" + // } + // + return this.parseOrder (response, market); + } + + async cancelOrder (id, symbol = undefined, params = {}) { + await this.loadMarkets (); + const request = { + 'order_id': id, + }; + const response = await this.privateDeleteUserOrdersOrderId (this.extend (request, params)); + // + // { + // "title": "string", + // "symbol": "xht-usdt", + // "side": "sell", + // "size": 1, + // "type": "limit", + // "price": 0.1, + // "id": "string", + // "created_by": 34, + // "filled": 0 + // } + // + return this.parseOrder (response); + } + + async cancelAllOrders (symbol = undefined, params = {}) { + await this.loadMarkets (); + const request = {}; + let market = undefined; + if (symbol !== undefined) { + market = this.markets (symbol); + request['symbol'] = market['id']; + } + const response = await this.privateDeleteUserOrders (this.extend (request, params)); + // + // [ + // { + // "title": "string", + // "symbol": "xht-usdt", + // "side": "sell", + // "size": 1, + // "type": "limit", + // "price": 0.1, + // "id": "string", + // "created_by": 34, + // "filled": 0 + // } + // ] + // + return this.parseOrders (response, market); + } + + async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'symbol': market['id'], + // 'limit': 50, // default 50, max 100 + // 'page': 1, // page of data to retrieve + // 'order_by': 'timestamp', // field to order data + // 'order': 'asc', // asc or desc + // 'start_date': 123, // starting date of queried data + // 'end_date': 321, // ending date of queried data + }; + let market = undefined; + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + } + if (limit !== undefined) { + request['limit'] = limit; // default 50, max 100 + } + if (since !== undefined) { + request['start_date'] = this.iso8601 (since); + } + const response = await this.privateGetUserTrades (this.extend (request, params)); + // + // { + // "count": 1, + // "data": [ + // { + // "side": "buy", + // "symbol": "eth-usdt", + // "size": 0.086, + // "price": 226.19, + // "timestamp": "2020-03-03T08:03:55.459Z", + // "fee": 0.1 + // } + // ] + // } + // + const data = this.safeValue (response, 'data', []); + return this.parseTrades (data, market, since, limit); + } + + async fetchDepositAddress (code, params = {}) { + await this.loadMarkets (); + const currency = this.currency (code); + const response = await this.privateGetUser (params); + // + // { + // "id": 620, + // "email": "email@gmail.com", + // "full_name": "", + // "name_verified": false, + // "gender": false, + // "nationality": "", + // "phone_number": "", + // "address": { "city": "", "address": "", "country": "", "postal_code": "" }, + // "id_data": { "note": "", "type": "", "number": "", "status": 0 }, + // "bank_account":[], + // "crypto_wallet":{ + // "xrp": "rJtoECs6rPkJoAfgtR8SDDshV6hRHe3X7y:391496555" + // "usdt":"0x1fb4248e167901dfa0d8cdda2243a2126d7ce48d" + // // ... + // }, + // "verification_level": 1, + // "otp_enabled": true, + // "activated": true, + // "note": "", + // "username": "user", + // "affiliation_code": "QSWA6G", + // "settings": { + // "chat": { "set_username": false }, + // "risk": { "order_portfolio_percentage": 20 }, + // "audio": { + // "public_trade": false, + // "order_completed": true, + // "order_partially_completed": true + // }, + // "language": "en", + // "interface": { "theme": "white","order_book_levels": 10 }, + // "notification": { + // "popup_order_completed": true, + // "popup_order_confirmation": true, + // "popup_order_partially_filled": true + // } + // }, + // "flagged": false, + // "is_hap": false, + // "pin": false, + // "discount": 0, + // "created_at": "2020-03-02T22:27:38.331Z", + // "updated_at": "2020-03-03T07:54:58.315Z", + // "balance": { + // "xht_balance": 0, + // "xht_pending": 0, + // "xht_available": 0, + // // ... + // "updated_at": "2020-03-03T10:21:05.430Z" + // }, + // "images": [], + // "fees": { + // "btc-usdt": { "maker_fee": 0.1, "taker_fee": 0.3 }, + // "eth-usdt": { "maker_fee": 0.1, "taker_fee": 0.3 }, + // // ... + // } + // } + // + const cryptoWallet = this.safeValue (response, 'crypto_wallet'); + let address = this.safeString (cryptoWallet, currency['id']); + let tag = undefined; + if (address !== undefined) { + const parts = address.split (':'); + address = this.safeString (parts, 0); + tag = this.safeString (parts, 1); + } + this.checkAddress (address); + return { + 'currency': code, + 'address': address, + 'tag': tag, + 'info': response, + }; + } + + async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'currency': currency['id'], + // 'limit': 50, // default 50, max 100 + // 'page': 1, // page of data to retrieve + // 'order_by': 'timestamp', // field to order data + // 'order': 'asc', // asc or desc + // 'start_date': 123, // starting date of queried data + // 'end_date': 321, // ending date of queried data + }; + let currency = undefined; + if (code !== undefined) { + currency = this.currency (code); + request['currency'] = currency['id']; + } + if (limit !== undefined) { + request['limit'] = limit; // default 50, max 100 + } + if (since !== undefined) { + request['start_date'] = this.iso8601 (since); + } + const response = await this.privateGetUserDeposits (this.extend (request, params)); + // + // { + // "count": 1, + // "data": [ + // { + // "id": 539, + // "amount": 20, + // "fee": 0, + // "address": "0x5c0cc98270d7089408fcbcc8e2131287f5be2306", + // "transaction_id": "0xd4006327a5ec2c41adbdcf566eaaba6597c3d45906abe78ea1a4a022647c2e28", + // "status": true, + // "dismissed": false, + // "rejected": false, + // "description": "", + // "type": "deposit", + // "currency": "usdt", + // "created_at": "2020-03-03T07:56:36.198Z", + // "updated_at": "2020-03-03T08:00:05.674Z", + // "user_id": 620 + // } + // ] + // } + // + const data = this.safeValue (response, 'data', []); + return this.parseTransactions (data, currency, since, limit); + } + + async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = { + // 'currency': currency['id'], + // 'limit': 50, // default 50, max 100 + // 'page': 1, // page of data to retrieve + // 'order_by': 'timestamp', // field to order data + // 'order': 'asc', // asc or desc + // 'start_date': 123, // starting date of queried data + // 'end_date': 321, // ending date of queried data + }; + let currency = undefined; + if (code !== undefined) { + currency = this.currency (code); + request['currency'] = currency['id']; + } + if (limit !== undefined) { + request['limit'] = limit; // default 50, max 100 + } + if (since !== undefined) { + request['start_date'] = this.iso8601 (since); + } + const response = await this.privateGetUserWithdrawals (this.extend (request, params)); + // + // { + // "count": 1, + // "data": [ + // { + // "id": 539, + // "amount": 20, + // "fee": 0, + // "address": "0x5c0cc98270d7089408fcbcc8e2131287f5be2306", + // "transaction_id": "0xd4006327a5ec2c41adbdcf566eaaba6597c3d45906abe78ea1a4a022647c2e28", + // "status": true, + // "dismissed": false, + // "rejected": false, + // "description": "", + // "type": "withdrawal", + // "currency": "usdt", + // "created_at": "2020-03-03T07:56:36.198Z", + // "updated_at": "2020-03-03T08:00:05.674Z", + // "user_id": 620 + // } + // ] + // } + // + const data = this.safeValue (response, 'data', []); + return this.parseTransactions (data, currency, since, limit); + } + + parseTransaction (transaction, currency = undefined) { + // + // { + // "id": 539, + // "amount": 20, + // "fee": 0, + // "address": "0x5c0cc98270d7089408fcbcc8e2131287f5be2306", + // "transaction_id": "0xd4006327a5ec2c41adbdcf566eaaba6597c3d45906abe78ea1a4a022647c2e28", + // "status": true, + // "dismissed": false, + // "rejected": false, + // "description": "", + // "type": "withdrawal", + // "currency": "usdt", + // "created_at": "2020-03-03T07:56:36.198Z", + // "updated_at": "2020-03-03T08:00:05.674Z", + // "user_id": 620 + // } + // + const id = this.safeString (transaction, 'id'); + const txid = this.safeString (transaction, 'transaction_id'); + const timestamp = this.parse8601 (this.safeString (transaction, 'created_at')); + const updated = this.parse8601 (this.safeString (transaction, 'updated_at')); + const type = this.safeString (transaction, 'type'); + const amount = this.safeFloat (transaction, 'amount'); + let address = this.safeString (transaction, 'address'); + let addressTo = undefined; + const addressFrom = undefined; + let tag = undefined; + let tagTo = undefined; + const tagFrom = undefined; + if (address !== undefined) { + const parts = address.split (':'); + address = this.safeString (parts, 0); + tag = this.safeString (parts, 1); + addressTo = address; + tagTo = tag; + } + const currencyId = this.safeString (transaction, 'currency'); + const code = this.safeCurrencyCode (currencyId); + let status = this.safeValue (transaction, 'status'); + const dismissed = this.safeValue (transaction, 'dismissed'); + const rejected = this.safeValue (transaction, 'rejected'); + if (status) { + status = 'ok'; + } else if (dismissed) { + status = 'canceled'; + } else if (rejected) { + status = 'failed'; + } else { + status = 'pending'; + } + const fee = { + 'currency': code, + 'cost': this.safeFloat (transaction, 'fee'), + }; + return { + 'info': transaction, + 'id': id, + 'txid': txid, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'addressFrom': addressFrom, + 'address': address, + 'addressTo': addressTo, + 'tagFrom': tagFrom, + 'tag': tag, + 'tagTo': tagTo, + 'type': type, + 'amount': amount, + 'currency': code, + 'status': status, + 'updated': updated, + 'fee': fee, + }; + } + + async withdraw (code, amount, address, tag = undefined, params = {}) { + this.checkAddress (address); + await this.loadMarkets (); + const currency = this.currency (code); + if (tag !== undefined) { + address += ':' + tag; + } + const request = { + 'currency': currency['id'], + 'amount': amount, + 'address': address, + }; + // one time password + let otp = this.safeString (params, 'otp_code'); + if ((otp !== undefined) || (this.twofa !== undefined)) { + if (otp === undefined) { + otp = this.oath (); + } + request['otp_code'] = otp; + } + const response = await this.privatePostUserRequestWithdrawal (this.extend (request, params)); + return { + 'info': response, + 'id': undefined, + }; + } + + sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { + const query = this.omit (params, this.extractParams (path)); + path = '/' + this.version + '/' + this.implodeParams (path, params); + if (method === 'GET') { + if (Object.keys (query).length) { + path += '?' + this.urlencode (query); + } + } + const url = this.urls['api'] + path; + if (api === 'private') { + this.checkRequiredCredentials (); + const defaultExpires = this.safeInteger2 (this.options, 'api-expires', 'expires', parseInt (this.timeout / 1000)); + const expires = this.sum (this.seconds (), defaultExpires); + const expiresString = expires.toString (); + let auth = method + path + expiresString; + headers = { + 'api-key': this.encode (this.apiKey), + 'api-expires': expiresString, + }; + if (method === 'POST') { + headers['Content-type'] = 'application/json'; + if (Object.keys (query).length) { + body = this.json (query); + auth += body; + } + } + const signature = this.hmac (this.encode (auth), this.encode (this.secret)); + headers['api-signature'] = signature; + } + return { 'url': url, 'method': method, 'body': body, 'headers': headers }; + } + + handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (response === undefined) { + return; + } + if ((code >= 400) && (code <= 503)) { + // + // { "message": "Invalid token" } + // + const feedback = this.id + ' ' + body; + const message = this.safeString (response, 'message'); + this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback); + const status = code.toString (); + this.throwExactlyMatchedException (this.exceptions['exact'], status, feedback); + } + } +}; diff --git a/TaskServer/node_modules/ccxt/js/huobipro.js b/TaskServer/node_modules/ccxt/js/huobipro.js index 23c6fe99b..b3b298c49 100644 --- a/TaskServer/node_modules/ccxt/js/huobipro.js +++ b/TaskServer/node_modules/ccxt/js/huobipro.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { AuthenticationError, ExchangeError, ExchangeNotAvailable, InvalidOrder, OrderNotFound, InsufficientFunds, ArgumentsRequired, BadSymbol, BadRequest, RequestTimeout } = require ('./base/errors'); +const { AuthenticationError, ExchangeError, PermissionDenied, ExchangeNotAvailable, InvalidOrder, OrderNotFound, InsufficientFunds, ArgumentsRequired, BadSymbol, BadRequest, RequestTimeout } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -18,11 +18,12 @@ module.exports = class huobipro extends Exchange { 'version': 'v1', 'accounts': undefined, 'accountsById': undefined, - 'hostname': 'api.huobi.pro', + 'hostname': 'api.huobi.pro', // api.testnet.huobi.pro + 'pro': true, 'has': { 'CORS': false, 'fetchTickers': true, - 'fetchDepositAddress': false, + 'fetchDepositAddress': true, 'fetchOHLCV': true, 'fetchOrder': true, 'fetchOrders': true, @@ -48,12 +49,18 @@ module.exports = class huobipro extends Exchange { '1y': '1year', }, 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/27766569-15aa7b9a-5edd-11e7-9e7f-44791f4ee49c.jpg', + 'test': { + 'market': 'https://api.testnet.huobi.pro', + 'public': 'https://api.testnet.huobi.pro', + 'private': 'https://api.testnet.huobi.pro', + }, + 'logo': 'https://user-images.githubusercontent.com/1294454/76137448-22748a80-604e-11ea-8069-6e389271911d.jpg', 'api': { 'market': 'https://{hostname}', 'public': 'https://{hostname}', 'private': 'https://{hostname}', - 'zendesk': 'https://huobiglobal.zendesk.com/hc/en-us/articles', + 'v2Public': 'https://{hostname}', + 'v2Private': 'https://{hostname}', }, 'www': 'https://www.huobi.pro', 'referral': 'https://www.huobi.co/en-us/topic/invited/?invite_code=rwrd3', @@ -61,9 +68,19 @@ module.exports = class huobipro extends Exchange { 'fees': 'https://www.huobi.pro/about/fee/', }, 'api': { - 'zendesk': { + 'v2Public': { 'get': [ - '360000400491-Trade-Limits', + 'reference/currencies', + ], + }, + 'v2Private': { + 'get': [ + 'account/withdraw/quota', + 'account/deposit/address', + 'reference/transact-fee-rate', + ], + 'post': [ + 'sub-user/management', ], }, 'market': { @@ -87,10 +104,6 @@ module.exports = class huobipro extends Exchange { ], }, 'private': { - // todo add v2 endpoints - // 'GET /v2/account/withdraw/quota - // 'GET /v2/reference/currencies - // 'GET /v2/account/deposit/address 'get': [ 'account/accounts', // 查询当前用户的所有账户(即account-id) 'account/accounts/{id}/balance', // 查询指定账户的余额 @@ -115,8 +128,6 @@ module.exports = class huobipro extends Exchange { 'stable-coin/exchange_rate', 'stable-coin/quote', ], - // todo add v2 endpoints - // POST /v2/sub-user/management 'post': [ 'futures/transfer', 'order/batch-orders', @@ -152,6 +163,7 @@ module.exports = class huobipro extends Exchange { 'exceptions': { 'exact': { // err-code + 'api-not-support-temp-addr': PermissionDenied, // {"status":"error","err-code":"api-not-support-temp-addr","err-msg":"API withdrawal does not support temporary addresses","data":null} 'timeout': RequestTimeout, // {"ts":1571653730865,"status":"error","err-code":"timeout","err-msg":"Request Timeout"} 'gateway-internal-error': ExchangeNotAvailable, // {"status":"error","err-code":"gateway-internal-error","err-msg":"Failed to load data. Try again later.","data":null} 'account-frozen-balance-insufficient-error': InsufficientFunds, // {"status":"error","err-code":"account-frozen-balance-insufficient-error","err-msg":"trade account balance is not enough, left: `0.0027`","data":null} @@ -319,6 +331,21 @@ module.exports = class huobipro extends Exchange { } parseTicker (ticker, market = undefined) { + // + // { + // "amount": 26228.672978342216, + // "open": 9078.95, + // "close": 9146.86, + // "high": 9155.41, + // "id": 209988544334, + // "count": 265846, + // "low": 8988.0, + // "version": 209988544334, + // "ask": [ 9146.87, 0.156134 ], + // "vol": 2.3822168242201668E8, + // "bid": [ 9146.86, 0.080758 ], + // } + // let symbol = undefined; if (market !== undefined) { symbol = market['symbol']; @@ -390,13 +417,35 @@ module.exports = class huobipro extends Exchange { 'type': 'step0', }; const response = await this.marketGetDepth (this.extend (request, params)); + // + // { + // "status": "ok", + // "ch": "market.btcusdt.depth.step0", + // "ts": 1583474832790, + // "tick": { + // "bids": [ + // [ 9100.290000000000000000, 0.200000000000000000 ], + // [ 9099.820000000000000000, 0.200000000000000000 ], + // [ 9099.610000000000000000, 0.205000000000000000 ], + // ], + // "asks": [ + // [ 9100.640000000000000000, 0.005904000000000000 ], + // [ 9101.010000000000000000, 0.287311000000000000 ], + // [ 9101.030000000000000000, 0.012121000000000000 ], + // ], + // "ts":1583474832008, + // "version":104999698780 + // } + // } + // if ('tick' in response) { if (!response['tick']) { throw new ExchangeError (this.id + ' fetchOrderBook() returned empty response: ' + this.json (response)); } - const orderbook = this.safeValue (response, 'tick'); - const result = this.parseOrderBook (orderbook, orderbook['ts']); - result['nonce'] = orderbook['version']; + const tick = this.safeValue (response, 'tick'); + const timestamp = this.safeInteger (tick, 'ts', this.safeInteger (response, 'ts')); + const result = this.parseOrderBook (tick, timestamp); + result['nonce'] = this.safeInteger (tick, 'version'); return result; } throw new ExchangeError (this.id + ' fetchOrderBook() returned unrecognized response: ' + this.json (response)); @@ -409,7 +458,31 @@ module.exports = class huobipro extends Exchange { 'symbol': market['id'], }; const response = await this.marketGetDetailMerged (this.extend (request, params)); - return this.parseTicker (response['tick'], market); + // + // { + // "status": "ok", + // "ch": "market.btcusdt.detail.merged", + // "ts": 1583494336669, + // "tick": { + // "amount": 26228.672978342216, + // "open": 9078.95, + // "close": 9146.86, + // "high": 9155.41, + // "id": 209988544334, + // "count": 265846, + // "low": 8988.0, + // "version": 209988544334, + // "ask": [ 9146.87, 0.156134 ], + // "vol": 2.3822168242201668E8, + // "bid": [ 9146.86, 0.080758 ], + // } + // } + // + const ticker = this.parseTicker (response['tick'], market); + const timestamp = this.safeValue (response, 'ts'); + ticker['timestamp'] = timestamp; + ticker['datetime'] = this.iso8601 (timestamp); + return ticker; } async fetchTickers (symbols = undefined, params = {}) { @@ -430,10 +503,24 @@ module.exports = class huobipro extends Exchange { result[symbol] = ticker; } } - return result; + return this.filterByArray (result, 'symbol', symbols); } parseTrade (trade, market = undefined) { + // + // fetchTrades (public) + // + // { + // "amount": 0.010411000000000000, + // "trade-id": 102090736910, + // "ts": 1583497692182, + // "id": 10500517034273194594947, + // "price": 9096.050000000000000000, + // "direction": "sell" + // } + // + // fetchMyTrades (private) + // let symbol = undefined; if (market === undefined) { const marketId = this.safeString (trade, 'symbol'); @@ -481,7 +568,8 @@ module.exports = class huobipro extends Exchange { 'currency': feeCurrency, }; } - const id = this.safeString (trade, 'id'); + const tradeId = this.safeString2 (trade, 'trade-id', 'tradeId'); + const id = this.safeString (trade, 'id', tradeId); return { 'id': id, 'info': trade, @@ -528,6 +616,30 @@ module.exports = class huobipro extends Exchange { request['size'] = limit; } const response = await this.marketGetHistoryTrade (this.extend (request, params)); + // + // { + // "status": "ok", + // "ch": "market.btcusdt.trade.detail", + // "ts": 1583497692365, + // "data": [ + // { + // "id": 105005170342, + // "ts": 1583497692182, + // "data": [ + // { + // "amount": 0.010411000000000000, + // "trade-id": 102090736910, + // "ts": 1583497692182, + // "id": 10500517034273194594947, + // "price": 9096.050000000000000000, + // "direction": "sell" + // } + // ] + // }, + // // ... + // ] + // } + // const data = this.safeValue (response, 'data'); let result = []; for (let i = 0; i < data.length; i++) { @@ -729,6 +841,9 @@ module.exports = class huobipro extends Exchange { } async fetchOpenOrdersV1 (symbol = undefined, since = undefined, limit = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOpenOrdersV1 requires a symbol argument'); + } return await this.fetchOrdersByStates ('pre-submitted,submitted,partial-filled', symbol, since, limit, params); } @@ -892,6 +1007,7 @@ module.exports = class huobipro extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -906,6 +1022,7 @@ module.exports = class huobipro extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; } @@ -960,6 +1077,8 @@ module.exports = class huobipro extends Exchange { 'cost': undefined, 'trades': undefined, 'fee': undefined, + 'clientOrderId': undefined, + 'average': undefined, }; } @@ -999,94 +1118,50 @@ module.exports = class huobipro extends Exchange { }; } - async withdraw (code, amount, address, tag = undefined, params = {}) { - await this.loadMarkets (); + parseDepositAddress (depositAddress, currency = undefined) { + // + // { + // currency: "eth", + // address: "0xf7292eb9ba7bc50358e27f0e025a4d225a64127b", + // addressTag: "", + // chain: "eth" + // } + // + const address = this.safeString (depositAddress, 'address'); + const tag = this.safeString (depositAddress, 'addressTag'); + const currencyId = this.safeString (depositAddress, 'currency'); + const code = this.safeCurrencyCode (currencyId); this.checkAddress (address); + return { + 'currency': code, + 'address': address, + 'tag': tag, + 'info': depositAddress, + }; + } + + async fetchDepositAddress (code, params = {}) { + await this.loadMarkets (); const currency = this.currency (code); const request = { - 'address': address, // only supports existing addresses in your withdraw address list - 'amount': amount, - 'currency': currency['id'].toLowerCase (), + 'currency': currency['id'], }; - if (tag !== undefined) { - request['addr-tag'] = tag; // only for XRP? - } - const response = await this.privatePostDwWithdrawApiCreate (this.extend (request, params)); - const id = this.safeString (response, 'data'); - return { - 'info': response, - 'id': id, - }; - } - - sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = '/'; - if (api === 'market') { - url += api; - } else if ((api === 'public') || (api === 'private')) { - url += this.version; - } - url += '/' + this.implodeParams (path, params); - const query = this.omit (params, this.extractParams (path)); - if (api === 'private') { - this.checkRequiredCredentials (); - const timestamp = this.ymdhms (this.milliseconds (), 'T'); - let request = { - 'SignatureMethod': 'HmacSHA256', - 'SignatureVersion': '2', - 'AccessKeyId': this.apiKey, - 'Timestamp': timestamp, - }; - if (method !== 'POST') { - request = this.extend (request, query); - } - request = this.keysort (request); - let auth = this.urlencode (request); - // unfortunately, PHP demands double quotes for the escaped newline symbol - // eslint-disable-next-line quotes - const payload = [ method, this.hostname, url, auth ].join ("\n"); - const signature = this.hmac (this.encode (payload), this.encode (this.secret), 'sha256', 'base64'); - auth += '&' + this.urlencode ({ 'Signature': signature }); - url += '?' + auth; - if (method === 'POST') { - body = this.json (query); - headers = { - 'Content-Type': 'application/json', - }; - } else { - headers = { - 'Content-Type': 'application/x-www-form-urlencoded', - }; - } - } else { - if (Object.keys (params).length) { - url += '?' + this.urlencode (params); - } - } - url = this.implodeParams (this.urls['api'][api], { - 'hostname': this.hostname, - }) + url; - return { 'url': url, 'method': method, 'body': body, 'headers': headers }; - } - - handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) { - if (response === undefined) { - return; // fallback to default error handler - } - if ('status' in response) { - // - // {"status":"error","err-code":"order-limitorder-amount-min-error","err-msg":"limit order amount error, min: `0.001`","data":null} - // - const status = this.safeString (response, 'status'); - if (status === 'error') { - const code = this.safeString (response, 'err-code'); - const feedback = this.id + ' ' + body; - this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback); - const message = this.safeString (response, 'err-msg'); - this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback); - throw new ExchangeError (feedback); - } - } + const response = await this.v2PrivateGetAccountDepositAddress (this.extend (request, params)); + // + // { + // code: 200, + // data: [ + // { + // currency: "eth", + // address: "0xf7292eb9ba7bc50358e27f0e025a4d225a64127b", + // addressTag: "", + // chain: "eth" + // } + // ] + // } + // + const data = this.safeValue (response, 'data', []); + return this.parseDepositAddress (this.safeValue (data, 0, {}), currency); } async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { @@ -1230,4 +1305,96 @@ module.exports = class huobipro extends Exchange { }; return this.safeString (statuses, status, status); } + + async withdraw (code, amount, address, tag = undefined, params = {}) { + await this.loadMarkets (); + this.checkAddress (address); + const currency = this.currency (code); + const request = { + 'address': address, // only supports existing addresses in your withdraw address list + 'amount': amount, + 'currency': currency['id'].toLowerCase (), + }; + if (tag !== undefined) { + request['addr-tag'] = tag; // only for XRP? + } + const response = await this.privatePostDwWithdrawApiCreate (this.extend (request, params)); + const id = this.safeString (response, 'data'); + return { + 'info': response, + 'id': id, + }; + } + + sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { + let url = '/'; + if (api === 'market') { + url += api; + } else if ((api === 'public') || (api === 'private')) { + url += this.version; + } else if ((api === 'v2Public') || (api === 'v2Private')) { + url += 'v2'; + } + url += '/' + this.implodeParams (path, params); + const query = this.omit (params, this.extractParams (path)); + if (api === 'private' || api === 'v2Private') { + this.checkRequiredCredentials (); + const timestamp = this.ymdhms (this.milliseconds (), 'T'); + let request = { + 'SignatureMethod': 'HmacSHA256', + 'SignatureVersion': '2', + 'AccessKeyId': this.apiKey, + 'Timestamp': timestamp, + }; + if (method !== 'POST') { + request = this.extend (request, query); + } + request = this.keysort (request); + let auth = this.urlencode (request); + // unfortunately, PHP demands double quotes for the escaped newline symbol + // eslint-disable-next-line quotes + const payload = [ method, this.hostname, url, auth ].join ("\n"); + const signature = this.hmac (this.encode (payload), this.encode (this.secret), 'sha256', 'base64'); + auth += '&' + this.urlencode ({ 'Signature': signature }); + url += '?' + auth; + if (method === 'POST') { + body = this.json (query); + headers = { + 'Content-Type': 'application/json', + }; + } else { + headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + }; + } + } else { + if (Object.keys (params).length) { + url += '?' + this.urlencode (params); + } + } + url = this.implodeParams (this.urls['api'][api], { + 'hostname': this.hostname, + }) + url; + return { 'url': url, 'method': method, 'body': body, 'headers': headers }; + } + + handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if (response === undefined) { + return; // fallback to default error handler + } + if ('status' in response) { + // + // {"status":"error","err-code":"order-limitorder-amount-min-error","err-msg":"limit order amount error, min: `0.001`","data":null} + // + const status = this.safeString (response, 'status'); + if (status === 'error') { + const code = this.safeString (response, 'err-code'); + const feedback = this.id + ' ' + body; + this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback); + const message = this.safeString (response, 'err-msg'); + this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback); + throw new ExchangeError (feedback); + } + } + } }; diff --git a/TaskServer/node_modules/ccxt/js/huobiru.js b/TaskServer/node_modules/ccxt/js/huobiru.js index 039a8ce78..b628d3dc4 100644 --- a/TaskServer/node_modules/ccxt/js/huobiru.js +++ b/TaskServer/node_modules/ccxt/js/huobiru.js @@ -13,12 +13,13 @@ module.exports = class huobiru extends huobipro { 'name': 'Huobi Russia', 'countries': [ 'RU' ], 'hostname': 'www.huobi.com.ru', + 'pro': true, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/52978816-e8552e00-33e3-11e9-98ed-845acfece834.jpg', 'api': { - 'market': 'https://www.huobi.com.ru/api', - 'public': 'https://www.huobi.com.ru/api', - 'private': 'https://www.huobi.com.ru/api', + 'market': 'https://{hostname}/api', + 'public': 'https://{hostname}/api', + 'private': 'https://{hostname}/api', 'zendesk': 'https://huobiglobal.zendesk.com/hc/en-us/articles', }, 'www': 'https://www.huobi.com.ru/ru-ru', diff --git a/TaskServer/node_modules/ccxt/js/ice3x.js b/TaskServer/node_modules/ccxt/js/ice3x.js index 6405d358b..1f660df72 100644 --- a/TaskServer/node_modules/ccxt/js/ice3x.js +++ b/TaskServer/node_modules/ccxt/js/ice3x.js @@ -116,6 +116,7 @@ module.exports = class ice3x extends Exchange { }, }, 'info': currency, + 'fee': undefined, }; } return result; @@ -148,6 +149,8 @@ module.exports = class ice3x extends Exchange { 'quoteId': quoteId, 'active': undefined, 'info': market, + 'precision': this.precision, + 'limits': this.limits, }); } return result; @@ -330,6 +333,7 @@ module.exports = class ice3x extends Exchange { } return { 'id': this.safeString (order, 'order_id'), + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -345,6 +349,7 @@ module.exports = class ice3x extends Exchange { 'trades': undefined, 'fee': fee, 'info': order, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/idex.js b/TaskServer/node_modules/ccxt/js/idex.js index 50000d5eb..e57a4ff06 100644 --- a/TaskServer/node_modules/ccxt/js/idex.js +++ b/TaskServer/node_modules/ccxt/js/idex.js @@ -97,8 +97,11 @@ module.exports = class idex extends Exchange { 'secret': false, }, 'commonCurrencies': { - 'ONE': 'Menlo One', 'FT': 'Fabric Token', + 'MT': 'Monarch', + 'ONE': 'Menlo One', + 'PLA': 'PlayChip', + 'WAX': 'WAXP', }, }); } @@ -382,13 +385,13 @@ module.exports = class idex extends Exchange { if (side === 'buy') { tokenBuy = market['baseId']; tokenSell = market['quoteId']; - amountBuy = this.toWei (amount, 'ether', market['precision']['amount']); - amountSell = this.toWei (quoteAmount, 'ether', 18); + amountBuy = this.toWei (amount, market['precision']['amount']); + amountSell = this.toWei (quoteAmount, 18); } else { tokenBuy = market['quoteId']; tokenSell = market['baseId']; - amountBuy = this.toWei (quoteAmount, 'ether', 18); - amountSell = this.toWei (amount, 'ether', market['precision']['amount']); + amountBuy = this.toWei (quoteAmount, 18); + amountSell = this.toWei (amount, market['precision']['amount']); } const nonce = await this.getNonce (); const orderToHash = { @@ -733,8 +736,11 @@ module.exports = class idex extends Exchange { amount = this.safeFloat (order, 'amount'); } const filled = this.safeFloat (order, 'filled'); - const cost = this.safeFloat (order, 'total'); const price = this.safeFloat (order, 'price'); + let cost = this.safeFloat (order, 'total'); + if ((cost !== undefined) && (filled !== undefined) && !cost) { + cost = filled * price; + } if ('market' in order) { const marketId = order['market']; symbol = this.markets_by_id[marketId]['symbol']; @@ -754,6 +760,7 @@ module.exports = class idex extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -765,6 +772,10 @@ module.exports = class idex extends Exchange { 'remaining': remaining, 'cost': cost, 'status': status, + 'lastTradeTimestamp': undefined, + 'average': undefined, + 'trades': undefined, + 'fee': undefined, }; } @@ -988,7 +999,7 @@ module.exports = class idex extends Exchange { const currency = this.currency (code); const tokenAddress = currency['id']; const nonce = await this.getNonce (); - amount = this.toWei (amount, 'ether', currency['precision']); + amount = this.toWei (amount, currency['precision']); const requestToHash = { 'contractAddress': await this.getContractAddress (), 'token': tokenAddress, diff --git a/TaskServer/node_modules/ccxt/js/independentreserve.js b/TaskServer/node_modules/ccxt/js/independentreserve.js index 98a30e08e..872ce0b05 100644 --- a/TaskServer/node_modules/ccxt/js/independentreserve.js +++ b/TaskServer/node_modules/ccxt/js/independentreserve.js @@ -71,6 +71,9 @@ module.exports = class independentreserve extends Exchange { 'tierBased': false, }, }, + 'commonCurrencies': { + 'PLA': 'PlayChip', + }, }); } @@ -94,6 +97,9 @@ module.exports = class independentreserve extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'info': id, + 'active': undefined, + 'precision': this.precision, + 'limits': this.limits, }); } } @@ -171,6 +177,21 @@ module.exports = class independentreserve extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "OrderGuid": "c7347e4c-b865-4c94-8f74-d934d4b0b177", + // "CreatedTimestampUtc": "2014-09-23T12:39:34.3817763Z", + // "Type": "MarketBid", + // "VolumeOrdered": 5.0, + // "VolumeFilled": 5.0, + // "Price": null, + // "AvgPrice": 100.0, + // "ReservedAmount": 0.0, + // "Status": "Filled", + // "PrimaryCurrencyCode": "Xbt", + // "SecondaryCurrencyCode": "Usd" + // } + // let symbol = undefined; const baseId = this.safeString (order, 'PrimaryCurrencyCode'); const quoteId = this.safeString (order, 'PrimaryCurrencyCode'); @@ -227,6 +248,7 @@ module.exports = class independentreserve extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -241,6 +263,7 @@ module.exports = class independentreserve extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/indodax.js b/TaskServer/node_modules/ccxt/js/indodax.js index 6d54ec676..83f7b4e2c 100644 --- a/TaskServer/node_modules/ccxt/js/indodax.js +++ b/TaskServer/node_modules/ccxt/js/indodax.js @@ -280,6 +280,16 @@ module.exports = class indodax extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "order_id": "12345", + // "submit_time": "1392228122", + // "price": "8000000", + // "type": "sell", + // "order_ltc": "100000000", + // "remain_ltc": "100000000" + // } + // let side = undefined; if ('type' in order) { side = order['type']; @@ -331,6 +341,7 @@ module.exports = class indodax extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -345,6 +356,7 @@ module.exports = class indodax extends Exchange { 'remaining': remaining, 'status': status, 'fee': fee, + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/itbit.js b/TaskServer/node_modules/ccxt/js/itbit.js index 192fa145d..f146ae46c 100644 --- a/TaskServer/node_modules/ccxt/js/itbit.js +++ b/TaskServer/node_modules/ccxt/js/itbit.js @@ -61,12 +61,12 @@ module.exports = class itbit extends Exchange { }, }, 'markets': { - 'BTC/USD': { 'id': 'XBTUSD', 'symbol': 'BTC/USD', 'base': 'BTC', 'quote': 'USD' }, - 'BTC/SGD': { 'id': 'XBTSGD', 'symbol': 'BTC/SGD', 'base': 'BTC', 'quote': 'SGD' }, - 'BTC/EUR': { 'id': 'XBTEUR', 'symbol': 'BTC/EUR', 'base': 'BTC', 'quote': 'EUR' }, - 'ETH/USD': { 'id': 'ETHUSD', 'symbol': 'ETH/USD', 'base': 'ETH', 'quote': 'USD' }, - 'ETH/EUR': { 'id': 'ETHEUR', 'symbol': 'ETH/EUR', 'base': 'ETH', 'quote': 'EUR' }, - 'ETH/SGD': { 'id': 'ETHSGD', 'symbol': 'ETH/SGD', 'base': 'ETH', 'quote': 'SGD' }, + 'BTC/USD': { 'id': 'XBTUSD', 'symbol': 'BTC/USD', 'base': 'BTC', 'quote': 'USD', 'baseId': 'XBT', 'quoteId': 'USD' }, + 'BTC/SGD': { 'id': 'XBTSGD', 'symbol': 'BTC/SGD', 'base': 'BTC', 'quote': 'SGD', 'baseId': 'XBT', 'quoteId': 'SGD' }, + 'BTC/EUR': { 'id': 'XBTEUR', 'symbol': 'BTC/EUR', 'base': 'BTC', 'quote': 'EUR', 'baseId': 'XBT', 'quoteId': 'EUR' }, + 'ETH/USD': { 'id': 'ETHUSD', 'symbol': 'ETH/USD', 'base': 'ETH', 'quote': 'USD', 'baseId': 'ETH', 'quoteId': 'USD' }, + 'ETH/EUR': { 'id': 'ETHEUR', 'symbol': 'ETH/EUR', 'base': 'ETH', 'quote': 'EUR', 'baseId': 'ETH', 'quoteId': 'EUR' }, + 'ETH/SGD': { 'id': 'ETHSGD', 'symbol': 'ETH/SGD', 'base': 'ETH', 'quote': 'SGD', 'baseId': 'ETH', 'quoteId': 'SGD' }, }, 'fees': { 'trading': { @@ -213,6 +213,7 @@ module.exports = class itbit extends Exchange { 'price': price, 'amount': amount, 'cost': cost, + 'fee': undefined, }; if (feeCost !== undefined) { if (rebatesApplied !== undefined) { @@ -472,19 +473,51 @@ module.exports = class itbit extends Exchange { } parseOrder (order, market = undefined) { - const side = order['side']; - const type = order['type']; + // + // { + // "id": "13d6af57-8b0b-41e5-af30-becf0bcc574d", + // "walletId": "7e037345-1288-4c39-12fe-d0f99a475a98", + // "side": "buy", + // "instrument": "XBTUSD", + // "type": "limit", + // "currency": "XBT", + // "amount": "2.50000000", + // "displayAmount": "2.50000000", + // "price": "650.00000000", + // "volumeWeightedAveragePrice": "0.00000000", + // "amountFilled": "0.00000000", + // "createdTime": "2014-02-11T17:05:15Z", + // "status": "submitted", + // "funds": null, + // "metadata": {}, + // "clientOrderIdentifier": null, + // "postOnly": "False" + // } + // + const side = this.safeString (order, 'side'); + const type = this.safeString (order, 'type'); const symbol = this.markets_by_id[order['instrument']]['symbol']; const timestamp = this.parse8601 (order['createdTime']); const amount = this.safeFloat (order, 'amount'); const filled = this.safeFloat (order, 'amountFilled'); - const remaining = amount - filled; + let remaining = undefined; + let cost = undefined; const fee = undefined; const price = this.safeFloat (order, 'price'); const average = this.safeFloat (order, 'volumeWeightedAveragePrice'); - const cost = filled * average; + if (filled !== undefined) { + if (amount !== undefined) { + remaining = amount - filled; + } + if (average !== undefined) { + cost = filled * average; + } + } + const clientOrderId = this.safeString (order, 'clientOrderIdentifier'); + const id = this.safeString (order, 'id'); return { - 'id': order['id'], + 'id': id, + 'clientOrderId': clientOrderId, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -501,6 +534,7 @@ module.exports = class itbit extends Exchange { 'remaining': remaining, 'fee': fee, // 'trades': this.parseTrades (order['trades'], market), + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/kkex.js b/TaskServer/node_modules/ccxt/js/kkex.js index 58b799e95..cd0457f21 100644 --- a/TaskServer/node_modules/ccxt/js/kkex.js +++ b/TaskServer/node_modules/ccxt/js/kkex.js @@ -399,6 +399,20 @@ module.exports = class kkex extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "status": 2, + // "source": "NORMAL", + // "amount": "10.852019", + // "create_date": 1523938461036, + // "avg_price": "0.00096104", + // "order_id": "100", + // "price": "0.00096105", + // "type": "buy", + // "symbol": "READBTC", + // "deal_amount": "10.852019" + // } + // let symbol = undefined; if (market !== undefined) { symbol = market['symbol']; @@ -427,6 +441,7 @@ module.exports = class kkex extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -442,6 +457,7 @@ module.exports = class kkex extends Exchange { 'remaining': remaining, 'fee': undefined, 'info': order, + 'trades': undefined, }; } @@ -490,6 +506,8 @@ module.exports = class kkex extends Exchange { 'remaining': undefined, 'trades': undefined, 'fee': undefined, + 'clientOrderId': undefined, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/kraken.js b/TaskServer/node_modules/ccxt/js/kraken.js index 51505f672..7063d9d37 100644 --- a/TaskServer/node_modules/ccxt/js/kraken.js +++ b/TaskServer/node_modules/ccxt/js/kraken.js @@ -17,6 +17,7 @@ module.exports = class kraken extends Exchange { 'version': '0', 'rateLimit': 3000, 'certified': true, + 'pro': true, 'has': { 'createDepositAddress': true, 'fetchDepositAddress': true, @@ -49,7 +50,7 @@ module.exports = class kraken extends Exchange { '2w': 21600, }, 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/27766599-22709304-5ede-11e7-9de1-9f33732e1509.jpg', + 'logo': 'https://user-images.githubusercontent.com/51840849/76173629-fc67fb00-61b1-11ea-84fe-f2de582f58a3.jpg', 'api': { 'public': 'https://api.kraken.com', 'private': 'https://api.kraken.com', @@ -205,6 +206,7 @@ module.exports = class kraken extends Exchange { 'delistedMarketsById': {}, // cannot withdraw/deposit these 'inactiveCurrencies': [ 'CAD', 'USD', 'JPY', 'GBP' ], + 'fetchMinOrderAmounts': true, }, 'exceptions': { 'EQuery:Invalid asset pair': BadSymbol, // {"error":["EQuery:Invalid asset pair"]} @@ -260,7 +262,11 @@ module.exports = class kraken extends Exchange { async fetchMarkets (params = {}) { const response = await this.publicGetAssetPairs (params); - const limits = await this.fetchMinOrderAmounts (); + const fetchMinOrderAmounts = this.safeValue (this.options, 'fetchMinOrderAmounts', false); + let limits = {}; + if (fetchMinOrderAmounts) { + limits = await this.fetchMinOrderAmounts (); + } const keys = Object.keys (response['result']); let result = []; for (let i = 0; i < keys.length; i++) { @@ -723,14 +729,14 @@ module.exports = class kraken extends Exchange { symbol = market['symbol']; } if (Array.isArray (trade)) { - timestamp = parseInt (trade[2] * 1000); + timestamp = this.safeTimestamp (trade, 2); side = (trade[3] === 's') ? 'sell' : 'buy'; type = (trade[4] === 'l') ? 'limit' : 'market'; - price = parseFloat (trade[0]); - amount = parseFloat (trade[1]); + price = this.safeFloat (trade, 0); + amount = this.safeFloat (trade, 1); const tradeLength = trade.length; if (tradeLength > 6) { - id = trade[6]; // artificially added as per #1794 + id = this.safeString (trade, 6); // artificially added as per #1794 } } else if ('ordertxid' in trade) { order = trade['ordertxid']; @@ -854,8 +860,10 @@ module.exports = class kraken extends Exchange { id = (length > 1) ? id : id[0]; } } + const clientOrderId = this.safeString (params, 'userref'); return { 'id': id, + 'clientOrderId': clientOrderId, 'info': response, 'timestamp': undefined, 'datetime': undefined, @@ -977,8 +985,10 @@ module.exports = class kraken extends Exchange { } const status = this.parseOrderStatus (this.safeString (order, 'status')); const id = this.safeString (order, 'id'); + const clientOrderId = this.safeString (order, 'userref'); return { 'id': id, + 'clientOrderId': clientOrderId, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -995,6 +1005,7 @@ module.exports = class kraken extends Exchange { 'remaining': remaining, 'fee': fee, // 'trades': this.parseTrades (order['trades'], market), + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/kucoin.js b/TaskServer/node_modules/ccxt/js/kucoin.js index 8d2e8a33c..3afaaba98 100644 --- a/TaskServer/node_modules/ccxt/js/kucoin.js +++ b/TaskServer/node_modules/ccxt/js/kucoin.js @@ -16,8 +16,10 @@ module.exports = class kucoin extends Exchange { 'rateLimit': 334, 'version': 'v2', 'certified': false, + 'pro': true, 'comment': 'Platform 2.0', 'has': { + 'CORS': false, 'fetchTime': true, 'fetchMarkets': true, 'fetchCurrencies': true, @@ -70,6 +72,10 @@ module.exports = class kucoin extends Exchange { 'symbols', 'market/allTickers', 'market/orderbook/level{level}', + 'market/orderbook/level2', + 'market/orderbook/level2_20', + 'market/orderbook/level2_100', + 'market/orderbook/level3', 'market/histories', 'market/candles', 'market/stats', @@ -101,6 +107,7 @@ module.exports = class kucoin extends Exchange { 'post': [ 'accounts', 'accounts/inner-transfer', + 'accounts/sub-transfer', 'deposit-addresses', 'withdrawals', 'orders', @@ -182,6 +189,8 @@ module.exports = class kucoin extends Exchange { 'commonCurrencies': { 'HOT': 'HOTNOW', 'EDGE': 'DADI', // https://github.com/ccxt/ccxt/issues/5756 + 'WAX': 'WAXP', + 'TRY': 'Trias', }, 'options': { 'version': 'v1', @@ -190,6 +199,23 @@ module.exports = class kucoin extends Exchange { 'fetchBalance': { 'type': 'trade', // or 'main' }, + // endpoint versions + 'versions': { + 'public': { + 'GET': { + 'market/orderbook/level{level}': 'v1', + 'market/orderbook/level2': 'v2', + 'market/orderbook/level2_20': 'v1', + 'market/orderbook/level2_100': 'v1', + }, + }, + 'private': { + 'POST': { + 'accounts/inner-transfer': 'v2', + 'accounts/sub-transfer': 'v2', + }, + }, + }, }, }); } @@ -239,8 +265,7 @@ module.exports = class kucoin extends Exchange { for (let i = 0; i < data.length; i++) { const market = data[i]; const id = this.safeString (market, 'symbol'); - const baseId = this.safeString (market, 'baseCurrency'); - const quoteId = this.safeString (market, 'quoteCurrency'); + const [ baseId, quoteId ] = id.split ('-'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const symbol = base + '/' + quote; @@ -308,6 +333,9 @@ module.exports = class kucoin extends Exchange { 'code': code, 'precision': precision, 'info': entry, + 'active': undefined, + 'fee': undefined, + 'limits': this.limits, }; } return result; @@ -873,8 +901,10 @@ module.exports = class kucoin extends Exchange { } } } + const clientOrderId = this.safeString (order, 'clientOid'); return { 'id': orderId, + 'clientOrderId': clientOrderId, 'symbol': symbol, 'type': type, 'side': side, @@ -888,6 +918,9 @@ module.exports = class kucoin extends Exchange { 'fee': fee, 'status': status, 'info': order, + 'lastTradeTimestamp': undefined, + 'average': undefined, + 'trades': undefined, }; } @@ -1612,7 +1645,11 @@ module.exports = class kucoin extends Exchange { // the v2 URL is https://openapi-v2.kucoin.com/api/v1/endpoint // † ↑ // - const version = this.safeString (params, 'version', this.options['version']); + const versions = this.safeValue (this.options, 'versions', {}); + const apiVersions = this.safeValue (versions, api); + const methodVersions = this.safeValue (apiVersions, method, {}); + const defaultVersion = this.safeString (methodVersions, path, this.options['version']); + const version = this.safeString (params, 'version', defaultVersion); params = this.omit (params, 'version'); let endpoint = '/api/' + version + '/' + this.implodeParams (path, params); const query = this.omit (params, this.extractParams (path)); diff --git a/TaskServer/node_modules/ccxt/js/kuna.js b/TaskServer/node_modules/ccxt/js/kuna.js index 63e4225c2..08651fad2 100644 --- a/TaskServer/node_modules/ccxt/js/kuna.js +++ b/TaskServer/node_modules/ccxt/js/kuna.js @@ -103,6 +103,8 @@ module.exports = class kuna extends acx { 'max': undefined, }, }, + 'active': undefined, + 'info': undefined, }); break; } diff --git a/TaskServer/node_modules/ccxt/js/lakebtc.js b/TaskServer/node_modules/ccxt/js/lakebtc.js index 522584224..396bf0b69 100644 --- a/TaskServer/node_modules/ccxt/js/lakebtc.js +++ b/TaskServer/node_modules/ccxt/js/lakebtc.js @@ -78,6 +78,9 @@ module.exports = class lakebtc extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'info': market, + 'active': undefined, + 'precision': this.precision, + 'limits': this.limits, }); } return result; diff --git a/TaskServer/node_modules/ccxt/js/latoken.js b/TaskServer/node_modules/ccxt/js/latoken.js index 055ec98a7..aedf173a1 100644 --- a/TaskServer/node_modules/ccxt/js/latoken.js +++ b/TaskServer/node_modules/ccxt/js/latoken.js @@ -92,6 +92,7 @@ module.exports = class latoken extends Exchange { }, }, 'commonCurrencies': { + 'MT': 'Monarch', 'TSL': 'Treasure SL', }, 'options': { @@ -647,8 +648,10 @@ module.exports = class latoken extends Exchange { if ((timeFilled !== undefined) && (timeFilled > 0)) { lastTradeTimestamp = timeFilled; } + const clientOrderId = this.safeString (order, 'cliOrdId'); return { 'id': id, + 'clientOrderId': clientOrderId, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -664,6 +667,7 @@ module.exports = class latoken extends Exchange { 'average': undefined, 'remaining': remaining, 'fee': undefined, + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/lbank.js b/TaskServer/node_modules/ccxt/js/lbank.js index c63e53959..de0464dab 100644 --- a/TaskServer/node_modules/ccxt/js/lbank.js +++ b/TaskServer/node_modules/ccxt/js/lbank.js @@ -409,6 +409,19 @@ module.exports = class lbank extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "symbol":"eth_btc", + // "amount":10.000000, + // "create_time":1484289832081, + // "price":5000.000000, + // "avg_price":5277.301200, + // "type":"sell", + // "order_id":"ab704110-af0d-48fd-a083-c218f19a4a55", + // "deal_amount":10.000000, + // "status":2 + // } + // let symbol = undefined; const responseMarket = this.safeValue (this.marketsById, order['symbol']); if (responseMarket !== undefined) { @@ -439,6 +452,7 @@ module.exports = class lbank extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -454,6 +468,7 @@ module.exports = class lbank extends Exchange { 'trades': undefined, 'fee': undefined, 'info': this.safeValue (order, 'info', order), + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/liquid.js b/TaskServer/node_modules/ccxt/js/liquid.js index 1b7a4b66d..cd1337126 100644 --- a/TaskServer/node_modules/ccxt/js/liquid.js +++ b/TaskServer/node_modules/ccxt/js/liquid.js @@ -658,6 +658,7 @@ module.exports = class liquid extends Exchange { const side = this.safeString (order, 'side'); return { 'id': orderId, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, diff --git a/TaskServer/node_modules/ccxt/js/livecoin.js b/TaskServer/node_modules/ccxt/js/livecoin.js index a08144a31..9f8395531 100644 --- a/TaskServer/node_modules/ccxt/js/livecoin.js +++ b/TaskServer/node_modules/ccxt/js/livecoin.js @@ -104,6 +104,7 @@ module.exports = class livecoin extends Exchange { 'RUR': 'RUB', 'SCT': 'SpaceCoin', 'TPI': 'ThaneCoin', + 'WAX': 'WAXP', 'wETT': 'WETT', 'XBT': 'Bricktox', }, @@ -254,6 +255,9 @@ module.exports = class livecoin extends Exchange { 'max': Math.pow (10, precision), }, }, + 'id': undefined, + 'code': undefined, + 'name': undefined, }; const currencies = [ { 'id': 'USD', 'code': 'USD', 'name': 'US Dollar' }, @@ -602,6 +606,7 @@ module.exports = class livecoin extends Exchange { return { 'info': order, 'id': order['id'], + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -620,6 +625,7 @@ module.exports = class livecoin extends Exchange { 'currency': feeCurrency, 'rate': feeRate, }, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/luno.js b/TaskServer/node_modules/ccxt/js/luno.js index aa6986fdd..26538662a 100644 --- a/TaskServer/node_modules/ccxt/js/luno.js +++ b/TaskServer/node_modules/ccxt/js/luno.js @@ -103,6 +103,9 @@ module.exports = class luno extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'info': market, + 'active': undefined, + 'precision': this.precision, + 'limits': this.limits, }); } return result; @@ -145,6 +148,23 @@ module.exports = class luno extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "base": "string", + // "completed_timestamp": "string", + // "counter": "string", + // "creation_timestamp": "string", + // "expiration_timestamp": "string", + // "fee_base": "string", + // "fee_counter": "string", + // "limit_price": "string", + // "limit_volume": "string", + // "order_id": "string", + // "pair": "string", + // "state": "PENDING", + // "type": "BID" + // } + // const timestamp = this.safeInteger (order, 'creation_timestamp'); const status = (order['state'] === 'PENDING') ? 'open' : 'closed'; const side = (order['type'] === 'ASK') ? 'sell' : 'buy'; @@ -183,6 +203,7 @@ module.exports = class luno extends Exchange { const id = this.safeString (order, 'order_id'); return { 'id': id, + 'clientOrderId': undefined, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, @@ -198,6 +219,7 @@ module.exports = class luno extends Exchange { 'trades': undefined, 'fee': fee, 'info': order, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/lykke.js b/TaskServer/node_modules/ccxt/js/lykke.js index a18711500..2e69a172e 100644 --- a/TaskServer/node_modules/ccxt/js/lykke.js +++ b/TaskServer/node_modules/ccxt/js/lykke.js @@ -255,6 +255,8 @@ module.exports = class lykke extends Exchange { 'max': undefined, }, }, + 'baseId': undefined, + 'quoteId': undefined, }); } return result; @@ -316,6 +318,23 @@ module.exports = class lykke extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "Id": "string", + // "Status": "Unknown", + // "AssetPairId": "string", + // "Volume": 0, + // "Price": 0, + // "RemainingVolume": 0, + // "LastMatchTime": "2020-03-26T20:58:50.710Z", + // "CreatedAt": "2020-03-26T20:58:50.710Z", + // "Type": "Unknown", + // "LowerLimitPrice": 0, + // "LowerPrice": 0, + // "UpperLimitPrice": 0, + // "UpperPrice": 0 + // } + // const status = this.parseOrderStatus (this.safeString (order, 'Status')); let symbol = undefined; if (market === undefined) { @@ -341,6 +360,7 @@ module.exports = class lykke extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -355,6 +375,7 @@ module.exports = class lykke extends Exchange { 'remaining': remaining, 'status': status, 'fee': undefined, + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/mercado.js b/TaskServer/node_modules/ccxt/js/mercado.js index ed02fd5b2..661b51b66 100644 --- a/TaskServer/node_modules/ccxt/js/mercado.js +++ b/TaskServer/node_modules/ccxt/js/mercado.js @@ -352,6 +352,7 @@ module.exports = class mercado extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, diff --git a/TaskServer/node_modules/ccxt/js/oceanex.js b/TaskServer/node_modules/ccxt/js/oceanex.js index 12e7fa96b..4cea6ef6b 100644 --- a/TaskServer/node_modules/ccxt/js/oceanex.js +++ b/TaskServer/node_modules/ccxt/js/oceanex.js @@ -94,6 +94,9 @@ module.exports = class oceanex extends Exchange { 'taker': 0.1 / 100, }, }, + 'commonCurrencies': { + 'PLA': 'Plair', + }, 'exceptions': { 'codes': { '-1': BadRequest, @@ -553,6 +556,23 @@ module.exports = class oceanex extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "created_at": "2019-01-18T00:38:18Z", + // "trades_count": 0, + // "remaining_volume": "0.2", + // "price": "1001.0", + // "created_on": "1547771898", + // "side": "buy", + // "volume": "0.2", + // "state": "wait", + // "ord_type": "limit", + // "avg_price": "0.0", + // "executed_volume": "0.0", + // "id": 473797, + // "market": "veteth" + // } + // const status = this.parseOrderStatus (this.safeValue (order, 'state')); const marketId = this.safeValue2 (order, 'market', 'market_id'); let symbol = undefined; @@ -576,6 +596,7 @@ module.exports = class oceanex extends Exchange { return { 'info': order, 'id': this.safeString (order, 'id'), + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, diff --git a/TaskServer/node_modules/ccxt/js/okcoin.js b/TaskServer/node_modules/ccxt/js/okcoin.js new file mode 100644 index 000000000..59c0c3cb2 --- /dev/null +++ b/TaskServer/node_modules/ccxt/js/okcoin.js @@ -0,0 +1,35 @@ +'use strict'; + +// --------------------------------------------------------------------------- + +const okex = require ('./okex.js'); + +// --------------------------------------------------------------------------- + +module.exports = class okcoin extends okex { + describe () { + return this.deepExtend (super.describe (), { + 'id': 'okcoin', + 'name': 'OKCoin', + 'countries': [ 'CN', 'US' ], + 'hostname': 'okcoin.com', + 'pro': true, + 'urls': { + 'logo': 'https://user-images.githubusercontent.com/1294454/27766791-89ffb502-5ee5-11e7-8a5b-c5950b68ac65.jpg', + 'www': 'https://www.okcoin.com', + 'doc': 'https://www.okcoin.com/docs/en/', + 'fees': 'https://www.okcoin.com/coin-fees', + 'referral': 'https://www.okcoin.com/account/register?flag=activity&channelId=600001513', + }, + 'fees': { + 'trading': { + 'taker': 0.002, + 'maker': 0.001, + }, + }, + 'options': { + 'fetchMarkets': [ 'spot' ], + }, + }); + } +}; diff --git a/TaskServer/node_modules/ccxt/js/okcoincny.js b/TaskServer/node_modules/ccxt/js/okcoincny.js deleted file mode 100644 index 04c306ff4..000000000 --- a/TaskServer/node_modules/ccxt/js/okcoincny.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -// --------------------------------------------------------------------------- - -const okcoinusd = require ('./okcoinusd.js'); - -// --------------------------------------------------------------------------- - -module.exports = class okcoincny extends okcoinusd { - describe () { - return this.deepExtend (super.describe (), { - 'id': 'okcoincny', - 'name': 'OKCoin CNY', - 'countries': [ 'CN' ], - 'has': { - 'CORS': false, - }, - 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/27766792-8be9157a-5ee5-11e7-926c-6d69b8d3378d.jpg', - 'api': { - 'web': 'https://www.okcoin.cn', - 'public': 'https://www.okcoin.cn/api', - 'private': 'https://www.okcoin.cn/api', - }, - 'www': 'https://www.okcoin.cn', - 'doc': 'https://www.okcoin.cn/rest_getStarted.html', - 'referral': 'https://www.okcoin.cn', - }, - 'markets': { - 'BTC/CNY': { 'id': 'btc_cny', 'symbol': 'BTC/CNY', 'base': 'BTC', 'quote': 'CNY', 'type': 'spot', 'spot': true, 'future': false }, - 'LTC/CNY': { 'id': 'ltc_cny', 'symbol': 'LTC/CNY', 'base': 'LTC', 'quote': 'CNY', 'type': 'spot', 'spot': true, 'future': false }, - 'ETH/CNY': { 'id': 'eth_cny', 'symbol': 'ETH/CNY', 'base': 'ETH', 'quote': 'CNY', 'type': 'spot', 'spot': true, 'future': false }, - 'ETC/CNY': { 'id': 'etc_cny', 'symbol': 'ETC/CNY', 'base': 'ETC', 'quote': 'CNY', 'type': 'spot', 'spot': true, 'future': false }, - 'BCH/CNY': { 'id': 'bcc_cny', 'symbol': 'BCH/CNY', 'base': 'BCH', 'quote': 'CNY', 'type': 'spot', 'spot': true, 'future': false }, - }, - }); - } -}; diff --git a/TaskServer/node_modules/ccxt/js/okcoinusd.js b/TaskServer/node_modules/ccxt/js/okcoinusd.js deleted file mode 100644 index 6e9e2cba7..000000000 --- a/TaskServer/node_modules/ccxt/js/okcoinusd.js +++ /dev/null @@ -1,1116 +0,0 @@ -'use strict'; - -// --------------------------------------------------------------------------- - -const Exchange = require ('./base/Exchange'); -const { BadSymbol, ExchangeError, ArgumentsRequired, DDoSProtection, InsufficientFunds, InvalidOrder, OrderNotFound, AuthenticationError, BadRequest } = require ('./base/errors'); - -// --------------------------------------------------------------------------- - -module.exports = class okcoinusd extends Exchange { - describe () { - return this.deepExtend (super.describe (), { - 'id': 'okcoinusd', - 'name': 'OKCoin USD', - 'countries': [ 'CN', 'US' ], - 'version': 'v1', - 'rateLimit': 1000, // up to 3000 requests per 5 minutes ≈ 600 requests per minute ≈ 10 requests per second ≈ 100 ms - 'has': { - 'CORS': false, - 'fetchOHLCV': true, - 'fetchOrder': true, - 'fetchOrders': false, - 'fetchOpenOrders': true, - 'fetchClosedOrders': true, - 'fetchTickers': true, - 'withdraw': true, - 'futures': false, - }, - 'extension': '.do', // appended to endpoint URL - 'timeframes': { - '1m': '1min', - '3m': '3min', - '5m': '5min', - '15m': '15min', - '30m': '30min', - '1h': '1hour', - '2h': '2hour', - '4h': '4hour', - '6h': '6hour', - '12h': '12hour', - '1d': '1day', - '3d': '3day', - '1w': '1week', - }, - 'api': { - 'v3': { - 'get': [ - 'futures/pc/market/futuresCoin', - ], - }, - 'web': { - 'get': [ - 'futures/pc/market/marketOverview', - 'spot/markets/index-tickers', - 'spot/markets/currencies', - 'spot/markets/products', - 'spot/markets/tickers', - 'spot/user-level', - ], - 'post': [ - 'futures/pc/market/futuresCoin', - ], - }, - 'public': { - 'get': [ - 'depth', - 'exchange_rate', - 'future_depth', - 'future_estimated_price', - 'future_hold_amount', - 'future_index', - 'future_kline', - 'future_price_limit', - 'future_ticker', - 'future_trades', - 'kline', - 'otcs', - 'ticker', - 'tickers', - 'trades', - ], - }, - 'private': { - 'post': [ - 'account_records', - 'batch_trade', - 'borrow_money', - 'borrow_order_info', - 'borrows_info', - 'cancel_borrow', - 'cancel_order', - 'cancel_otc_order', - 'cancel_withdraw', - 'funds_transfer', - 'future_batch_trade', - 'future_cancel', - 'future_devolve', - 'future_explosive', - 'future_order_info', - 'future_orders_info', - 'future_position', - 'future_position_4fix', - 'future_trade', - 'future_trades_history', - 'future_userinfo', - 'future_userinfo_4fix', - 'lend_depth', - 'order_fee', - 'order_history', - 'order_info', - 'orders_info', - 'otc_order_history', - 'otc_order_info', - 'repayment', - 'submit_otc_order', - 'trade', - 'trade_history', - 'trade_otc_order', - 'wallet_info', - 'withdraw', - 'withdraw_info', - 'unrepayments_info', - 'userinfo', - ], - }, - }, - 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/27766791-89ffb502-5ee5-11e7-8a5b-c5950b68ac65.jpg', - 'api': { - 'v3': 'https://www.okcoin.com/v3', - 'web': 'https://www.okcoin.com/v2', - 'public': 'https://www.okcoin.com/api', - 'private': 'https://www.okcoin.com', - }, - 'www': 'https://www.okcoin.com', - 'doc': [ - 'https://www.okcoin.com/docs/en/', - 'https://www.npmjs.com/package/okcoin.com', - ], - 'referral': 'https://www.okcoin.com/account/register?flag=activity&channelId=600001513', - 'fees': 'https://support.okcoin.com/hc/en-us/articles/360015261532-OKCoin-Fee-Rates', - }, - // these are okcoin.com fees, okex fees are in okex.js - 'fees': { - 'trading': { - 'taker': 0.002, - 'maker': 0.001, - }, - }, - 'exceptions': { - // see https://github.com/okcoin-okex/API-docs-OKEx.com/blob/master/API-For-Spot-EN/Error%20Code%20For%20Spot.md - '10000': ExchangeError, // "Required field, can not be null" - '10001': DDoSProtection, // "Request frequency too high to exceed the limit allowed" - '10005': AuthenticationError, // "'SecretKey' does not exist" - '10006': AuthenticationError, // "'Api_key' does not exist" - '10007': AuthenticationError, // "Signature does not match" - '1002': InsufficientFunds, // "The transaction amount exceed the balance" - '1003': InvalidOrder, // "The transaction amount is less than the minimum requirement" - '1004': InvalidOrder, // "The transaction amount is less than 0" - '1013': InvalidOrder, // no contract type (PR-1101) - '1027': InvalidOrder, // createLimitBuyOrder(symbol, 0, 0): Incorrect parameter may exceeded limits - '1050': InvalidOrder, // returned when trying to cancel an order that was filled or canceled previously - '1217': InvalidOrder, // "Order was sent at ±5% of the current market price. Please resend" - '10014': InvalidOrder, // "Order price must be between 0 and 1,000,000" - '1009': OrderNotFound, // for spot markets, cancelling closed order - '1019': OrderNotFound, // order closed? ("Undo order failed") - '1051': OrderNotFound, // for spot markets, cancelling "just closed" order - '10009': OrderNotFound, // for spot markets, "Order does not exist" - '20015': OrderNotFound, // for future markets - '10008': BadRequest, // Illegal URL parameter - '1007': BadSymbol, // No trading market information - // todo: sort out below - // 10000 Required parameter is empty - // 10001 Request frequency too high to exceed the limit allowed - // 10002 Authentication failure - // 10002 System error - // 10003 This connection has requested other user data - // 10004 Request failed - // 10005 api_key or sign is invalid, 'SecretKey' does not exist - // 10006 'Api_key' does not exist - // 10007 Signature does not match - // 10008 Illegal parameter, Parameter erorr - // 10009 Order does not exist - // 10010 Insufficient funds - // 10011 Amount too low - // 10012 Only btc_usd ltc_usd supported - // 10013 Only support https request - // 10014 Order price must be between 0 and 1,000,000 - // 10015 Order price differs from current market price too much / Channel subscription temporally not available - // 10016 Insufficient coins balance - // 10017 API authorization error / WebSocket authorization error - // 10018 borrow amount less than lower limit [usd:100,btc:0.1,ltc:1] - // 10019 loan agreement not checked - // 1002 The transaction amount exceed the balance - // 10020 rate cannot exceed 1% - // 10021 rate cannot less than 0.01% - // 10023 fail to get latest ticker - // 10024 balance not sufficient - // 10025 quota is full, cannot borrow temporarily - // 10026 Loan (including reserved loan) and margin cannot be withdrawn - // 10027 Cannot withdraw within 24 hrs of authentication information modification - // 10028 Withdrawal amount exceeds daily limit - // 10029 Account has unpaid loan, please cancel/pay off the loan before withdraw - // 1003 The transaction amount is less than the minimum requirement - // 10031 Deposits can only be withdrawn after 6 confirmations - // 10032 Please enabled phone/google authenticator - // 10033 Fee higher than maximum network transaction fee - // 10034 Fee lower than minimum network transaction fee - // 10035 Insufficient BTC/LTC - // 10036 Withdrawal amount too low - // 10037 Trade password not set - // 1004 The transaction amount is less than 0 - // 10040 Withdrawal cancellation fails - // 10041 Withdrawal address not exsit or approved - // 10042 Admin password error - // 10043 Account equity error, withdrawal failure - // 10044 fail to cancel borrowing order - // 10047 this function is disabled for sub-account - // 10048 withdrawal information does not exist - // 10049 User can not have more than 50 unfilled small orders (amount<0.15BTC) - // 10050 can't cancel more than once - // 10051 order completed transaction - // 10052 not allowed to withdraw - // 10064 after a USD deposit, that portion of assets will not be withdrawable for the next 48 hours - // 1008 No latest market information - // 1009 No order - // 1010 Different user of the cancelled order and the original order - // 10100 User account frozen - // 10101 order type is wrong - // 10102 incorrect ID - // 10103 the private otc order's key incorrect - // 10106 API key domain not matched - // 1011 No documented user - // 1013 No order type - // 1014 No login - // 1015 No market depth information - // 1017 Date error - // 1018 Order failed - // 1019 Undo order failed - // 10216 Non-available API / non-public API - // 1024 Currency does not exist - // 1025 No chart type - // 1026 No base currency quantity - // 1027 Incorrect parameter may exceeded limits - // 1028 Reserved decimal failed - // 1029 Preparing - // 1030 Account has margin and futures, transactions can not be processed - // 1031 Insufficient Transferring Balance - // 1032 Transferring Not Allowed - // 1035 Password incorrect - // 1036 Google Verification code Invalid - // 1037 Google Verification code incorrect - // 1038 Google Verification replicated - // 1039 Message Verification Input exceed the limit - // 1040 Message Verification invalid - // 1041 Message Verification incorrect - // 1042 Wrong Google Verification Input exceed the limit - // 1043 Login password cannot be same as the trading password - // 1044 Old password incorrect - // 1045 2nd Verification Needed - // 1046 Please input old password - // 1048 Account Blocked - // 1050 Orders have been withdrawn or withdrawn - // 1051 Order completed - // 1201 Account Deleted at 00: 00 - // 1202 Account Not Exist - // 1203 Insufficient Balance - // 1204 Invalid currency - // 1205 Invalid Account - // 1206 Cash Withdrawal Blocked - // 1207 Transfer Not Support - // 1208 No designated account - // 1209 Invalid api - // 1216 Market order temporarily suspended. Please send limit order - // 1217 Order was sent at ±5% of the current market price. Please resend - // 1218 Place order failed. Please try again later - // 20001 User does not exist - // 20002 Account frozen - // 20003 Account frozen due to forced liquidation - // 20004 Contract account frozen - // 20005 User contract account does not exist - // 20006 Required field missing - // 20007 Illegal parameter - // 20008 Contract account balance is too low - // 20009 Contract status error - // 20010 Risk rate ratio does not exist - // 20011 Risk rate lower than 90%/80% before opening BTC position with 10x/20x leverage. or risk rate lower than 80%/60% before opening LTC position with 10x/20x leverage - // 20012 Risk rate lower than 90%/80% after opening BTC position with 10x/20x leverage. or risk rate lower than 80%/60% after opening LTC position with 10x/20x leverage - // 20013 Temporally no counter party price - // 20014 System error - // 20015 Order does not exist - // 20016 Close amount bigger than your open positions, liquidation quantity bigger than holding - // 20017 Not authorized/illegal operation/illegal order ID - // 20018 Order price cannot be more than 103-105% or less than 95-97% of the previous minute price - // 20019 IP restricted from accessing the resource - // 20020 Secret key does not exist - // 20021 Index information does not exist - // 20022 Wrong API interface (Cross margin mode shall call cross margin API, fixed margin mode shall call fixed margin API) - // 20023 Account in fixed-margin mode - // 20024 Signature does not match - // 20025 Leverage rate error - // 20026 API Permission Error - // 20027 no transaction record - // 20028 no such contract - // 20029 Amount is large than available funds - // 20030 Account still has debts - // 20038 Due to regulation, this function is not availavle in the country/region your currently reside in. - // 20049 Request frequency too high - // 20100 request time out - // 20101 the format of data is error - // 20102 invalid login - // 20103 event type error - // 20104 subscription type error - // 20107 JSON format error - // 20115 The quote is not match - // 20116 Param not match - // 21020 Contracts are being delivered, orders cannot be placed - // 21021 Contracts are being settled, contracts cannot be placed - }, - 'options': { - 'marketBuyPrice': false, - 'fetchOHLCVWarning': true, - 'contractTypes': { - '1': 'this_week', - '2': 'next_week', - '4': 'quarter', - }, - 'fetchTickersMethod': 'fetch_tickers_from_api', - }, - }); - } - - async fetchMarkets (params = {}) { - // TODO: they have a new fee schedule as of Feb 7 - // the new fees are progressive and depend on 30-day traded volume - // the following is the worst case - const result = []; - const spotResponse = await this.webGetSpotMarketsProducts (); - // - // { - // "code": 0, - // "data": [ - // { - // "baseCurrency":0, - // "brokerId":0, - // "callAuctionOrCallNoCancelAuction":false, - // "callNoCancelSwitchTime":{}, - // "collect":"0", - // "continuousSwitchTime":{}, - // "groupId":1, - // "isMarginOpen":true, - // "listDisplay":0, - // "marginRiskPreRatio":1.2, - // "marginRiskRatio":1.1, - // "marketFrom":118, - // "maxMarginLeverage":5, - // "maxPriceDigit":1, - // "maxSizeDigit":8, - // "mergeTypes":"0.1,1,10", - // "minTradeSize":0.00100000, - // "online":1, - // "productId":20, - // "quoteCurrency":7, - // "quoteIncrement":"0.1", - // "quotePrecision":2, - // "sort":30038, - // "symbol":"btc_usdt", - // "tradingMode":3 - // }, - // ] - // } - // - const spotMarkets = this.safeValue (spotResponse, 'data', []); - let markets = spotMarkets; - if (this.has['futures']) { - const futuresResponse = await this.v3GetFuturesPcMarketFuturesCoin ({ - 'currencyCode': 0, - }); - // - // { - // "msg":"success", - // "code":0, - // "detailMsg":"", - // "data": [ - // { - // "symbolId":0, - // "symbol":"f_usd_btc", - // "iceSingleAvgMinAmount":2, - // "minTradeSize":1, - // "iceSingleAvgMaxAmount":500, - // "contractDepthLevel":["0.01","0.2"], - // "dealAllMaxAmount":999, - // "maxSizeDigit":4, - // "contracts":[ - // { "marketFrom":34, "id":201905240000034, "type":1, "desc":"BTC0524" }, - // { "marketFrom":13, "id":201905310000013, "type":2, "desc":"BTC0531" }, - // { "marketFrom":12, "id":201906280000012, "type":4, "desc":"BTC0628" }, - // ], - // "maxPriceDigit":2, - // "nativeRate":1, - // "quote":"usd", - // "nativeCurrency":"usd", - // "nativeCurrencyMark":"$", - // "contractSymbol":0, - // "unitAmount":100.00, - // "symbolMark":"฿", - // "symbolDesc":"BTC" - // }, - // ] - // } - // - const data = this.safeValue (futuresResponse, 'data', {}); - const futuresMarkets = this.safeValue (data, 'usd', []); - markets = this.arrayConcat (spotMarkets, futuresMarkets); - } - for (let i = 0; i < markets.length; i++) { - const market = markets[i]; - const id = this.safeString (market, 'symbol'); - let symbol = undefined; - let base = undefined; - let quote = undefined; - let baseId = undefined; - let quoteId = undefined; - let baseNumericId = undefined; - let quoteNumericId = undefined; - let lowercaseId = undefined; - let uppercaseBaseId = undefined; - const precision = { - 'amount': this.safeInteger (market, 'maxSizeDigit'), - 'price': this.safeInteger (market, 'maxPriceDigit'), - }; - const minAmount = this.safeFloat (market, 'minTradeSize'); - const minPrice = Math.pow (10, -precision['price']); - let contracts = this.safeValue (market, 'contracts'); - if (contracts === undefined) { - // spot markets - lowercaseId = id; - const parts = id.split ('_'); - baseId = parts[0]; - quoteId = parts[1]; - baseNumericId = this.safeInteger (market, 'baseCurrency'); - quoteNumericId = this.safeInteger (market, 'quoteCurrency'); - base = this.safeCurrencyCode (baseId); - quote = this.safeCurrencyCode (quoteId); - contracts = [{}]; - } else { - // futures markets - quoteId = this.safeStringLower2 (market, 'quote', 'denomination'); - uppercaseBaseId = this.safeStringLower (market, 'symbolDesc'); - baseId = uppercaseBaseId.toLowerCase (); - lowercaseId = baseId + '_' + quoteId; - base = this.safeCurrencyCode (uppercaseBaseId); - quote = this.safeCurrencyCode (quoteId); - } - for (let k = 0; k < contracts.length; k++) { - const contract = contracts[k]; - let type = this.safeString (contract, 'type', 'spot'); - let contractType = undefined; - let spot = true; - let future = false; - let active = true; - if (type === 'spot') { - symbol = base + '/' + quote; - active = market['online'] !== 0; - } else { - const contractId = this.safeString (contract, 'id'); - symbol = base + '-' + quote + '-' + contractId.slice (2, 8); - contractType = this.safeString (this.options['contractTypes'], type); - type = 'future'; - spot = false; - future = true; - } - const fees = this.safeValue2 (this.fees, type, 'trading', {}); - result.push (this.extend (fees, { - 'id': id, - 'lowercaseId': lowercaseId, - 'contractType': contractType, - 'symbol': symbol, - 'base': base, - 'quote': quote, - 'baseId': baseId, - 'quoteId': quoteId, - 'baseNumericId': baseNumericId, - 'quoteNumericId': quoteNumericId, - 'info': market, - 'type': type, - 'spot': spot, - 'future': future, - 'active': active, - 'precision': precision, - 'limits': { - 'amount': { - 'min': minAmount, - 'max': undefined, - }, - 'price': { - 'min': minPrice, - 'max': undefined, - }, - 'cost': { - 'min': minAmount * minPrice, - 'max': undefined, - }, - }, - })); - } - } - return result; - } - - calculateFee (symbol, type, side, amount, price, takerOrMaker = 'taker', params = {}) { - const market = this.markets[symbol]; - let key = 'quote'; - const rate = market[takerOrMaker]; - let cost = parseFloat (this.costToPrecision (symbol, amount * rate)); - if (side === 'sell') { - cost *= price; - } else { - key = 'base'; - } - return { - 'type': takerOrMaker, - 'currency': market[key], - 'rate': rate, - 'cost': parseFloat (this.feeToPrecision (symbol, cost)), - }; - } - - async fetchTickersFromApi (symbols = undefined, params = {}) { - await this.loadMarkets (); - const request = {}; - const response = await this.publicGetTickers (this.extend (request, params)); - const tickers = response['tickers']; - const timestamp = this.safeTimestamp (response, 'date'); - const result = {}; - for (let i = 0; i < tickers.length; i++) { - let ticker = tickers[i]; - ticker = this.parseTicker (this.extend (tickers[i], { 'timestamp': timestamp })); - const symbol = ticker['symbol']; - result[symbol] = ticker; - } - return result; - } - - async fetchTickersFromWeb (symbols = undefined, params = {}) { - await this.loadMarkets (); - const request = {}; - const response = await this.webGetSpotMarketsTickers (this.extend (request, params)); - const tickers = this.safeValue (response, 'data'); - const result = {}; - for (let i = 0; i < tickers.length; i++) { - const ticker = this.parseTicker (tickers[i]); - const symbol = ticker['symbol']; - result[symbol] = ticker; - } - return result; - } - - async fetchTickers (symbols = undefined, params = {}) { - const method = this.options['fetchTickersMethod']; - return await this[method] (symbols, params); - } - - async fetchOrderBook (symbol = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['future'] ? 'publicGetFutureDepth' : 'publicGetDepth'; - const request = this.createRequest (market, params); - if (limit !== undefined) { - request['size'] = limit; - } - const response = await this[method] (request); - return this.parseOrderBook (response); - } - - parseTicker (ticker, market = undefined) { - // - // { buy: "48.777300", - // change: "-1.244500", - // changePercentage: "-2.47%", - // close: "49.064000", - // createdDate: 1531704852254, - // currencyId: 527, - // dayHigh: "51.012500", - // dayLow: "48.124200", - // high: "51.012500", - // inflows: "0", - // last: "49.064000", - // low: "48.124200", - // marketFrom: 627, - // name: { }, - // open: "50.308500", - // outflows: "0", - // productId: 527, - // sell: "49.064000", - // symbol: "zec_okb", - // volume: "1049.092535" } - // - const timestamp = this.safeInteger2 (ticker, 'timestamp', 'createdDate'); - let symbol = undefined; - if (market === undefined) { - if ('symbol' in ticker) { - const marketId = ticker['symbol']; - if (marketId in this.markets_by_id) { - market = this.markets_by_id[marketId]; - } else { - const [ baseId, quoteId ] = ticker['symbol'].split ('_'); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - symbol = base + '/' + quote; - } - } - } - if (market !== undefined) { - symbol = market['symbol']; - } - const last = this.safeFloat (ticker, 'last'); - const open = this.safeFloat (ticker, 'open'); - const change = this.safeFloat (ticker, 'change'); - const percentage = this.safeFloat (ticker, 'changePercentage'); - return { - 'symbol': symbol, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'high': this.safeFloat (ticker, 'high'), - 'low': this.safeFloat (ticker, 'low'), - 'bid': this.safeFloat (ticker, 'buy'), - 'bidVolume': undefined, - 'ask': this.safeFloat (ticker, 'sell'), - 'askVolume': undefined, - 'vwap': undefined, - 'open': open, - 'close': last, - 'last': last, - 'previousClose': undefined, - 'change': change, - 'percentage': percentage, - 'average': undefined, - 'baseVolume': this.safeFloat2 (ticker, 'vol', 'volume'), - 'quoteVolume': undefined, - 'info': ticker, - }; - } - - async fetchTicker (symbol = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['future'] ? 'publicGetFutureTicker' : 'publicGetTicker'; - const request = this.createRequest (market, params); - const response = await this[method] (request); - let ticker = this.safeValue (response, 'ticker'); - if (ticker === undefined) { - throw new ExchangeError (this.id + ' fetchTicker returned an empty response: ' + this.json (response)); - } - const timestamp = this.safeTimestamp (response, 'date'); - if (timestamp !== undefined) { - ticker = this.extend (ticker, { 'timestamp': timestamp }); - } - return this.parseTicker (ticker, market); - } - - parseTrade (trade, market = undefined) { - let symbol = undefined; - if (market) { - symbol = market['symbol']; - } - const timestamp = this.safeInteger (trade, 'date_ms'); - const id = this.safeString (trade, 'tid'); - const type = undefined; - const side = this.safeString (trade, 'type'); - const price = this.safeFloat (trade, 'price'); - const amount = this.safeFloat (trade, 'amount'); - let cost = undefined; - if (price !== undefined) { - if (amount !== undefined) { - cost = price * amount; - } - } - return { - 'id': id, - 'info': trade, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': symbol, - 'order': undefined, - 'type': type, - 'side': side, - 'takerOrMaker': undefined, - 'price': price, - 'amount': amount, - 'cost': cost, - 'fee': undefined, - }; - } - - async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['future'] ? 'publicGetFutureTrades' : 'publicGetTrades'; - const request = this.createRequest (market, params); - const response = await this[method] (request); - return this.parseTrades (response, market, since, limit); - } - - parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) { - const numElements = ohlcv.length; - const volumeIndex = (numElements > 6) ? 6 : 5; - return [ - ohlcv[0], // timestamp - parseFloat (ohlcv[1]), // Open - parseFloat (ohlcv[2]), // High - parseFloat (ohlcv[3]), // Low - parseFloat (ohlcv[4]), // Close - // parseFloat (ohlcv[5]), // quote volume - // parseFloat (ohlcv[6]), // base volume - parseFloat (ohlcv[volumeIndex]), // okex will return base volume in the 7th element for future markets - ]; - } - - async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['future'] ? 'publicGetFutureKline' : 'publicGetKline'; - const request = this.createRequest (market, { - 'type': this.timeframes[timeframe], - }); - if (since !== undefined) { - request['since'] = parseInt ((this.milliseconds () - 86400000) / 1000); // default last 24h - } - if (limit !== undefined) { - if (this.options['fetchOHLCVWarning']) { - throw new ExchangeError (this.id + ' fetchOHLCV counts "limit" candles backwards in chronological ascending order, therefore the "limit" argument for ' + this.id + ' is disabled. Set ' + this.id + '.options["fetchOHLCVWarning"] = false to suppress this warning message.'); - } - request['size'] = parseInt (limit); // max is 1440 candles - } - const response = await this[method] (this.extend (request, params)); - return this.parseOHLCVs (response, market, timeframe, since, limit); - } - - async fetchBalance (params = {}) { - await this.loadMarkets (); - const response = await this.privatePostUserinfo (params); - const info = this.safeValue (response, 'info', {}); - const balances = this.safeValue (info, 'funds', {}); - const result = { 'info': response }; - let ids = Object.keys (balances['free']); - let usedField = 'freezed'; - // wtf, okex? - // https://github.com/okcoin-okex/API-docs-OKEx.com/commit/01cf9dd57b1f984a8737ef76a037d4d3795d2ac7 - if (!(usedField in balances)) { - usedField = 'holds'; - } - const usedKeys = Object.keys (balances[usedField]); - ids = this.arrayConcat (ids, usedKeys); - for (let i = 0; i < ids.length; i++) { - const id = ids[i]; - const code = this.safeCurrencyCode (id); - const account = this.account (); - account['free'] = this.safeFloat (balances['free'], id); - account['used'] = this.safeFloat (balances[usedField], id); - result[code] = account; - } - return this.parseBalance (result); - } - - async createOrder (symbol, type, side, amount, price = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['future'] ? 'privatePostFutureTrade' : 'privatePostTrade'; - const orderSide = (type === 'market') ? (side + '_market') : side; - const isMarketBuy = ((market['spot']) && (type === 'market') && (side === 'buy') && (!this.options['marketBuyPrice'])); - const orderPrice = isMarketBuy ? this.safeFloat (params, 'cost') : price; - const request = this.createRequest (market, { - 'type': orderSide, - }); - if (market['future']) { - request['match_price'] = (type === 'market') ? 1 : 0; // match best counter party price? 0 or 1, ignores price if 1 - request['lever_rate'] = 10; // leverage rate value: 10 or 20 (10 by default) - request['type'] = (side === 'buy') ? '1' : '2'; - } else if (type === 'market') { - if (side === 'buy') { - if (!orderPrice) { - if (this.options['marketBuyPrice']) { - // eslint-disable-next-line quotes - throw new ExchangeError (this.id + " market buy orders require a price argument (the amount you want to spend or the cost of the order) when this.options['marketBuyPrice'] is true."); - } else { - // eslint-disable-next-line quotes - throw new ExchangeError (this.id + " market buy orders require an additional cost parameter, cost = price * amount. If you want to pass the cost of the market order (the amount you want to spend) in the price argument (the default " + this.id + " behaviour), set this.options['marketBuyPrice'] = true. It will effectively suppress this warning exception as well."); - } - } else { - request['price'] = orderPrice; - } - } else { - request['amount'] = amount; - } - } - if (type !== 'market') { - request['price'] = orderPrice; - request['amount'] = amount; - } - params = this.omit (params, 'cost'); - const response = await this[method] (this.extend (request, params)); - const timestamp = this.milliseconds (); - return { - 'info': response, - 'id': this.safeString (response, 'order_id'), - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'lastTradeTimestamp': undefined, - 'status': undefined, - 'symbol': symbol, - 'type': type, - 'side': side, - 'price': price, - 'amount': amount, - 'filled': undefined, - 'remaining': undefined, - 'cost': undefined, - 'trades': undefined, - 'fee': undefined, - }; - } - - async cancelOrder (id, symbol = undefined, params = {}) { - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument'); - } - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['future'] ? 'privatePostFutureCancel' : 'privatePostCancelOrder'; - const request = this.createRequest (market, { - 'order_id': id, - }); - const response = await this[method] (this.extend (request, params)); - return response; - } - - parseOrderStatus (status) { - const statuses = { - '-1': 'canceled', - '0': 'open', - '1': 'open', - '2': 'closed', - '3': 'open', - '4': 'canceled', - }; - return this.safeValue (statuses, status, status); - } - - parseOrderSide (side) { - if (side === 1) { - return 'buy'; // open long position - } else if (side === 2) { - return 'sell'; // open short position - } else if (side === 3) { - return 'sell'; // liquidate long position - } else if (side === 4) { - return 'buy'; // liquidate short position - } - return side; - } - - parseOrder (order, market = undefined) { - let side = undefined; - let type = undefined; - if ('type' in order) { - if ((order['type'] === 'buy') || (order['type'] === 'sell')) { - side = order['type']; - type = 'limit'; - } else if (order['type'] === 'buy_market') { - side = 'buy'; - type = 'market'; - } else if (order['type'] === 'sell_market') { - side = 'sell'; - type = 'market'; - } else { - side = this.parseOrderSide (order['type']); - if (('contract_name' in order) || ('lever_rate' in order)) { - type = 'margin'; - } - } - } - const status = this.parseOrderStatus (this.safeString (order, 'status')); - let symbol = undefined; - if (market === undefined) { - const marketId = this.safeString (order, 'symbol'); - if (marketId in this.markets_by_id) { - market = this.markets_by_id[marketId]; - } - } - if (market) { - symbol = market['symbol']; - } - const createDateField = this.getCreateDateField (); - const timestamp = this.safeInteger (order, createDateField); - let amount = this.safeFloat (order, 'amount'); - const filled = this.safeFloat (order, 'deal_amount'); - amount = Math.max (amount, filled); - let remaining = Math.max (0, amount - filled); - if (type === 'market') { - remaining = 0; - } - let average = this.safeFloat (order, 'avg_price'); - // https://github.com/ccxt/ccxt/issues/2452 - average = this.safeFloat (order, 'price_avg', average); - const cost = average * filled; - return { - 'info': order, - 'id': this.safeString (order, 'order_id'), - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'lastTradeTimestamp': undefined, - 'symbol': symbol, - 'type': type, - 'side': side, - 'price': this.safeFloat (order, 'price'), - 'average': average, - 'cost': cost, - 'amount': amount, - 'filled': filled, - 'remaining': remaining, - 'status': status, - 'fee': undefined, - }; - } - - getCreateDateField () { - // needed for derived exchanges - // allcoin typo create_data instead of create_date - return 'create_date'; - } - - getOrdersField () { - // needed for derived exchanges - // allcoin typo order instead of orders (expected based on their API docs) - return 'orders'; - } - - async fetchOrder (id, symbol = undefined, params = {}) { - if (symbol === undefined) { - throw new ExchangeError (this.id + ' fetchOrder requires a symbol argument'); - } - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['future'] ? 'privatePostFutureOrderInfo' : 'privatePostOrderInfo'; - const request = this.createRequest (market, { - 'order_id': id, - // 'status': 0, // 0 for unfilled orders, 1 for filled orders - // 'current_page': 1, // current page number - // 'page_length': 200, // number of orders returned per page, maximum 200 - }); - const response = await this[method] (this.extend (request, params)); - const ordersField = this.getOrdersField (); - const numOrders = response[ordersField].length; - if (numOrders > 0) { - return this.parseOrder (response[ordersField][0]); - } - throw new OrderNotFound (this.id + ' order ' + id + ' not found'); - } - - async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - if (symbol === undefined) { - throw new ExchangeError (this.id + ' fetchOrders requires a symbol argument'); - } - await this.loadMarkets (); - const market = this.market (symbol); - let method = market['future'] ? 'privatePostFutureOrdersInfo' : 'privatePost'; - let request = this.createRequest (market); - const order_id_in_params = ('order_id' in params); - if (market['future']) { - if (!order_id_in_params) { - throw new ExchangeError (this.id + ' fetchOrders() requires order_id param for futures market ' + symbol + ' (a string of one or more order ids, comma-separated)'); - } - } else { - const status = ('type' in params) ? params['type'] : params['status']; - if (typeof status === 'undefined') { - const name = order_id_in_params ? 'type' : 'status'; - throw new ExchangeError (this.id + ' fetchOrders() requires ' + name + ' param for spot market ' + symbol + ' (0 - for unfilled orders, 1 - for filled/canceled orders)'); - } - if (order_id_in_params) { - method += 'OrdersInfo'; - request = this.extend (request, { - 'type': status, - 'order_id': params['order_id'], - }); - } else { - method += 'OrderHistory'; - request = this.extend (request, { - 'status': status, - 'current_page': 1, // current page number - 'page_length': 200, // number of orders returned per page, maximum 200 - }); - } - params = this.omit (params, [ 'type', 'status' ]); - } - const response = await this[method] (this.extend (request, params)); - const ordersField = this.getOrdersField (); - return this.parseOrders (response[ordersField], market, since, limit); - } - - async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - const request = { - 'status': 0, // 0 for unfilled orders, 1 for filled orders - }; - return await this.fetchOrders (symbol, since, limit, this.extend (request, params)); - } - - async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - const request = { - 'status': 1, // 0 for unfilled orders, 1 for filled orders - }; - return await this.fetchOrders (symbol, since, limit, this.extend (request, params)); - } - - async withdraw (code, amount, address, tag = undefined, params = {}) { - this.checkAddress (address); - await this.loadMarkets (); - const currency = this.currency (code); - // if (amount < 0.01) - // throw new ExchangeError (this.id + ' withdraw() requires amount > 0.01'); - // for some reason they require to supply a pair of currencies for withdrawing one currency - const currencyId = currency['id'] + '_usd'; - if (tag) { - address = address + ':' + tag; - } - const request = { - 'symbol': currencyId, - 'withdraw_address': address, - 'withdraw_amount': amount, - 'target': 'address', // or 'okcn', 'okcom', 'okex' - }; - let query = params; - if ('chargefee' in query) { - request['chargefee'] = query['chargefee']; - query = this.omit (query, 'chargefee'); - } else { - throw new ExchangeError (this.id + ' withdraw() requires a `chargefee` parameter'); - } - if (this.password) { - request['trade_pwd'] = this.password; - } else if ('password' in query) { - request['trade_pwd'] = query['password']; - query = this.omit (query, 'password'); - } else if ('trade_pwd' in query) { - request['trade_pwd'] = query['trade_pwd']; - query = this.omit (query, 'trade_pwd'); - } - const passwordInRequest = ('trade_pwd' in request); - if (!passwordInRequest) { - throw new ExchangeError (this.id + ' withdraw() requires this.password set on the exchange instance or a password / trade_pwd parameter'); - } - const response = await this.privatePostWithdraw (this.extend (request, query)); - return { - 'info': response, - 'id': this.safeString (response, 'withdraw_id'), - }; - } - - sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = '/'; - const isWebApi = (api === 'web') || (api === 'v3'); - if (!isWebApi) { - url += this.version + '/'; - } - url += path; - if (!isWebApi) { - url += this.extension; - } - if (api === 'private') { - this.checkRequiredCredentials (); - const query = this.keysort (this.extend ({ - 'api_key': this.apiKey, - }, params)); - // secret key must be at the end of query - const queryString = this.rawencode (query) + '&secret_key=' + this.secret; - query['sign'] = this.hash (this.encode (queryString)).toUpperCase (); - body = this.urlencode (query); - headers = { 'Content-Type': 'application/x-www-form-urlencoded' }; - } else { - if (Object.keys (params).length) { - url += '?' + this.urlencode (params); - } - } - url = this.urls['api'][api] + url; - return { 'url': url, 'method': method, 'body': body, 'headers': headers }; - } - - createRequest (market, params = {}) { - if (market['future']) { - return this.deepExtend ({ - 'symbol': market['lowercaseId'], - 'contract_type': market['contractType'], - }, params); - } - return this.deepExtend ({ - 'symbol': market['id'], - }, params); - } - - handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { - if (response === undefined) { - return; // fallback to default error handler - } - if ('error_code' in response) { - const error = this.safeString (response, 'error_code'); - const message = this.id + ' ' + body; - this.throwExactlyMatchedException (this.exceptions, error, message); - throw new ExchangeError (message); - } - if ('result' in response) { - if (!response['result']) { - throw new ExchangeError (this.id + ' ' + body); - } - } - } -}; diff --git a/TaskServer/node_modules/ccxt/js/okex.js b/TaskServer/node_modules/ccxt/js/okex.js index d13a78f98..d7e5c73cd 100644 --- a/TaskServer/node_modules/ccxt/js/okex.js +++ b/TaskServer/node_modules/ccxt/js/okex.js @@ -1,37 +1,276 @@ 'use strict'; -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- -const okcoinusd = require ('./okcoinusd.js'); +const Exchange = require ('./base/Exchange'); +const { ExchangeError, ExchangeNotAvailable, ArgumentsRequired, BadRequest, AccountSuspended, InvalidAddress, PermissionDenied, DDoSProtection, InsufficientFunds, InvalidNonce, CancelPending, InvalidOrder, OrderNotFound, AuthenticationError, RequestTimeout, NotSupported, BadSymbol } = require ('./base/errors'); +const { TICK_SIZE, TRUNCATE } = require ('./base/functions/number'); -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- -module.exports = class okex extends okcoinusd { +module.exports = class okex extends Exchange { describe () { return this.deepExtend (super.describe (), { 'id': 'okex', 'name': 'OKEX', 'countries': [ 'CN', 'US' ], + 'version': 'v3', + 'rateLimit': 1000, // up to 3000 requests per 5 minutes ≈ 600 requests per minute ≈ 10 requests per second ≈ 100 ms + 'pro': true, 'has': { 'CORS': false, - 'futures': true, + 'fetchOHLCV': true, + 'fetchOrder': true, + 'fetchOrders': false, + 'fetchOpenOrders': true, + 'fetchClosedOrders': true, + 'fetchCurrencies': false, // see below + 'fetchDeposits': true, + 'fetchWithdrawals': true, + 'fetchTime': true, + 'fetchTransactions': false, + 'fetchMyTrades': true, + 'fetchDepositAddress': true, + 'fetchOrderTrades': true, 'fetchTickers': true, + 'fetchLedger': true, + 'withdraw': true, + 'futures': true, }, + 'timeframes': { + '1m': '60', + '3m': '180', + '5m': '300', + '15m': '900', + '30m': '1800', + '1h': '3600', + '2h': '7200', + '4h': '14400', + '6h': '21600', + '12h': '43200', + '1d': '86400', + '1w': '604800', + }, + 'hostname': 'okex.com', 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/32552768-0d6dd3c6-c4a6-11e7-90f8-c043b64756a7.jpg', 'api': { - 'v3': 'https://www.okex.com/v3', - 'web': 'https://www.okex.com/v2', - 'public': 'https://www.okex.com/api', - 'private': 'https://www.okex.com/api', + 'rest': 'https://www.{hostname}', }, 'www': 'https://www.okex.com', - 'doc': [ - 'https://github.com/okcoin-okex/API-docs-OKEx.com', - 'https://www.okex.com/docs/en/', - ], + 'doc': 'https://www.okex.com/docs/en/', 'fees': 'https://www.okex.com/pages/products/fees.html', - 'referral': 'https://www.okex.com', + 'referral': 'https://www.okex.com/join/1888677', + }, + 'api': { + 'general': { + 'get': [ + 'time', + ], + }, + 'account': { + 'get': [ + 'wallet', + 'sub-account', + 'asset-valuation', + 'wallet/{currency}', + 'withdrawal/history', + 'withdrawal/history/{currency}', + 'ledger', + 'deposit/address', + 'deposit/history', + 'deposit/history/{currency}', + 'currencies', + 'withdrawal/fee', + ], + 'post': [ + 'transfer', + 'withdrawal', + ], + }, + 'spot': { + 'get': [ + 'accounts', + 'accounts/{currency}', + 'accounts/{currency}/ledger', + 'orders', + 'orders_pending', + 'orders/{order_id}', + 'orders/{client_oid}', + 'trade_fee', + 'fills', + 'algo', + // public + 'instruments', + 'instruments/{instrument_id}/book', + 'instruments/ticker', + 'instruments/{instrument_id}/ticker', + 'instruments/{instrument_id}/trades', + 'instruments/{instrument_id}/candles', + ], + 'post': [ + 'order_algo', + 'orders', + 'batch_orders', + 'cancel_orders/{order_id}', + 'cancel_orders/{client_oid}', + 'cancel_batch_algos', + 'cancel_batch_orders', + ], + }, + 'margin': { + 'get': [ + 'accounts', + 'accounts/{instrument_id}', + 'accounts/{instrument_id}/ledger', + 'accounts/availability', + 'accounts/{instrument_id}/availability', + 'accounts/borrowed', + 'accounts/{instrument_id}/borrowed', + 'orders', + 'accounts/{instrument_id}/leverage', + 'orders/{order_id}', + 'orders/{client_oid}', + 'orders_pending', + 'fills', + // public + 'instruments/{instrument_id}/mark_price', + ], + 'post': [ + 'accounts/borrow', + 'accounts/repayment', + 'orders', + 'batch_orders', + 'cancel_orders', + 'cancel_orders/{order_id}', + 'cancel_orders/{client_oid}', + 'cancel_batch_orders', + 'accounts/{instrument_id}/leverage', + ], + }, + 'futures': { + 'get': [ + 'position', + '{instrument_id}/position', + 'accounts', + 'accounts/{underlying}', + 'accounts/{underlying}/leverage', + 'accounts/{underlying}/ledger', + 'order_algo/{instrument_id}', + 'orders/{instrument_id}', + 'orders/{instrument_id}/{order_id}', + 'orders/{instrument_id}/{client_oid}', + 'fills', + 'trade_fee', + 'accounts/{instrument_id}/holds', + 'order_algo/{instrument_id}', + // public + 'instruments', + 'instruments/{instrument_id}/book', + 'instruments/ticker', + 'instruments/{instrument_id}/ticker', + 'instruments/{instrument_id}/trades', + 'instruments/{instrument_id}/candles', + 'instruments/{instrument_id}/index', + 'rate', + 'instruments/{instrument_id}/estimated_price', + 'instruments/{instrument_id}/open_interest', + 'instruments/{instrument_id}/price_limit', + 'instruments/{instrument_id}/mark_price', + 'instruments/{instrument_id}/liquidation', + ], + 'post': [ + 'accounts/{underlying}/leverage', + 'order', + 'orders', + 'cancel_order/{instrument_id}/{order_id}', + 'cancel_order/{instrument_id}/{client_oid}', + 'cancel_batch_orders/{instrument_id}', + 'accounts/margin_mode', + 'close_position', + 'cancel_all', + 'order_algo', + 'cancel_algos', + ], + }, + 'swap': { + 'get': [ + 'position', + '{instrument_id}/position', + 'accounts', + '{instrument_id}/accounts', + 'accounts/{instrument_id}/settings', + 'accounts/{instrument_id}/ledger', + 'orders/{instrument_id}', + 'orders/{instrument_id}/{order_id}', + 'orders/{instrument_id}/{client_oid}', + 'fills', + 'accounts/{instrument_id}/holds', + 'trade_fee', + 'order_algo/{instrument_id}', + // public + 'instruments', + 'instruments/{instrument_id}/depth', + 'instruments/ticker', + 'instruments/{instrument_id}/ticker', + 'instruments/{instrument_id}/trades', + 'instruments/{instrument_id}/candles', + 'instruments/{instrument_id}/index', + 'rate', + 'instruments/{instrument_id}/open_interest', + 'instruments/{instrument_id}/price_limit', + 'instruments/{instrument_id}/liquidation', + 'instruments/{instrument_id}/funding_time', + 'instruments/{instrument_id}/mark_price', + 'instruments/{instrument_id}/historical_funding_rate', + ], + 'post': [ + 'accounts/{instrument_id}/leverage', + 'order', + 'orders', + 'cancel_order/{instrument_id}/{order_id}', + 'cancel_order/{instrument_id}/{client_oid}', + 'cancel_batch_orders/{instrument_id}', + 'order_algo', + 'cancel_algos', + ], + }, + 'option': { + 'get': [ + 'accounts', + '{underlying}/position', + 'accounts/{underlying}', + 'orders/{underlying}', + 'fills/{underlying}', + 'accounts/{underlying}/ledger', + 'trade_fee', + 'orders/{underlying}/{order_id}', + 'orders/{underlying}/{client_oid}', + // public + 'underlying', + 'instruments/{underlying}', + 'instruments/{underlying}/summary', + 'instruments/{underlying}/summary/{instrument_id}', + 'instruments/{instrument_id}/book', + 'instruments/{instrument_id}/trades', + 'instruments/{instrument_id}/ticker', + 'instruments/{instrument_id}/candles', + ], + 'post': [ + 'order', + 'orders', + 'cancel_order/{underlying}/{order_id}', + 'cancel_order/{underlying}/{client_oid}', + 'cancel_batch_orders/{underlying}', + 'amend_order/{underlying}', + 'amend_batch_orders/{underlying}', + ], + }, + 'index': { + 'get': [ + '{instrument_id}/constituents', + ], + }, }, 'fees': { 'trading': { @@ -42,13 +281,365 @@ module.exports = class okex extends okcoinusd { 'taker': 0.0015, 'maker': 0.0010, }, - 'future': { + 'futures': { 'taker': 0.0005, 'maker': 0.0002, }, 'swap': { 'taker': 0.00075, - 'maker': 0.0002, + 'maker': 0.00020, + }, + }, + 'requiredCredentials': { + 'apiKey': true, + 'secret': true, + 'password': true, + }, + 'exceptions': { + // http error codes + // 400 Bad Request — Invalid request format + // 401 Unauthorized — Invalid API Key + // 403 Forbidden — You do not have access to the requested resource + // 404 Not Found + // 500 Internal Server Error — We had a problem with our server + 'exact': { + '1': ExchangeError, // { "code": 1, "message": "System error" } + // undocumented + 'failure to get a peer from the ring-balancer': ExchangeNotAvailable, // { "message": "failure to get a peer from the ring-balancer" } + '4010': PermissionDenied, // { "code": 4010, "message": "For the security of your funds, withdrawals are not permitted within 24 hours after changing fund password / mobile number / Google Authenticator settings " } + // common + // '0': ExchangeError, // 200 successful,when the order placement / cancellation / operation is successful + '4001': ExchangeError, // no data received in 30s + '4002': ExchangeError, // Buffer full. cannot write data + // -------------------------------------------------------- + '30001': AuthenticationError, // { "code": 30001, "message": 'request header "OK_ACCESS_KEY" cannot be blank'} + '30002': AuthenticationError, // { "code": 30002, "message": 'request header "OK_ACCESS_SIGN" cannot be blank'} + '30003': AuthenticationError, // { "code": 30003, "message": 'request header "OK_ACCESS_TIMESTAMP" cannot be blank'} + '30004': AuthenticationError, // { "code": 30004, "message": 'request header "OK_ACCESS_PASSPHRASE" cannot be blank'} + '30005': InvalidNonce, // { "code": 30005, "message": "invalid OK_ACCESS_TIMESTAMP" } + '30006': AuthenticationError, // { "code": 30006, "message": "invalid OK_ACCESS_KEY" } + '30007': BadRequest, // { "code": 30007, "message": 'invalid Content_Type, please use "application/json" format'} + '30008': RequestTimeout, // { "code": 30008, "message": "timestamp request expired" } + '30009': ExchangeError, // { "code": 30009, "message": "system error" } + '30010': AuthenticationError, // { "code": 30010, "message": "API validation failed" } + '30011': PermissionDenied, // { "code": 30011, "message": "invalid IP" } + '30012': AuthenticationError, // { "code": 30012, "message": "invalid authorization" } + '30013': AuthenticationError, // { "code": 30013, "message": "invalid sign" } + '30014': DDoSProtection, // { "code": 30014, "message": "request too frequent" } + '30015': AuthenticationError, // { "code": 30015, "message": 'request header "OK_ACCESS_PASSPHRASE" incorrect'} + '30016': ExchangeError, // { "code": 30015, "message": "you are using v1 apiKey, please use v1 endpoint. If you would like to use v3 endpoint, please subscribe to v3 apiKey" } + '30017': ExchangeError, // { "code": 30017, "message": "apikey's broker id does not match" } + '30018': ExchangeError, // { "code": 30018, "message": "apikey's domain does not match" } + '30019': ExchangeNotAvailable, // { "code": 30019, "message": "Api is offline or unavailable" } + '30020': BadRequest, // { "code": 30020, "message": "body cannot be blank" } + '30021': BadRequest, // { "code": 30021, "message": "Json data format error" }, { "code": 30021, "message": "json data format error" } + '30022': PermissionDenied, // { "code": 30022, "message": "Api has been frozen" } + '30023': BadRequest, // { "code": 30023, "message": "{0} parameter cannot be blank" } + '30024': BadSymbol, // {"code":30024,"message":"\"instrument_id\" is an invalid parameter"} + '30025': BadRequest, // { "code": 30025, "message": "{0} parameter category error" } + '30026': DDoSProtection, // { "code": 30026, "message": "requested too frequent" } + '30027': AuthenticationError, // { "code": 30027, "message": "login failure" } + '30028': PermissionDenied, // { "code": 30028, "message": "unauthorized execution" } + '30029': AccountSuspended, // { "code": 30029, "message": "account suspended" } + '30030': ExchangeError, // { "code": 30030, "message": "endpoint request failed. Please try again" } + '30031': BadRequest, // { "code": 30031, "message": "token does not exist" } + '30032': BadSymbol, // { "code": 30032, "message": "pair does not exist" } + '30033': BadRequest, // { "code": 30033, "message": "exchange domain does not exist" } + '30034': ExchangeError, // { "code": 30034, "message": "exchange ID does not exist" } + '30035': ExchangeError, // { "code": 30035, "message": "trading is not supported in this website" } + '30036': ExchangeError, // { "code": 30036, "message": "no relevant data" } + '30038': AuthenticationError, // { "code": 30038, "message": "user does not exist" } + '30037': ExchangeNotAvailable, // { "code": 30037, "message": "endpoint is offline or unavailable" } + // futures + '32001': AccountSuspended, // { "code": 32001, "message": "futures account suspended" } + '32002': PermissionDenied, // { "code": 32002, "message": "futures account does not exist" } + '32003': CancelPending, // { "code": 32003, "message": "canceling, please wait" } + '32004': ExchangeError, // { "code": 32004, "message": "you have no unfilled orders" } + '32005': InvalidOrder, // { "code": 32005, "message": "max order quantity" } + '32006': InvalidOrder, // { "code": 32006, "message": "the order price or trigger price exceeds USD 1 million" } + '32007': InvalidOrder, // { "code": 32007, "message": "leverage level must be the same for orders on the same side of the contract" } + '32008': InvalidOrder, // { "code": 32008, "message": "Max. positions to open (cross margin)" } + '32009': InvalidOrder, // { "code": 32009, "message": "Max. positions to open (fixed margin)" } + '32010': ExchangeError, // { "code": 32010, "message": "leverage cannot be changed with open positions" } + '32011': ExchangeError, // { "code": 32011, "message": "futures status error" } + '32012': ExchangeError, // { "code": 32012, "message": "futures order update error" } + '32013': ExchangeError, // { "code": 32013, "message": "token type is blank" } + '32014': ExchangeError, // { "code": 32014, "message": "your number of contracts closing is larger than the number of contracts available" } + '32015': ExchangeError, // { "code": 32015, "message": "margin ratio is lower than 100% before opening positions" } + '32016': ExchangeError, // { "code": 32016, "message": "margin ratio is lower than 100% after opening position" } + '32017': ExchangeError, // { "code": 32017, "message": "no BBO" } + '32018': ExchangeError, // { "code": 32018, "message": "the order quantity is less than 1, please try again" } + '32019': ExchangeError, // { "code": 32019, "message": "the order price deviates from the price of the previous minute by more than 3%" } + '32020': ExchangeError, // { "code": 32020, "message": "the price is not in the range of the price limit" } + '32021': ExchangeError, // { "code": 32021, "message": "leverage error" } + '32022': ExchangeError, // { "code": 32022, "message": "this function is not supported in your country or region according to the regulations" } + '32023': ExchangeError, // { "code": 32023, "message": "this account has outstanding loan" } + '32024': ExchangeError, // { "code": 32024, "message": "order cannot be placed during delivery" } + '32025': ExchangeError, // { "code": 32025, "message": "order cannot be placed during settlement" } + '32026': ExchangeError, // { "code": 32026, "message": "your account is restricted from opening positions" } + '32027': ExchangeError, // { "code": 32027, "message": "cancelled over 20 orders" } + '32028': ExchangeError, // { "code": 32028, "message": "account is suspended and liquidated" } + '32029': ExchangeError, // { "code": 32029, "message": "order info does not exist" } + '32030': InvalidOrder, // The order cannot be cancelled + '32031': ArgumentsRequired, // client_oid or order_id is required. + '32038': AuthenticationError, // User does not exist + '32040': ExchangeError, // User have open contract orders or position + '32044': ExchangeError, // { "code": 32044, "message": "The margin ratio after submitting this order is lower than the minimum requirement ({0}) for your tier." } + '32045': ExchangeError, // String of commission over 1 million + '32046': ExchangeError, // Each user can hold up to 10 trade plans at the same time + '32047': ExchangeError, // system error + '32048': InvalidOrder, // Order strategy track range error + '32049': ExchangeError, // Each user can hold up to 10 track plans at the same time + '32050': InvalidOrder, // Order strategy rang error + '32051': InvalidOrder, // Order strategy ice depth error + '32052': ExchangeError, // String of commission over 100 thousand + '32053': ExchangeError, // Each user can hold up to 6 ice plans at the same time + '32057': ExchangeError, // The order price is zero. Market-close-all function cannot be executed + '32054': ExchangeError, // Trade not allow + '32055': InvalidOrder, // cancel order error + '32056': ExchangeError, // iceberg per order average should between {0}-{1} contracts + '32058': ExchangeError, // Each user can hold up to 6 initiative plans at the same time + '32059': InvalidOrder, // Total amount should exceed per order amount + '32060': InvalidOrder, // Order strategy type error + '32061': InvalidOrder, // Order strategy initiative limit error + '32062': InvalidOrder, // Order strategy initiative range error + '32063': InvalidOrder, // Order strategy initiative rate error + '32064': ExchangeError, // Time Stringerval of orders should set between 5-120s + '32065': ExchangeError, // Close amount exceeds the limit of Market-close-all (999 for BTC, and 9999 for the rest tokens) + '32066': ExchangeError, // You have open orders. Please cancel all open orders before changing your leverage level. + '32067': ExchangeError, // Account equity < required margin in this setting. Please adjust your leverage level again. + '32068': ExchangeError, // The margin for this position will fall short of the required margin in this setting. Please adjust your leverage level or increase your margin to proceed. + '32069': ExchangeError, // Target leverage level too low. Your account balance is insufficient to cover the margin required. Please adjust the leverage level again. + '32070': ExchangeError, // Please check open position or unfilled order + '32071': ExchangeError, // Your current liquidation mode does not support this action. + '32072': ExchangeError, // The highest available margin for your order’s tier is {0}. Please edit your margin and place a new order. + '32073': ExchangeError, // The action does not apply to the token + '32074': ExchangeError, // The number of contracts of your position, open orders, and the current order has exceeded the maximum order limit of this asset. + '32075': ExchangeError, // Account risk rate breach + '32076': ExchangeError, // Liquidation of the holding position(s) at market price will require cancellation of all pending close orders of the contracts. + '32077': ExchangeError, // Your margin for this asset in futures account is insufficient and the position has been taken over for liquidation. (You will not be able to place orders, close positions, transfer funds, or add margin during this period of time. Your account will be restored after the liquidation is complete.) + '32078': ExchangeError, // Please cancel all open orders before switching the liquidation mode(Please cancel all open orders before switching the liquidation mode) + '32079': ExchangeError, // Your open positions are at high risk.(Please add margin or reduce positions before switching the mode) + '32080': ExchangeError, // Funds cannot be transferred out within 30 minutes after futures settlement + '32083': ExchangeError, // The number of contracts should be a positive multiple of %%. Please place your order again + // token and margin trading + '33001': PermissionDenied, // { "code": 33001, "message": "margin account for this pair is not enabled yet" } + '33002': AccountSuspended, // { "code": 33002, "message": "margin account for this pair is suspended" } + '33003': InsufficientFunds, // { "code": 33003, "message": "no loan balance" } + '33004': ExchangeError, // { "code": 33004, "message": "loan amount cannot be smaller than the minimum limit" } + '33005': ExchangeError, // { "code": 33005, "message": "repayment amount must exceed 0" } + '33006': ExchangeError, // { "code": 33006, "message": "loan order not found" } + '33007': ExchangeError, // { "code": 33007, "message": "status not found" } + '33008': ExchangeError, // { "code": 33008, "message": "loan amount cannot exceed the maximum limit" } + '33009': ExchangeError, // { "code": 33009, "message": "user ID is blank" } + '33010': ExchangeError, // { "code": 33010, "message": "you cannot cancel an order during session 2 of call auction" } + '33011': ExchangeError, // { "code": 33011, "message": "no new market data" } + '33012': ExchangeError, // { "code": 33012, "message": "order cancellation failed" } + '33013': InvalidOrder, // { "code": 33013, "message": "order placement failed" } + '33014': OrderNotFound, // { "code": 33014, "message": "order does not exist" } + '33015': InvalidOrder, // { "code": 33015, "message": "exceeded maximum limit" } + '33016': ExchangeError, // { "code": 33016, "message": "margin trading is not open for this token" } + '33017': InsufficientFunds, // { "code": 33017, "message": "insufficient balance" } + '33018': ExchangeError, // { "code": 33018, "message": "this parameter must be smaller than 1" } + '33020': ExchangeError, // { "code": 33020, "message": "request not supported" } + '33021': BadRequest, // { "code": 33021, "message": "token and the pair do not match" } + '33022': InvalidOrder, // { "code": 33022, "message": "pair and the order do not match" } + '33023': ExchangeError, // { "code": 33023, "message": "you can only place market orders during call auction" } + '33024': InvalidOrder, // { "code": 33024, "message": "trading amount too small" } + '33025': InvalidOrder, // { "code": 33025, "message": "base token amount is blank" } + '33026': ExchangeError, // { "code": 33026, "message": "transaction completed" } + '33027': InvalidOrder, // { "code": 33027, "message": "cancelled order or order cancelling" } + '33028': InvalidOrder, // { "code": 33028, "message": "the decimal places of the trading price exceeded the limit" } + '33029': InvalidOrder, // { "code": 33029, "message": "the decimal places of the trading size exceeded the limit" } + '33034': ExchangeError, // { "code": 33034, "message": "You can only place limit order after Call Auction has started" } + '33035': ExchangeError, // This type of order cannot be canceled(This type of order cannot be canceled) + '33036': ExchangeError, // Exceeding the limit of entrust order + '33037': ExchangeError, // The buy order price should be lower than 130% of the trigger price + '33038': ExchangeError, // The sell order price should be higher than 70% of the trigger price + '33039': ExchangeError, // The limit of callback rate is 0 < x <= 5% + '33040': ExchangeError, // The trigger price of a buy order should be lower than the latest transaction price + '33041': ExchangeError, // The trigger price of a sell order should be higher than the latest transaction price + '33042': ExchangeError, // The limit of price variance is 0 < x <= 1% + '33043': ExchangeError, // The total amount must be larger than 0 + '33044': ExchangeError, // The average amount should be 1/1000 * total amount <= x <= total amount + '33045': ExchangeError, // The price should not be 0, including trigger price, order price, and price limit + '33046': ExchangeError, // Price variance should be 0 < x <= 1% + '33047': ExchangeError, // Sweep ratio should be 0 < x <= 100% + '33048': ExchangeError, // Per order limit: Total amount/1000 < x <= Total amount + '33049': ExchangeError, // Total amount should be X > 0 + '33050': ExchangeError, // Time interval should be 5 <= x <= 120s + '33051': ExchangeError, // cancel order number not higher limit: plan and track entrust no more than 10, ice and time entrust no more than 6 + '33059': BadRequest, // { "code": 33059, "message": "client_oid or order_id is required" } + '33060': BadRequest, // { "code": 33060, "message": "Only fill in either parameter client_oid or order_id" } + '33061': ExchangeError, // Value of a single market price order cannot exceed 100,000 USD + '33062': ExchangeError, // The leverage ratio is too high. The borrowed position has exceeded the maximum position of this leverage ratio. Please readjust the leverage ratio + '33063': ExchangeError, // Leverage multiple is too low, there is insufficient margin in the account, please readjust the leverage ratio + '33064': ExchangeError, // The setting of the leverage ratio cannot be less than 2, please readjust the leverage ratio + '33065': ExchangeError, // Leverage ratio exceeds maximum leverage ratio, please readjust leverage ratio + // account + '21009': ExchangeError, // Funds cannot be transferred out within 30 minutes after swap settlement(Funds cannot be transferred out within 30 minutes after swap settlement) + '34001': PermissionDenied, // { "code": 34001, "message": "withdrawal suspended" } + '34002': InvalidAddress, // { "code": 34002, "message": "please add a withdrawal address" } + '34003': ExchangeError, // { "code": 34003, "message": "sorry, this token cannot be withdrawn to xx at the moment" } + '34004': ExchangeError, // { "code": 34004, "message": "withdrawal fee is smaller than minimum limit" } + '34005': ExchangeError, // { "code": 34005, "message": "withdrawal fee exceeds the maximum limit" } + '34006': ExchangeError, // { "code": 34006, "message": "withdrawal amount is lower than the minimum limit" } + '34007': ExchangeError, // { "code": 34007, "message": "withdrawal amount exceeds the maximum limit" } + '34008': InsufficientFunds, // { "code": 34008, "message": "insufficient balance" } + '34009': ExchangeError, // { "code": 34009, "message": "your withdrawal amount exceeds the daily limit" } + '34010': ExchangeError, // { "code": 34010, "message": "transfer amount must be larger than 0" } + '34011': ExchangeError, // { "code": 34011, "message": "conditions not met" } + '34012': ExchangeError, // { "code": 34012, "message": "the minimum withdrawal amount for NEO is 1, and the amount must be an integer" } + '34013': ExchangeError, // { "code": 34013, "message": "please transfer" } + '34014': ExchangeError, // { "code": 34014, "message": "transfer limited" } + '34015': ExchangeError, // { "code": 34015, "message": "subaccount does not exist" } + '34016': PermissionDenied, // { "code": 34016, "message": "transfer suspended" } + '34017': AccountSuspended, // { "code": 34017, "message": "account suspended" } + '34018': AuthenticationError, // { "code": 34018, "message": "incorrect trades password" } + '34019': PermissionDenied, // { "code": 34019, "message": "please bind your email before withdrawal" } + '34020': PermissionDenied, // { "code": 34020, "message": "please bind your funds password before withdrawal" } + '34021': InvalidAddress, // { "code": 34021, "message": "Not verified address" } + '34022': ExchangeError, // { "code": 34022, "message": "Withdrawals are not available for sub accounts" } + '34023': PermissionDenied, // { "code": 34023, "message": "Please enable futures trading before transferring your funds" } + '34026': ExchangeError, // transfer too frequently(transfer too frequently) + '34036': ExchangeError, // Parameter is incorrect, please refer to API documentation + '34037': ExchangeError, // Get the sub-account balance interface, account type is not supported + '34038': ExchangeError, // Since your C2C transaction is unusual, you are restricted from fund transfer. Please contact our customer support to cancel the restriction + '34039': ExchangeError, // You are now restricted from transferring out your funds due to abnormal trades on C2C Market. Please transfer your fund on our website or app instead to verify your identity + // swap + '35001': ExchangeError, // { "code": 35001, "message": "Contract does not exist" } + '35002': ExchangeError, // { "code": 35002, "message": "Contract settling" } + '35003': ExchangeError, // { "code": 35003, "message": "Contract paused" } + '35004': ExchangeError, // { "code": 35004, "message": "Contract pending settlement" } + '35005': AuthenticationError, // { "code": 35005, "message": "User does not exist" } + '35008': InvalidOrder, // { "code": 35008, "message": "Risk ratio too high" } + '35010': InvalidOrder, // { "code": 35010, "message": "Position closing too large" } + '35012': InvalidOrder, // { "code": 35012, "message": "Incorrect order size" } + '35014': InvalidOrder, // { "code": 35014, "message": "Order price is not within limit" } + '35015': InvalidOrder, // { "code": 35015, "message": "Invalid leverage level" } + '35017': ExchangeError, // { "code": 35017, "message": "Open orders exist" } + '35019': InvalidOrder, // { "code": 35019, "message": "Order size too large" } + '35020': InvalidOrder, // { "code": 35020, "message": "Order price too high" } + '35021': InvalidOrder, // { "code": 35021, "message": "Order size exceeded current tier limit" } + '35022': ExchangeError, // { "code": 35022, "message": "Contract status error" } + '35024': ExchangeError, // { "code": 35024, "message": "Contract not initialized" } + '35025': InsufficientFunds, // { "code": 35025, "message": "No account balance" } + '35026': ExchangeError, // { "code": 35026, "message": "Contract settings not initialized" } + '35029': OrderNotFound, // { "code": 35029, "message": "Order does not exist" } + '35030': InvalidOrder, // { "code": 35030, "message": "Order size too large" } + '35031': InvalidOrder, // { "code": 35031, "message": "Cancel order size too large" } + '35032': ExchangeError, // { "code": 35032, "message": "Invalid user status" } + '35037': ExchangeError, // No last traded price in cache + '35039': ExchangeError, // { "code": 35039, "message": "Open order quantity exceeds limit" } + '35040': InvalidOrder, // {"error_message":"Invalid order type","result":"true","error_code":"35040","order_id":"-1"} + '35044': ExchangeError, // { "code": 35044, "message": "Invalid order status" } + '35046': InsufficientFunds, // { "code": 35046, "message": "Negative account balance" } + '35047': InsufficientFunds, // { "code": 35047, "message": "Insufficient account balance" } + '35048': ExchangeError, // { "code": 35048, "message": "User contract is frozen and liquidating" } + '35049': InvalidOrder, // { "code": 35049, "message": "Invalid order type" } + '35050': InvalidOrder, // { "code": 35050, "message": "Position settings are blank" } + '35052': InsufficientFunds, // { "code": 35052, "message": "Insufficient cross margin" } + '35053': ExchangeError, // { "code": 35053, "message": "Account risk too high" } + '35055': InsufficientFunds, // { "code": 35055, "message": "Insufficient account balance" } + '35057': ExchangeError, // { "code": 35057, "message": "No last traded price" } + '35058': ExchangeError, // { "code": 35058, "message": "No limit" } + '35059': BadRequest, // { "code": 35059, "message": "client_oid or order_id is required" } + '35060': BadRequest, // { "code": 35060, "message": "Only fill in either parameter client_oid or order_id" } + '35061': BadRequest, // { "code": 35061, "message": "Invalid instrument_id" } + '35062': InvalidOrder, // { "code": 35062, "message": "Invalid match_price" } + '35063': InvalidOrder, // { "code": 35063, "message": "Invalid order_size" } + '35064': InvalidOrder, // { "code": 35064, "message": "Invalid client_oid" } + '35066': InvalidOrder, // Order interval error + '35067': InvalidOrder, // Time-weighted order ratio error + '35068': InvalidOrder, // Time-weighted order range error + '35069': InvalidOrder, // Time-weighted single transaction limit error + '35070': InvalidOrder, // Algo order type error + '35071': InvalidOrder, // Order total must be larger than single order limit + '35072': InvalidOrder, // Maximum 6 unfulfilled time-weighted orders can be held at the same time + '35073': InvalidOrder, // Order price is 0. Market-close-all not available + '35074': InvalidOrder, // Iceberg order single transaction average error + '35075': InvalidOrder, // Failed to cancel order + '35076': InvalidOrder, // LTC 20x leverage. Not allowed to open position + '35077': InvalidOrder, // Maximum 6 unfulfilled iceberg orders can be held at the same time + '35078': InvalidOrder, // Order amount exceeded 100,000 + '35079': InvalidOrder, // Iceberg order price variance error + '35080': InvalidOrder, // Callback rate error + '35081': InvalidOrder, // Maximum 10 unfulfilled trail orders can be held at the same time + '35082': InvalidOrder, // Trail order callback rate error + '35083': InvalidOrder, // Each user can only hold a maximum of 10 unfulfilled stop-limit orders at the same time + '35084': InvalidOrder, // Order amount exceeded 1 million + '35085': InvalidOrder, // Order amount is not in the correct range + '35086': InvalidOrder, // Price exceeds 100 thousand + '35087': InvalidOrder, // Price exceeds 100 thousand + '35088': InvalidOrder, // Average amount error + '35089': InvalidOrder, // Price exceeds 100 thousand + '35090': ExchangeError, // No stop-limit orders available for cancelation + '35091': ExchangeError, // No trail orders available for cancellation + '35092': ExchangeError, // No iceberg orders available for cancellation + '35093': ExchangeError, // No trail orders available for cancellation + '35094': ExchangeError, // Stop-limit order last traded price error + '35095': BadRequest, // Instrument_id error + '35096': ExchangeError, // Algo order status error + '35097': ExchangeError, // Order status and order ID cannot exist at the same time + '35098': ExchangeError, // An order status or order ID must exist + '35099': ExchangeError, // Algo order ID error + // option + '36001': BadRequest, // Invalid underlying index. + '36002': BadRequest, // Instrument does not exist. + '36005': ExchangeError, // Instrument status is invalid. + '36101': AuthenticationError, // Account does not exist. + '36102': PermissionDenied, // Account status is invalid. + '36103': PermissionDenied, // Account is suspended due to ongoing liquidation. + '36104': PermissionDenied, // Account is not enabled for options trading. + '36105': PermissionDenied, // Please enable the account for option contract. + '36106': PermissionDenied, // Funds cannot be transferred in or out, as account is suspended. + '36107': PermissionDenied, // Funds cannot be transferred out within 30 minutes after option exercising or settlement. + '36108': InsufficientFunds, // Funds cannot be transferred in or out, as equity of the account is less than zero. + '36109': PermissionDenied, // Funds cannot be transferred in or out during option exercising or settlement. + '36201': PermissionDenied, // New order function is blocked. + '36202': PermissionDenied, // Account does not have permission to short option. + '36203': InvalidOrder, // Invalid format for client_oid. + '36204': ExchangeError, // Invalid format for request_id. + '36205': BadRequest, // Instrument id does not match underlying index. + '36206': BadRequest, // Order_id and client_oid can not be used at the same time. + '36207': InvalidOrder, // Either order price or fartouch price must be present. + '36208': InvalidOrder, // Either order price or size must be present. + '36209': InvalidOrder, // Either order_id or client_oid must be present. + '36210': InvalidOrder, // Either order_ids or client_oids must be present. + '36211': InvalidOrder, // Exceeding max batch size for order submission. + '36212': InvalidOrder, // Exceeding max batch size for oder cancellation. + '36213': InvalidOrder, // Exceeding max batch size for order amendment. + '36214': ExchangeError, // Instrument does not have valid bid/ask quote. + '36216': OrderNotFound, // Order does not exist. + '36217': InvalidOrder, // Order submission failed. + '36218': InvalidOrder, // Order cancellation failed. + '36219': InvalidOrder, // Order amendment failed. + '36220': InvalidOrder, // Order is pending cancel. + '36221': InvalidOrder, // Order qty is not valid multiple of lot size. + '36222': InvalidOrder, // Order price is breaching highest buy limit. + '36223': InvalidOrder, // Order price is breaching lowest sell limit. + '36224': InvalidOrder, // Exceeding max order size. + '36225': InvalidOrder, // Exceeding max open order count for instrument. + '36226': InvalidOrder, // Exceeding max open order count for underlying. + '36227': InvalidOrder, // Exceeding max open size across all orders for underlying + '36228': InvalidOrder, // Exceeding max available qty for instrument. + '36229': InvalidOrder, // Exceeding max available qty for underlying. + '36230': InvalidOrder, // Exceeding max position limit for underlying. + }, + 'broad': { + }, + }, + 'precisionMode': TICK_SIZE, + 'options': { + 'createMarketBuyOrderRequiresPrice': true, + 'fetchMarkets': [ 'spot', 'futures', 'swap', 'option' ], + 'defaultType': 'spot', // 'account', 'spot', 'margin', 'futures', 'swap', 'option' + 'auth': { + 'time': 'public', + 'currencies': 'private', + 'instruments': 'public', + 'rate': 'public', + '{instrument_id}/constituents': 'public', }, }, 'commonCurrencies': { @@ -62,4 +653,2557 @@ module.exports = class okex extends okcoinusd { }, }); } + + async fetchTime (params = {}) { + const response = await this.generalGetTime (params); + // + // { + // "iso": "2015-01-07T23:47:25.201Z", + // "epoch": 1420674445.201 + // } + // + return this.parse8601 (this.safeString (response, 'iso')); + } + + async fetchMarkets (params = {}) { + const types = this.safeValue (this.options, 'fetchMarkets'); + let result = []; + for (let i = 0; i < types.length; i++) { + const markets = await this.fetchMarketsByType (types[i], params); + result = this.arrayConcat (result, markets); + } + return result; + } + + parseMarkets (markets) { + const result = []; + for (let i = 0; i < markets.length; i++) { + result.push (this.parseMarket (markets[i])); + } + return result; + } + + parseMarket (market) { + // + // spot markets + // + // { + // base_currency: "EOS", + // instrument_id: "EOS-OKB", + // min_size: "0.01", + // quote_currency: "OKB", + // size_increment: "0.000001", + // tick_size: "0.0001" + // } + // + // futures markets + // + // { + // instrument_id: "XRP-USD-200320", + // underlying_index: "XRP", + // quote_currency: "USD", + // tick_size: "0.0001", + // contract_val: "10", + // listing: "2020-03-06", + // delivery: "2020-03-20", + // trade_increment: "1", + // alias: "this_week", + // underlying: "XRP-USD", + // base_currency: "XRP", + // settlement_currency: "XRP", + // is_inverse: "true", + // contract_val_currency: "USD", + // } + // + // swap markets + // + // { + // instrument_id: "BSV-USD-SWAP", + // underlying_index: "BSV", + // quote_currency: "USD", + // coin: "BSV", + // contract_val: "10", + // listing: "2018-12-21T07:53:47.000Z", + // delivery: "2020-03-14T08:00:00.000Z", + // size_increment: "1", + // tick_size: "0.01", + // base_currency: "BSV", + // underlying: "BSV-USD", + // settlement_currency: "BSV", + // is_inverse: "true", + // contract_val_currency: "USD" + // } + // + // options markets + // + // { + // instrument_id: 'BTC-USD-200327-4000-C', + // underlying: 'BTC-USD', + // settlement_currency: 'BTC', + // contract_val: '0.1000', + // option_type: 'C', + // strike: '4000', + // tick_size: '0.0005', + // lot_size: '1.0000', + // listing: '2019-12-25T08:30:36.302Z', + // delivery: '2020-03-27T08:00:00.000Z', + // state: '2', + // trading_start_time: '2019-12-25T08:30:36.302Z', + // timestamp: '2020-03-13T08:05:09.456Z', + // } + // + const id = this.safeString (market, 'instrument_id'); + let marketType = 'spot'; + let spot = true; + let future = false; + let swap = false; + let option = false; + let baseId = this.safeString (market, 'base_currency'); + let quoteId = this.safeString (market, 'quote_currency'); + const contractVal = this.safeFloat (market, 'contract_val'); + if (contractVal !== undefined) { + if ('option_type' in market) { + marketType = 'option'; + spot = false; + option = true; + const underlying = this.safeString (market, 'underlying'); + const parts = underlying.split ('-'); + baseId = this.safeString (parts, 0); + quoteId = this.safeString (parts, 1); + } else { + marketType = 'swap'; + spot = false; + swap = true; + const futuresAlias = this.safeString (market, 'alias'); + if (futuresAlias !== undefined) { + swap = false; + future = true; + marketType = 'futures'; + baseId = this.safeString (market, 'underlying_index'); + } + } + } + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + const symbol = spot ? (base + '/' + quote) : id; + const lotSize = this.safeFloat2 (market, 'lot_size', 'trade_increment'); + const precision = { + 'amount': this.safeFloat (market, 'size_increment', lotSize), + 'price': this.safeFloat (market, 'tick_size'), + }; + const minAmount = this.safeFloat2 (market, 'min_size', 'base_min_size'); + let minPrice = this.safeFloat (market, 'tick_size'); + if (precision['price'] !== undefined) { + minPrice = Math.pow (10, -precision['price']); + } + let minCost = undefined; + if (minAmount !== undefined && minPrice !== undefined) { + minCost = minAmount * minPrice; + } + const active = true; + const fees = this.safeValue2 (this.fees, marketType, 'trading', {}); + return this.extend (fees, { + 'id': id, + 'symbol': symbol, + 'base': base, + 'quote': quote, + 'baseId': baseId, + 'quoteId': quoteId, + 'info': market, + 'type': marketType, + 'spot': spot, + 'futures': future, + 'swap': swap, + 'option': option, + 'active': active, + 'precision': precision, + 'limits': { + 'amount': { + 'min': minAmount, + 'max': undefined, + }, + 'price': { + 'min': minPrice, + 'max': undefined, + }, + 'cost': { + 'min': minCost, + 'max': undefined, + }, + }, + }); + } + + async fetchMarketsByType (type, params = {}) { + if (type === 'option') { + const underlying = await this.optionGetUnderlying (params); + let result = []; + for (let i = 0; i < underlying.length; i++) { + const response = await this.optionGetInstrumentsUnderlying ({ + 'underlying': underlying[i], + }); + // + // options markets + // + // [ + // { + // instrument_id: 'BTC-USD-200327-4000-C', + // underlying: 'BTC-USD', + // settlement_currency: 'BTC', + // contract_val: '0.1000', + // option_type: 'C', + // strike: '4000', + // tick_size: '0.0005', + // lot_size: '1.0000', + // listing: '2019-12-25T08:30:36.302Z', + // delivery: '2020-03-27T08:00:00.000Z', + // state: '2', + // trading_start_time: '2019-12-25T08:30:36.302Z', + // timestamp: '2020-03-13T08:05:09.456Z', + // }, + // ] + // + result = this.arrayConcat (result, response); + } + return this.parseMarkets (result); + } else if ((type === 'spot') || (type === 'futures') || (type === 'swap')) { + const method = type + 'GetInstruments'; + const response = await this[method] (params); + // + // spot markets + // + // [ + // { + // base_currency: "EOS", + // instrument_id: "EOS-OKB", + // min_size: "0.01", + // quote_currency: "OKB", + // size_increment: "0.000001", + // tick_size: "0.0001" + // } + // ] + // + // futures markets + // + // [ + // { + // instrument_id: "XRP-USD-200320", + // underlying_index: "XRP", + // quote_currency: "USD", + // tick_size: "0.0001", + // contract_val: "10", + // listing: "2020-03-06", + // delivery: "2020-03-20", + // trade_increment: "1", + // alias: "this_week", + // underlying: "XRP-USD", + // base_currency: "XRP", + // settlement_currency: "XRP", + // is_inverse: "true", + // contract_val_currency: "USD", + // } + // ] + // + // swap markets + // + // [ + // { + // instrument_id: "BSV-USD-SWAP", + // underlying_index: "BSV", + // quote_currency: "USD", + // coin: "BSV", + // contract_val: "10", + // listing: "2018-12-21T07:53:47.000Z", + // delivery: "2020-03-14T08:00:00.000Z", + // size_increment: "1", + // tick_size: "0.01", + // base_currency: "BSV", + // underlying: "BSV-USD", + // settlement_currency: "BSV", + // is_inverse: "true", + // contract_val_currency: "USD" + // } + // ] + // + return this.parseMarkets (response); + } else { + throw new NotSupported (this.id + ' fetchMarketsByType does not support market type ' + type); + } + } + + async fetchCurrencies (params = {}) { + // has['fetchCurrencies'] is currently set to false + // despite that their docs say these endpoints are public: + // https://www.okex.com/api/account/v3/withdrawal/fee + // https://www.okex.com/api/account/v3/currencies + // it will still reply with { "code":30001, "message": "OK-ACCESS-KEY header is required" } + // if you attempt to access it without authentication + const response = await this.accountGetCurrencies (params); + // + // [ + // { + // name: '', + // currency: 'BTC', + // can_withdraw: '1', + // can_deposit: '1', + // min_withdrawal: '0.0100000000000000' + // }, + // ] + // + const result = {}; + for (let i = 0; i < response.length; i++) { + const currency = response[i]; + const id = this.safeString (currency, 'currency'); + const code = this.safeCurrencyCode (id); + const precision = 8; // default precision, todo: fix "magic constants" + const name = this.safeString (currency, 'name'); + const canDeposit = this.safeInteger (currency, 'can_deposit'); + const canWithdraw = this.safeInteger (currency, 'can_withdraw'); + const active = canDeposit && canWithdraw; + result[code] = { + 'id': id, + 'code': code, + 'info': currency, + 'type': undefined, + 'name': name, + 'active': active, + 'fee': undefined, // todo: redesign + 'precision': precision, + 'limits': { + 'amount': { 'min': undefined, 'max': undefined }, + 'price': { 'min': undefined, 'max': undefined }, + 'cost': { 'min': undefined, 'max': undefined }, + 'withdraw': { + 'min': this.safeFloat (currency, 'min_withdrawal'), + 'max': undefined, + }, + }, + }; + } + return result; + } + + async fetchOrderBook (symbol, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + let method = market['type'] + 'GetInstrumentsInstrumentId'; + method += (market['type'] === 'swap') ? 'Depth' : 'Book'; + const request = { + 'instrument_id': market['id'], + }; + if (limit !== undefined) { + request['size'] = limit; // max 200 + } + const response = await this[method] (this.extend (request, params)); + // + // { asks: [ ["0.02685268", "0.242571", "1"], + // ["0.02685493", "0.164085", "1"], + // ... + // ["0.02779", "1.039", "1"], + // ["0.027813", "0.0876", "1"] ], + // bids: [ ["0.02684052", "10.371849", "1"], + // ["0.02684051", "3.707", "4"], + // ... + // ["0.02634963", "0.132934", "1"], + // ["0.02634962", "0.264838", "2"] ], + // timestamp: "2018-12-17T20:24:16.159Z" } + // + const timestamp = this.parse8601 (this.safeString (response, 'timestamp')); + return this.parseOrderBook (response, timestamp); + } + + parseTicker (ticker, market = undefined) { + // + // { best_ask: "0.02665472", + // best_bid: "0.02665221", + // instrument_id: "ETH-BTC", + // product_id: "ETH-BTC", + // last: "0.02665472", + // ask: "0.02665472", // missing in the docs + // bid: "0.02665221", // not mentioned in the docs + // open_24h: "0.02645482", + // high_24h: "0.02714633", + // low_24h: "0.02614109", + // base_volume_24h: "572298.901923", + // timestamp: "2018-12-17T21:20:07.856Z", + // quote_volume_24h: "15094.86831261" } + // + const timestamp = this.parse8601 (this.safeString (ticker, 'timestamp')); + let symbol = undefined; + const marketId = this.safeString (ticker, 'instrument_id'); + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else if (marketId !== undefined) { + const parts = marketId.split ('-'); + const numParts = parts.length; + if (numParts === 2) { + const [ baseId, quoteId ] = parts; + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } else { + symbol = marketId; + } + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + } + const last = this.safeFloat (ticker, 'last'); + const open = this.safeFloat (ticker, 'open_24h'); + return { + 'symbol': symbol, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'high': this.safeFloat (ticker, 'high_24h'), + 'low': this.safeFloat (ticker, 'low_24h'), + 'bid': this.safeFloat (ticker, 'best_bid'), + 'bidVolume': this.safeFloat (ticker, 'best_bid_size'), + 'ask': this.safeFloat (ticker, 'best_ask'), + 'askVolume': this.safeFloat (ticker, 'best_ask_size'), + 'vwap': undefined, + 'open': open, + 'close': last, + 'last': last, + 'previousClose': undefined, + 'change': undefined, + 'percentage': undefined, + 'average': undefined, + 'baseVolume': this.safeFloat (ticker, 'base_volume_24h'), + 'quoteVolume': this.safeFloat (ticker, 'quote_volume_24h'), + 'info': ticker, + }; + } + + async fetchTicker (symbol, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const method = market['type'] + 'GetInstrumentsInstrumentIdTicker'; + const request = { + 'instrument_id': market['id'], + }; + const response = await this[method] (this.extend (request, params)); + // + // { best_ask: "0.02665472", + // best_bid: "0.02665221", + // instrument_id: "ETH-BTC", + // product_id: "ETH-BTC", + // last: "0.02665472", + // ask: "0.02665472", + // bid: "0.02665221", + // open_24h: "0.02645482", + // high_24h: "0.02714633", + // low_24h: "0.02614109", + // base_volume_24h: "572298.901923", + // timestamp: "2018-12-17T21:20:07.856Z", + // quote_volume_24h: "15094.86831261" } + // + return this.parseTicker (response); + } + + async fetchTickersByType (type, symbols = undefined, params = {}) { + await this.loadMarkets (); + const method = type + 'GetInstrumentsTicker'; + const response = await this[method] (params); + const result = {}; + for (let i = 0; i < response.length; i++) { + const ticker = this.parseTicker (response[i]); + const symbol = ticker['symbol']; + result[symbol] = ticker; + } + return result; + } + + async fetchTickers (symbols = undefined, params = {}) { + const defaultType = this.safeString2 (this.options, 'fetchTickers', 'defaultType'); + const type = this.safeString (params, 'type', defaultType); + return await this.fetchTickersByType (type, symbols, this.omit (params, 'type')); + } + + parseTrade (trade, market = undefined) { + // + // fetchTrades (public) + // + // spot trades + // + // { + // time: "2018-12-17T23:31:08.268Z", + // timestamp: "2018-12-17T23:31:08.268Z", + // trade_id: "409687906", + // price: "0.02677805", + // size: "0.923467", + // side: "sell" + // } + // + // futures trades, swap trades + // + // { + // trade_id: "1989230840021013", + // side: "buy", + // price: "92.42", + // qty: "184", // missing in swap markets + // size: "5", // missing in futures markets + // timestamp: "2018-12-17T23:26:04.613Z" + // } + // + // fetchOrderTrades (private) + // + // spot trades, margin trades + // + // { + // "created_at":"2019-03-15T02:52:56.000Z", + // "exec_type":"T", // whether the order is taker or maker + // "fee":"0.00000082", + // "instrument_id":"BTC-USDT", + // "ledger_id":"3963052721", + // "liquidity":"T", // whether the order is taker or maker + // "order_id":"2482659399697408", + // "price":"3888.6", + // "product_id":"BTC-USDT", + // "side":"buy", + // "size":"0.00055306", + // "timestamp":"2019-03-15T02:52:56.000Z" + // }, + // + // futures trades, swap trades + // + // { + // "trade_id":"197429674631450625", + // "instrument_id":"EOS-USD-SWAP", + // "order_id":"6a-7-54d663a28-0", + // "price":"3.633", + // "order_qty":"1.0000", + // "fee":"-0.000551", + // "created_at":"2019-03-21T04:41:58.0Z", // missing in swap trades + // "timestamp":"2019-03-25T05:56:31.287Z", // missing in futures trades + // "exec_type":"M", // whether the order is taker or maker + // "side":"short", // "buy" in futures trades + // } + // + let symbol = undefined; + const marketId = this.safeString (trade, 'instrument_id'); + let base = undefined; + let quote = undefined; + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + base = market['base']; + quote = market['quote']; + } else if (marketId !== undefined) { + const parts = marketId.split ('-'); + const numParts = parts.length; + if (numParts === 2) { + const [ baseId, quoteId ] = parts; + base = this.safeCurrencyCode (baseId); + quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } else { + symbol = marketId; + } + } + if ((symbol === undefined) && (market !== undefined)) { + symbol = market['symbol']; + base = market['base']; + quote = market['quote']; + } + const timestamp = this.parse8601 (this.safeString2 (trade, 'timestamp', 'created_at')); + const price = this.safeFloat (trade, 'price'); + let amount = this.safeFloat2 (trade, 'size', 'qty'); + amount = this.safeFloat (trade, 'order_qty', amount); + let takerOrMaker = this.safeString2 (trade, 'exec_type', 'liquidity'); + if (takerOrMaker === 'M') { + takerOrMaker = 'maker'; + } else if (takerOrMaker === 'T') { + takerOrMaker = 'taker'; + } + const side = this.safeString (trade, 'side'); + let cost = undefined; + if (amount !== undefined) { + if (price !== undefined) { + cost = amount * price; + } + } + const feeCost = this.safeFloat (trade, 'fee'); + let fee = undefined; + if (feeCost !== undefined) { + const feeCurrency = (side === 'buy') ? base : quote; + fee = { + // fee is either a positive number (invitation rebate) + // or a negative number (transaction fee deduction) + // therefore we need to invert the fee + // more about it https://github.com/ccxt/ccxt/issues/5909 + 'cost': -feeCost, + 'currency': feeCurrency, + }; + } + const orderId = this.safeString (trade, 'order_id'); + return { + 'info': trade, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'symbol': symbol, + 'id': this.safeString2 (trade, 'trade_id', 'ledger_id'), + 'order': orderId, + 'type': undefined, + 'takerOrMaker': takerOrMaker, + 'side': side, + 'price': price, + 'amount': amount, + 'cost': cost, + 'fee': fee, + }; + } + + async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const method = market['type'] + 'GetInstrumentsInstrumentIdTrades'; + if ((limit === undefined) || (limit > 100)) { + limit = 100; // maximum = default = 100 + } + const request = { + 'instrument_id': market['id'], + 'limit': limit, + // from: 'id', + // to: 'id', + }; + const response = await this[method] (this.extend (request, params)); + // + // spot markets + // + // [ + // { + // time: "2018-12-17T23:31:08.268Z", + // timestamp: "2018-12-17T23:31:08.268Z", + // trade_id: "409687906", + // price: "0.02677805", + // size: "0.923467", + // side: "sell" + // } + // ] + // + // futures markets, swap markets + // + // [ + // { + // trade_id: "1989230840021013", + // side: "buy", + // price: "92.42", + // qty: "184", // missing in swap markets + // size: "5", // missing in futures markets + // timestamp: "2018-12-17T23:26:04.613Z" + // } + // ] + // + return this.parseTrades (response, market, since, limit); + } + + parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) { + // + // spot markets + // + // { + // close: "0.02684545", + // high: "0.02685084", + // low: "0.02683312", + // open: "0.02683894", + // time: "2018-12-17T20:28:00.000Z", + // volume: "101.457222" + // } + // + // futures markets + // + // [ + // 1545072720000, + // 0.3159, + // 0.3161, + // 0.3144, + // 0.3149, + // 22886, + // 725179.26172331, + // ] + // + if (Array.isArray (ohlcv)) { + const numElements = ohlcv.length; + const volumeIndex = (numElements > 6) ? 6 : 5; + let timestamp = ohlcv[0]; + if (typeof timestamp === 'string') { + timestamp = this.parse8601 (timestamp); + } + return [ + timestamp, // timestamp + parseFloat (ohlcv[1]), // Open + parseFloat (ohlcv[2]), // High + parseFloat (ohlcv[3]), // Low + parseFloat (ohlcv[4]), // Close + // parseFloat (ohlcv[5]), // Quote Volume + // parseFloat (ohlcv[6]), // Base Volume + parseFloat (ohlcv[volumeIndex]), // Volume, okex will return base volume in the 7th element for future markets + ]; + } else { + return [ + this.parse8601 (this.safeString (ohlcv, 'time')), + this.safeFloat (ohlcv, 'open'), // Open + this.safeFloat (ohlcv, 'high'), // High + this.safeFloat (ohlcv, 'low'), // Low + this.safeFloat (ohlcv, 'close'), // Close + this.safeFloat (ohlcv, 'volume'), // Base Volume + ]; + } + } + + async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + const method = market['type'] + 'GetInstrumentsInstrumentIdCandles'; + const request = { + 'instrument_id': market['id'], + 'granularity': this.timeframes[timeframe], + }; + if (since !== undefined) { + request['start'] = this.iso8601 (since); + } + const response = await this[method] (this.extend (request, params)); + // + // spot markets + // + // [ { close: "0.02683401", + // high: "0.02683401", + // low: "0.02683401", + // open: "0.02683401", + // time: "2018-12-17T23:47:00.000Z", + // volume: "0" }, + // ... + // { close: "0.02684545", + // high: "0.02685084", + // low: "0.02683312", + // open: "0.02683894", + // time: "2018-12-17T20:28:00.000Z", + // volume: "101.457222" } ] + // + // futures + // + // [ [ 1545090660000, + // 0.3171, + // 0.3174, + // 0.3171, + // 0.3173, + // 1648, + // 51930.38579450868 ], + // ... + // [ 1545072720000, + // 0.3159, + // 0.3161, + // 0.3144, + // 0.3149, + // 22886, + // 725179.26172331 ] ] + // + return this.parseOHLCVs (response, market, timeframe, since, limit); + } + + parseAccountBalance (response) { + // + // account + // + // [ + // { + // balance: 0, + // available: 0, + // currency: "BTC", + // hold: 0 + // }, + // { + // balance: 0, + // available: 0, + // currency: "ETH", + // hold: 0 + // } + // ] + // + // spot + // + // [ + // { + // frozen: "0", + // hold: "0", + // id: "2149632", + // currency: "BTC", + // balance: "0.0000000497717339", + // available: "0.0000000497717339", + // holds: "0" + // }, + // { + // frozen: "0", + // hold: "0", + // id: "2149632", + // currency: "ICN", + // balance: "0.00000000925", + // available: "0.00000000925", + // holds: "0" + // } + // ] + // + const result = { 'info': response }; + for (let i = 0; i < response.length; i++) { + const balance = response[i]; + const currencyId = this.safeString (balance, 'currency'); + const code = this.safeCurrencyCode (currencyId); + const account = this.account (); + account['total'] = this.safeFloat (balance, 'balance'); + account['used'] = this.safeFloat (balance, 'hold'); + account['free'] = this.safeFloat (balance, 'available'); + result[code] = account; + } + return this.parseBalance (result); + } + + parseMarginBalance (response) { + // + // [ + // { + // "currency:BTC": { + // "available":"0", + // "balance":"0", + // "borrowed":"0", + // "can_withdraw":"0", + // "frozen":"0", + // "hold":"0", + // "holds":"0", + // "lending_fee":"0" + // }, + // "currency:USDT": { + // "available":"100", + // "balance":"100", + // "borrowed":"0", + // "can_withdraw":"100", + // "frozen":"0", + // "hold":"0", + // "holds":"0", + // "lending_fee":"0" + // }, + // "instrument_id":"BTC-USDT", + // "liquidation_price":"0", + // "product_id":"BTC-USDT", + // "risk_rate":"" + // }, + // ] + // + const result = { 'info': response }; + for (let i = 0; i < response.length; i++) { + const balance = response[i]; + const marketId = this.safeString (balance, 'instrument_id'); + const market = this.safeValue (this.markets_by_id, marketId); + let symbol = undefined; + if (market === undefined) { + const [ baseId, quoteId ] = marketId.split ('-'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + symbol = base + '/' + quote; + } else { + symbol = market['symbol']; + } + const omittedBalance = this.omit (balance, [ + 'instrument_id', + 'liquidation_price', + 'product_id', + 'risk_rate', + 'margin_ratio', + 'maint_margin_ratio', + 'tiers', + ]); + const keys = Object.keys (omittedBalance); + const accounts = {}; + for (let k = 0; k < keys.length; k++) { + const key = keys[k]; + const marketBalance = balance[key]; + if (key.indexOf (':') >= 0) { + const parts = key.split (':'); + const currencyId = parts[1]; + const code = this.safeCurrencyCode (currencyId); + const account = this.account (); + account['total'] = this.safeFloat (marketBalance, 'balance'); + account['used'] = this.safeFloat (marketBalance, 'hold'); + account['free'] = this.safeFloat (marketBalance, 'available'); + accounts[code] = account; + } else { + throw new NotSupported (this.id + ' margin balance response format has changed!'); + } + } + result[symbol] = this.parseBalance (accounts); + } + return result; + } + + parseFuturesBalance (response) { + // + // { + // "info":{ + // "eos":{ + // "auto_margin":"0", + // "contracts": [ + // { + // "available_qty":"40.37069445", + // "fixed_balance":"0", + // "instrument_id":"EOS-USD-190329", + // "margin_for_unfilled":"0", + // "margin_frozen":"0", + // "realized_pnl":"0", + // "unrealized_pnl":"0" + // }, + // { + // "available_qty":"40.37069445", + // "fixed_balance":"14.54895721", + // "instrument_id":"EOS-USD-190628", + // "margin_for_unfilled":"0", + // "margin_frozen":"10.64042157", + // "realized_pnl":"-3.90853564", + // "unrealized_pnl":"-0.259" + // }, + // ], + // "equity":"50.75220665", + // "margin_mode":"fixed", + // "total_avail_balance":"40.37069445" + // }, + // } + // } + // + // their root field name is "info", so our info will contain their info + const result = { 'info': response }; + const info = this.safeValue (response, 'info', {}); + const ids = Object.keys (info); + for (let i = 0; i < ids.length; i++) { + const id = ids[i]; + const code = this.safeCurrencyCode (id); + const balance = this.safeValue (info, id, {}); + const account = this.account (); + // it may be incorrect to use total, free and used for swap accounts + account['total'] = this.safeFloat (balance, 'equity'); + account['free'] = this.safeFloat (balance, 'total_avail_balance'); + result[code] = account; + } + return this.parseBalance (result); + } + + parseSwapBalance (response) { + // + // { + // "info": [ + // { + // "equity":"3.0139", + // "fixed_balance":"0.0000", + // "instrument_id":"EOS-USD-SWAP", + // "margin":"0.5523", + // "margin_frozen":"0.0000", + // "margin_mode":"crossed", + // "margin_ratio":"1.0913", + // "realized_pnl":"-0.0006", + // "timestamp":"2019-03-25T03:46:10.336Z", + // "total_avail_balance":"3.0000", + // "unrealized_pnl":"0.0145" + // } + // ] + // } + // + // their root field name is "info", so our info will contain their info + const result = { 'info': response }; + const info = this.safeValue (response, 'info', []); + for (let i = 0; i < info.length; i++) { + const balance = info[i]; + const marketId = this.safeString (balance, 'instrument_id'); + let symbol = marketId; + if (marketId in this.markets_by_id) { + symbol = this.markets_by_id[marketId]['symbol']; + } + const account = this.account (); + // it may be incorrect to use total, free and used for swap accounts + account['total'] = this.safeFloat (balance, 'equity'); + account['free'] = this.safeFloat (balance, 'total_avail_balance'); + result[symbol] = account; + } + return this.parseBalance (result); + } + + async fetchBalance (params = {}) { + const defaultType = this.safeString2 (this.options, 'fetchBalance', 'defaultType'); + const type = this.safeString (params, 'type', defaultType); + if (type === undefined) { + throw new ArgumentsRequired (this.id + " fetchBalance requires a type parameter (one of 'account', 'spot', 'margin', 'futures', 'swap')"); + } + await this.loadMarkets (); + const suffix = (type === 'account') ? 'Wallet' : 'Accounts'; + const method = type + 'Get' + suffix; + const query = this.omit (params, 'type'); + const response = await this[method] (query); + // + // account + // + // [ + // { + // balance: 0, + // available: 0, + // currency: "BTC", + // hold: 0 + // }, + // { + // balance: 0, + // available: 0, + // currency: "ETH", + // hold: 0 + // } + // ] + // + // spot + // + // [ + // { + // frozen: "0", + // hold: "0", + // id: "2149632", + // currency: "BTC", + // balance: "0.0000000497717339", + // available: "0.0000000497717339", + // holds: "0" + // }, + // { + // frozen: "0", + // hold: "0", + // id: "2149632", + // currency: "ICN", + // balance: "0.00000000925", + // available: "0.00000000925", + // holds: "0" + // } + // ] + // + // margin + // + // [ + // { + // "currency:BTC": { + // "available":"0", + // "balance":"0", + // "borrowed":"0", + // "can_withdraw":"0", + // "frozen":"0", + // "hold":"0", + // "holds":"0", + // "lending_fee":"0" + // }, + // "currency:USDT": { + // "available":"100", + // "balance":"100", + // "borrowed":"0", + // "can_withdraw":"100", + // "frozen":"0", + // "hold":"0", + // "holds":"0", + // "lending_fee":"0" + // }, + // "instrument_id":"BTC-USDT", + // "liquidation_price":"0", + // "product_id":"BTC-USDT", + // "risk_rate":"" + // }, + // ] + // + // futures + // + // { + // "info":{ + // "eos":{ + // "auto_margin":"0", + // "contracts": [ + // { + // "available_qty":"40.37069445", + // "fixed_balance":"0", + // "instrument_id":"EOS-USD-190329", + // "margin_for_unfilled":"0", + // "margin_frozen":"0", + // "realized_pnl":"0", + // "unrealized_pnl":"0" + // }, + // { + // "available_qty":"40.37069445", + // "fixed_balance":"14.54895721", + // "instrument_id":"EOS-USD-190628", + // "margin_for_unfilled":"0", + // "margin_frozen":"10.64042157", + // "realized_pnl":"-3.90853564", + // "unrealized_pnl":"-0.259" + // }, + // ], + // "equity":"50.75220665", + // "margin_mode":"fixed", + // "total_avail_balance":"40.37069445" + // }, + // } + // } + // + // swap + // + // { + // "info": [ + // { + // "equity":"3.0139", + // "fixed_balance":"0.0000", + // "instrument_id":"EOS-USD-SWAP", + // "margin":"0.5523", + // "margin_frozen":"0.0000", + // "margin_mode":"crossed", + // "margin_ratio":"1.0913", + // "realized_pnl":"-0.0006", + // "timestamp":"2019-03-25T03:46:10.336Z", + // "total_avail_balance":"3.0000", + // "unrealized_pnl":"0.0145" + // } + // ] + // } + // + return this.parseBalanceByType (type, response); + } + + parseBalanceByType (type, response) { + if ((type === 'account') || (type === 'spot')) { + return this.parseAccountBalance (response); + } else if (type === 'margin') { + return this.parseMarginBalance (response); + } else if (type === 'futures') { + return this.parseFuturesBalance (response); + } else if (type === 'swap') { + return this.parseSwapBalance (response); + } + throw new NotSupported (this.id + " fetchBalance does not support the '" + type + "' type (the type must be one of 'account', 'spot', 'margin', 'futures', 'swap')"); + } + + async createOrder (symbol, type, side, amount, price = undefined, params = {}) { + await this.loadMarkets (); + const market = this.market (symbol); + let request = { + 'instrument_id': market['id'], + // 'client_oid': 'abcdef1234567890', // [a-z0-9]{1,32} + // 'order_type': '0', // 0: Normal limit order (Unfilled and 0 represent normal limit order) 1: Post only 2: Fill Or Kill 3: Immediatel Or Cancel + }; + let method = undefined; + if (market['futures'] || market['swap']) { + const size = market['futures'] ? this.numberToString (amount) : this.amountToPrecision (symbol, amount); + request = this.extend (request, { + 'type': type, // 1:open long 2:open short 3:close long 4:close short for futures + 'size': size, + 'price': this.priceToPrecision (symbol, price), + // 'match_price': '0', // Order at best counter party price? (0:no 1:yes). The default is 0. If it is set as 1, the price parameter will be ignored. When posting orders at best bid price, order_type can only be 0 (regular order). + }); + if (market['futures']) { + request['leverage'] = '10'; // or '20' + } + method = market['type'] + 'PostOrder'; + } else { + const marginTrading = this.safeString (params, 'margin_trading', '1'); // 1 = spot, 2 = margin + request = this.extend (request, { + 'side': side, + 'type': type, // limit/market + 'margin_trading': marginTrading, // 1 = spot, 2 = margin + }); + if (type === 'limit') { + request['price'] = this.priceToPrecision (symbol, price); + request['size'] = this.amountToPrecision (symbol, amount); + } else if (type === 'market') { + // for market buy it requires the amount of quote currency to spend + if (side === 'buy') { + let notional = this.safeFloat (params, 'notional'); + const createMarketBuyOrderRequiresPrice = this.safeValue (this.options, 'createMarketBuyOrderRequiresPrice', true); + if (createMarketBuyOrderRequiresPrice) { + if (price !== undefined) { + if (notional === undefined) { + notional = amount * price; + } + } else if (notional === undefined) { + throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'amount' argument or in the 'notional' extra parameter (the exchange-specific behaviour)"); + } + } else { + notional = (notional === undefined) ? amount : notional; + } + const precision = market['precision']['price']; + request['notional'] = this.decimalToPrecision (notional, TRUNCATE, precision, this.precisionMode); + } else { + request['size'] = this.amountToPrecision (symbol, amount); + } + } + method = (marginTrading === '2') ? 'marginPostOrders' : 'spotPostOrders'; + } + const response = await this[method] (this.extend (request, params)); + // + // { + // "client_oid":"oktspot79", + // "error_code":"", + // "error_message":"", + // "order_id":"2510789768709120", + // "result":true + // } + // + const timestamp = this.milliseconds (); + const id = this.safeString (response, 'order_id'); + return { + 'info': response, + 'id': id, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': undefined, + 'status': undefined, + 'symbol': symbol, + 'type': type, + 'side': side, + 'price': price, + 'amount': amount, + 'filled': undefined, + 'remaining': undefined, + 'cost': undefined, + 'trades': undefined, + 'fee': undefined, + 'clientOrderId': undefined, + 'average': undefined, + }; + } + + async cancelOrder (id, symbol = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const type = market['type']; + let method = type + 'PostCancelOrder'; + const request = { + 'instrument_id': market['id'], + }; + if (market['futures'] || market['swap']) { + method += 'InstrumentId'; + } else { + method += 's'; + } + const clientOid = this.safeString (params, 'client_oid'); + if (clientOid !== undefined) { + method += 'ClientOid'; + request['client_oid'] = clientOid; + } else { + method += 'OrderId'; + request['order_id'] = id; + } + const query = this.omit (params, 'type'); + const response = await this[method] (this.extend (request, query)); + const result = ('result' in response) ? response : this.safeValue (response, market['id'], {}); + // + // spot, margin + // + // { + // "btc-usdt": [ + // { + // "result":true, + // "client_oid":"a123", + // "order_id": "2510832677225473" + // } + // ] + // } + // + // futures, swap + // + // { + // "result": true, + // "client_oid": "oktfuture10", // missing if requested by order_id + // "order_id": "2517535534836736", + // "instrument_id": "EOS-USD-190628" + // } + // + return this.parseOrder (result, market); + } + + parseOrderStatus (status) { + const statuses = { + '-2': 'failed', + '-1': 'canceled', + '0': 'open', + '1': 'open', + '2': 'closed', + '3': 'open', + '4': 'canceled', + }; + return this.safeString (statuses, status, status); + } + + parseOrderSide (side) { + const sides = { + '1': 'buy', // open long + '2': 'sell', // open short + '3': 'sell', // close long + '4': 'buy', // close short + }; + return this.safeString (sides, side, side); + } + + parseOrder (order, market = undefined) { + // + // createOrder + // + // { + // "client_oid":"oktspot79", + // "error_code":"", + // "error_message":"", + // "order_id":"2510789768709120", + // "result":true + // } + // + // cancelOrder + // + // { + // "result": true, + // "client_oid": "oktfuture10", // missing if requested by order_id + // "order_id": "2517535534836736", + // // instrument_id is missing for spot/margin orders + // // available in futures and swap orders only + // "instrument_id": "EOS-USD-190628", + // } + // + // fetchOrder, fetchOrdersByState, fetchOpenOrders, fetchClosedOrders + // + // // spot and margin orders + // + // { + // "client_oid":"oktspot76", + // "created_at":"2019-03-18T07:26:49.000Z", + // "filled_notional":"3.9734", + // "filled_size":"0.001", // filled_qty in futures and swap orders + // "funds":"", // this is most likely the same as notional + // "instrument_id":"BTC-USDT", + // "notional":"", + // "order_id":"2500723297813504", + // "order_type":"0", + // "price":"4013", + // "product_id":"BTC-USDT", // missing in futures and swap orders + // "side":"buy", + // "size":"0.001", + // "status":"filled", + // "state": "2", + // "timestamp":"2019-03-18T07:26:49.000Z", + // "type":"limit" + // } + // + // // futures and swap orders + // + // { + // "instrument_id":"EOS-USD-190628", + // "size":"10", + // "timestamp":"2019-03-20T10:04:55.000Z", + // "filled_qty":"10", // filled_size in spot and margin orders + // "fee":"-0.00841043", + // "order_id":"2512669605501952", + // "price":"3.668", + // "price_avg":"3.567", // missing in spot and margin orders + // "status":"2", + // "state": "2", + // "type":"4", + // "contract_val":"10", + // "leverage":"10", // missing in swap, spot and margin orders + // "client_oid":"", + // "pnl":"1.09510794", // missing in swap, spo and margin orders + // "order_type":"0" + // } + // + const id = this.safeString (order, 'order_id'); + const timestamp = this.parse8601 (this.safeString (order, 'timestamp')); + let side = this.safeString (order, 'side'); + let type = this.safeString (order, 'type'); + if ((side !== 'buy') && (side !== 'sell')) { + side = this.parseOrderSide (type); + } + if ((type !== 'limit') && (type !== 'market')) { + if ('pnl' in order) { + type = 'futures'; + } else { + type = 'swap'; + } + } + let symbol = undefined; + const marketId = this.safeString (order, 'instrument_id'); + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + symbol = market['symbol']; + } else { + symbol = marketId; + } + if (market !== undefined) { + if (symbol === undefined) { + symbol = market['symbol']; + } + } + let amount = this.safeFloat (order, 'size'); + const filled = this.safeFloat2 (order, 'filled_size', 'filled_qty'); + let remaining = undefined; + if (amount !== undefined) { + if (filled !== undefined) { + amount = Math.max (amount, filled); + remaining = Math.max (0, amount - filled); + } + } + if (type === 'market') { + remaining = 0; + } + let cost = this.safeFloat2 (order, 'filled_notional', 'funds'); + const price = this.safeFloat (order, 'price'); + let average = this.safeFloat (order, 'price_avg'); + if (cost === undefined) { + if (filled !== undefined && average !== undefined) { + cost = average * filled; + } + } else { + if ((average === undefined) && (filled !== undefined) && (filled > 0)) { + average = cost / filled; + } + } + const status = this.parseOrderStatus (this.safeString (order, 'state')); + const feeCost = this.safeFloat (order, 'fee'); + let fee = undefined; + if (feeCost !== undefined) { + const feeCurrency = undefined; + fee = { + 'cost': feeCost, + 'currency': feeCurrency, + }; + } + const clientOrderId = this.safeString (order, 'client_oid'); + return { + 'info': order, + 'id': id, + 'clientOrderId': clientOrderId, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': undefined, + 'symbol': symbol, + 'type': type, + 'side': side, + 'price': price, + 'average': average, + 'cost': cost, + 'amount': amount, + 'filled': filled, + 'remaining': remaining, + 'status': status, + 'fee': fee, + 'trades': undefined, + }; + } + + async fetchOrder (id, symbol = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const defaultType = this.safeString2 (this.options, 'fetchOrder', 'defaultType', market['type']); + const type = this.safeString (params, 'type', defaultType); + if (type === undefined) { + throw new ArgumentsRequired (this.id + " fetchOrder requires a type parameter (one of 'spot', 'margin', 'futures', 'swap')."); + } + const instrumentId = (market['futures'] || market['swap']) ? 'InstrumentId' : ''; + let method = type + 'GetOrders' + instrumentId; + const request = { + 'instrument_id': market['id'], + // 'client_oid': 'abcdef12345', // optional, [a-z0-9]{1,32} + // 'order_id': id, + }; + const clientOid = this.safeString (params, 'client_oid'); + if (clientOid !== undefined) { + method += 'ClientOid'; + request['client_oid'] = clientOid; + } else { + method += 'OrderId'; + request['order_id'] = id; + } + const query = this.omit (params, 'type'); + const response = await this[method] (this.extend (request, query)); + // + // spot, margin + // + // { + // "client_oid":"oktspot70", + // "created_at":"2019-03-15T02:52:56.000Z", + // "filled_notional":"3.8886", + // "filled_size":"0.001", + // "funds":"", + // "instrument_id":"BTC-USDT", + // "notional":"", + // "order_id":"2482659399697408", + // "order_type":"0", + // "price":"3927.3", + // "product_id":"BTC-USDT", + // "side":"buy", + // "size":"0.001", + // "status":"filled", + // "state": "2", + // "timestamp":"2019-03-15T02:52:56.000Z", + // "type":"limit" + // } + // + // futures, swap + // + // { + // "instrument_id":"EOS-USD-190628", + // "size":"10", + // "timestamp":"2019-03-20T02:46:38.000Z", + // "filled_qty":"10", + // "fee":"-0.0080819", + // "order_id":"2510946213248000", + // "price":"3.712", + // "price_avg":"3.712", + // "status":"2", + // "state": "2", + // "type":"2", + // "contract_val":"10", + // "leverage":"10", + // "client_oid":"", // missing in swap orders + // "pnl":"0", // missing in swap orders + // "order_type":"0" + // } + // + return this.parseOrder (response); + } + + async fetchOrdersByState (state, symbol = undefined, since = undefined, limit = undefined, params = {}) { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOrdersByState requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const type = market['type']; + const request = { + 'instrument_id': market['id'], + // '-2': failed, + // '-1': cancelled, + // '0': open , + // '1': partially filled, + // '2': fully filled, + // '3': submitting, + // '4': cancelling, + // '6': incomplete(open+partially filled), + // '7': complete(cancelled+fully filled), + 'state': state, + }; + let method = type + 'GetOrders'; + if (market['futures'] || market['swap']) { + method += 'InstrumentId'; + } + const query = this.omit (params, 'type'); + const response = await this[method] (this.extend (request, query)); + // + // spot, margin + // + // [ + // // in fact, this documented API response does not correspond + // // to their actual API response for spot markets + // // OKEX v3 API returns a plain array of orders (see below) + // [ + // { + // "client_oid":"oktspot76", + // "created_at":"2019-03-18T07:26:49.000Z", + // "filled_notional":"3.9734", + // "filled_size":"0.001", + // "funds":"", + // "instrument_id":"BTC-USDT", + // "notional":"", + // "order_id":"2500723297813504", + // "order_type":"0", + // "price":"4013", + // "product_id":"BTC-USDT", + // "side":"buy", + // "size":"0.001", + // "status":"filled", + // "state": "2", + // "timestamp":"2019-03-18T07:26:49.000Z", + // "type":"limit" + // }, + // ], + // { + // "before":"2500723297813504", + // "after":"2500650881647616" + // } + // ] + // + // futures, swap + // + // { + // "result":true, // missing in swap orders + // "order_info": [ + // { + // "instrument_id":"EOS-USD-190628", + // "size":"10", + // "timestamp":"2019-03-20T10:04:55.000Z", + // "filled_qty":"10", + // "fee":"-0.00841043", + // "order_id":"2512669605501952", + // "price":"3.668", + // "price_avg":"3.567", + // "status":"2", + // "state": "2", + // "type":"4", + // "contract_val":"10", + // "leverage":"10", // missing in swap orders + // "client_oid":"", + // "pnl":"1.09510794", // missing in swap orders + // "order_type":"0" + // }, + // ] + // } + // + let orders = undefined; + if (market['type'] === 'swap' || market['type'] === 'futures') { + orders = this.safeValue (response, 'order_info', []); + } else { + orders = response; + const responseLength = response.length; + if (responseLength < 1) { + return []; + } + // in fact, this documented API response does not correspond + // to their actual API response for spot markets + // OKEX v3 API returns a plain array of orders + if (responseLength > 1) { + const before = this.safeValue (response[1], 'before'); + if (before !== undefined) { + orders = response[0]; + } + } + } + return this.parseOrders (orders, market, since, limit); + } + + async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + // '-2': failed, + // '-1': cancelled, + // '0': open , + // '1': partially filled, + // '2': fully filled, + // '3': submitting, + // '4': cancelling, + // '6': incomplete(open+partially filled), + // '7': complete(cancelled+fully filled), + return await this.fetchOrdersByState ('6', symbol, since, limit, params); + } + + async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { + // '-2': failed, + // '-1': cancelled, + // '0': open , + // '1': partially filled, + // '2': fully filled, + // '3': submitting, + // '4': cancelling, + // '6': incomplete(open+partially filled), + // '7': complete(cancelled+fully filled), + return await this.fetchOrdersByState ('7', symbol, since, limit, params); + } + + parseDepositAddresses (addresses) { + const result = []; + for (let i = 0; i < addresses.length; i++) { + result.push (this.parseDepositAddress (addresses[i])); + } + return result; + } + + parseDepositAddress (depositAddress, currency = undefined) { + // + // { + // address: '0x696abb81974a8793352cbd33aadcf78eda3cfdfa', + // currency: 'eth' + // tag: 'abcde12345', // will be missing if the token does not require a deposit tag + // payment_id: 'abcde12345', // will not be returned if the token does not require a payment_id + // // can_deposit: 1, // 0 or 1, documented but missing + // // can_withdraw: 1, // 0 or 1, documented but missing + // } + // + const address = this.safeString (depositAddress, 'address'); + let tag = this.safeString2 (depositAddress, 'tag', 'payment_id'); + tag = this.safeString (depositAddress, 'memo', tag); + const currencyId = this.safeString (depositAddress, 'currency'); + const code = this.safeCurrencyCode (currencyId); + this.checkAddress (address); + return { + 'currency': code, + 'address': address, + 'tag': tag, + 'info': depositAddress, + }; + } + + async fetchDepositAddress (code, params = {}) { + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'currency': currency['id'], + }; + const response = await this.accountGetDepositAddress (this.extend (request, params)); + // + // [ + // { + // address: '0x696abb81974a8793352cbd33aadcf78eda3cfdfa', + // currency: 'eth' + // } + // ] + // + const addresses = this.parseDepositAddresses (response); + const numAddresses = addresses.length; + if (numAddresses < 1) { + throw new InvalidAddress (this.id + ' fetchDepositAddress cannot return nonexistent addresses, you should create withdrawal addresses with the exchange website first'); + } + return addresses[0]; + } + + async withdraw (code, amount, address, tag = undefined, params = {}) { + this.checkAddress (address); + await this.loadMarkets (); + const currency = this.currency (code); + if (tag) { + address = address + ':' + tag; + } + const fee = this.safeString (params, 'fee'); + if (fee === undefined) { + throw new ExchangeError (this.id + " withdraw() requires a `fee` string parameter, network transaction fee must be ≥ 0. Withdrawals to OKCoin or OKEx are fee-free, please set '0'. Withdrawing to external digital asset address requires network transaction fee."); + } + const request = { + 'currency': currency['id'], + 'to_address': address, + 'destination': '4', // 2 = OKCoin International, 3 = OKEx 4 = others + 'amount': this.numberToString (amount), + 'fee': fee, // String. Network transaction fee ≥ 0. Withdrawals to OKCoin or OKEx are fee-free, please set as 0. Withdrawal to external digital asset address requires network transaction fee. + }; + if ('password' in params) { + request['trade_pwd'] = params['password']; + } else if ('trade_pwd' in params) { + request['trade_pwd'] = params['trade_pwd']; + } else if (this.password) { + request['trade_pwd'] = this.password; + } + const query = this.omit (params, [ 'fee', 'password', 'trade_pwd' ]); + if (!('trade_pwd' in request)) { + throw new ExchangeError (this.id + ' withdraw() requires this.password set on the exchange instance or a password / trade_pwd parameter'); + } + const response = await this.accountPostWithdrawal (this.extend (request, query)); + // + // { + // "amount":"0.1", + // "withdrawal_id":"67485", + // "currency":"btc", + // "result":true + // } + // + return { + 'info': response, + 'id': this.safeString (response, 'withdrawal_id'), + }; + } + + async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = {}; + let method = 'accountGetDepositHistory'; + let currency = undefined; + if (code !== undefined) { + currency = this.currency (code); + request['code'] = currency['code']; + method += 'Currency'; + } + const response = await this[method] (this.extend (request, params)); + return this.parseTransactions (response, currency, since, limit, params); + } + + async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const request = {}; + let method = 'accountGetWithdrawalHistory'; + let currency = undefined; + if (code !== undefined) { + currency = this.currency (code); + request['code'] = currency['code']; + method += 'Currency'; + } + const response = await this[method] (this.extend (request, params)); + return this.parseTransactions (response, currency, since, limit, params); + } + + parseTransactionStatus (status) { + // + // deposit statuses + // + // { + // '0': 'waiting for confirmation', + // '1': 'confirmation account', + // '2': 'recharge success' + // } + // + // withdrawal statues + // + // { + // '-3': 'pending cancel', + // '-2': 'cancelled', + // '-1': 'failed', + // '0': 'pending', + // '1': 'sending', + // '2': 'sent', + // '3': 'email confirmation', + // '4': 'manual confirmation', + // '5': 'awaiting identity confirmation' + // } + // + const statuses = { + '-3': 'pending', + '-2': 'pending', + '-1': 'failed', + '0': 'pending', + '1': 'pending', + '2': 'ok', + '3': 'pending', + '4': 'pending', + '5': 'pending', + }; + return this.safeString (statuses, status, status); + } + + parseTransaction (transaction, currency = undefined) { + // + // withdraw + // + // { + // "amount":"0.1", + // "withdrawal_id":"67485", + // "currency":"btc", + // "result":true + // } + // + // fetchWithdrawals + // + // { + // amount: "4.72100000", + // withdrawal_id: "1729116", + // fee: "0.01000000eth", + // txid: "0xf653125bbf090bcfe4b5e8e7b8f586a9d87aa7de94598702758c0802b…", + // currency: "ETH", + // from: "7147338839", + // to: "0x26a3CB49578F07000575405a57888681249c35Fd", + // timestamp: "2018-08-17T07:03:42.000Z", + // status: "2" + // } + // + // fetchDeposits + // + // { + // amount: "0.47847546", + // txid: "1723573_3_0_0_WALLET", + // currency: "BTC", + // to: "", + // timestamp: "2018-08-16T03:41:10.000Z", + // status: "2" + // } + // + let type = undefined; + let id = undefined; + let address = undefined; + const withdrawalId = this.safeString (transaction, 'withdrawal_id'); + const addressFrom = this.safeString (transaction, 'from'); + const addressTo = this.safeString (transaction, 'to'); + if (withdrawalId !== undefined) { + type = 'withdrawal'; + id = withdrawalId; + address = addressTo; + } else { + // the payment_id will appear on new deposits but appears to be removed from the response after 2 months + id = this.safeString (transaction, 'payment_id'); + type = 'deposit'; + address = addressTo; + } + const currencyId = this.safeString (transaction, 'currency'); + const code = this.safeCurrencyCode (currencyId); + const amount = this.safeFloat (transaction, 'amount'); + const status = this.parseTransactionStatus (this.safeString (transaction, 'status')); + const txid = this.safeString (transaction, 'txid'); + const timestamp = this.parse8601 (this.safeString (transaction, 'timestamp')); + let feeCost = undefined; + if (type === 'deposit') { + feeCost = 0; + } else { + if (currencyId !== undefined) { + const feeWithCurrencyId = this.safeString (transaction, 'fee'); + if (feeWithCurrencyId !== undefined) { + // https://github.com/ccxt/ccxt/pull/5748 + const lowercaseCurrencyId = currencyId.toLowerCase (); + const feeWithoutCurrencyId = feeWithCurrencyId.replace (lowercaseCurrencyId, ''); + feeCost = parseFloat (feeWithoutCurrencyId); + } + } + } + // todo parse tags + return { + 'info': transaction, + 'id': id, + 'currency': code, + 'amount': amount, + 'addressFrom': addressFrom, + 'addressTo': addressTo, + 'address': address, + 'tagFrom': undefined, + 'tagTo': undefined, + 'tag': undefined, + 'status': status, + 'type': type, + 'updated': undefined, + 'txid': txid, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'fee': { + 'currency': code, + 'cost': feeCost, + }, + }; + } + + parseMyTrade (pair, market = undefined) { + // check that trading symbols match in both entries + const first = pair[0]; + const second = pair[1]; + const firstMarketId = this.safeString (first, 'instrument_id'); + const secondMarketId = this.safeString (second, 'instrument_id'); + if (firstMarketId !== secondMarketId) { + throw new NotSupported (this.id + ' parseMyTrade() received unrecognized response format, differing instrument_ids in one fill, the exchange API might have changed, paste your verbose output: https://github.com/ccxt/ccxt/wiki/FAQ#what-is-required-to-get-help'); + } + const marketId = firstMarketId; + // determine the base and quote + let quoteId = undefined; + let symbol = undefined; + if (marketId in this.markets_by_id) { + market = this.markets_by_id[marketId]; + quoteId = market['quoteId']; + symbol = market['symbol']; + } else { + const parts = marketId.split ('-'); + quoteId = this.safeString (parts, 1); + symbol = marketId; + } + const id = this.safeString (first, 'trade_id'); + const price = this.safeFloat (first, 'price'); + // determine buy/sell side and amounts + // get the side from either the first trade or the second trade + let feeCost = this.safeFloat (first, 'fee'); + const index = (feeCost !== 0) ? 0 : 1; + const userTrade = this.safeValue (pair, index); + const otherTrade = this.safeValue (pair, 1 - index); + const receivedCurrencyId = this.safeString (userTrade, 'currency'); + let side = undefined; + let amount = undefined; + let cost = undefined; + if (receivedCurrencyId === quoteId) { + side = 'sell'; + amount = this.safeFloat (otherTrade, 'size'); + cost = this.safeFloat (userTrade, 'size'); + } else { + side = 'buy'; + amount = this.safeFloat (userTrade, 'size'); + cost = this.safeFloat (otherTrade, 'size'); + } + feeCost = (feeCost !== 0) ? feeCost : this.safeFloat (second, 'fee'); + const trade = this.safeValue (pair, index); + // + // simplified structures to show the underlying semantics + // + // // market/limit sell + // + // { + // "currency":"USDT", + // "fee":"-0.04647925", // ←--- fee in received quote currency + // "price":"129.13", // ←------ price + // "size":"30.98616393", // ←-- cost + // }, + // { + // "currency":"ETH", + // "fee":"0", + // "price":"129.13", + // "size":"0.23996099", // ←--- amount + // }, + // + // // market/limit buy + // + // { + // "currency":"ETH", + // "fee":"-0.00036049", // ←--- fee in received base currency + // "price":"129.16", // ←------ price + // "size":"0.240322", // ←----- amount + // }, + // { + // "currency":"USDT", + // "fee":"0", + // "price":"129.16", + // "size":"31.03998952", // ←-- cost + // } + // + const timestamp = this.parse8601 (this.safeString2 (trade, 'timestamp', 'created_at')); + let takerOrMaker = this.safeString2 (trade, 'exec_type', 'liquidity'); + if (takerOrMaker === 'M') { + takerOrMaker = 'maker'; + } else if (takerOrMaker === 'T') { + takerOrMaker = 'taker'; + } + let fee = undefined; + if (feeCost !== undefined) { + const feeCurrencyId = this.safeString (userTrade, 'currency'); + const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); + fee = { + // fee is either a positive number (invitation rebate) + // or a negative number (transaction fee deduction) + // therefore we need to invert the fee + // more about it https://github.com/ccxt/ccxt/issues/5909 + 'cost': -feeCost, + 'currency': feeCurrencyCode, + }; + } + const orderId = this.safeString (trade, 'order_id'); + return { + 'info': pair, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'symbol': symbol, + 'id': id, + 'order': orderId, + 'type': undefined, + 'takerOrMaker': takerOrMaker, + 'side': side, + 'price': price, + 'amount': amount, + 'cost': cost, + 'fee': fee, + }; + } + + parseMyTrades (trades, market = undefined, since = undefined, limit = undefined, params = {}) { + const grouped = this.groupBy (trades, 'trade_id'); + const tradeIds = Object.keys (grouped); + const result = []; + for (let i = 0; i < tradeIds.length; i++) { + const tradeId = tradeIds[i]; + const pair = grouped[tradeId]; + // make sure it has exactly 2 trades, no more, no less + const numTradesInPair = pair.length; + if (numTradesInPair === 2) { + const trade = this.parseMyTrade (pair); + result.push (trade); + } + } + let symbol = undefined; + if (market !== undefined) { + symbol = market['symbol']; + } + return this.filterBySymbolSinceLimit (result, symbol, since, limit); + } + + async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { + // okex actually returns ledger entries instead of fills here, so each fill in the order + // is represented by two trades with opposite buy/sell sides, not one :\ + // this aspect renders the 'fills' endpoint unusable for fetchOrderTrades + // until either OKEX fixes the API or we workaround this on our side somehow + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + if ((limit !== undefined) && (limit > 100)) { + limit = 100; + } + const request = { + 'instrument_id': market['id'], + // 'order_id': id, // string + // 'after': '1', // return the page after the specified page number + // 'before': '1', // return the page before the specified page number + // 'limit': limit, // optional, number of results per request, default = maximum = 100 + }; + const defaultType = this.safeString2 (this.options, 'fetchMyTrades', 'defaultType'); + const type = this.safeString (params, 'type', defaultType); + const query = this.omit (params, 'type'); + const method = type + 'GetFills'; + const response = await this[method] (this.extend (request, query)); + // + // [ + // // sell + // { + // "created_at":"2020-03-29T11:55:25.000Z", + // "currency":"USDT", + // "exec_type":"T", + // "fee":"-0.04647925", + // "instrument_id":"ETH-USDT", + // "ledger_id":"10562924353", + // "liquidity":"T", + // "order_id":"4636470489136128", + // "price":"129.13", + // "product_id":"ETH-USDT", + // "side":"buy", + // "size":"30.98616393", + // "timestamp":"2020-03-29T11:55:25.000Z", + // "trade_id":"18551601" + // }, + // { + // "created_at":"2020-03-29T11:55:25.000Z", + // "currency":"ETH", + // "exec_type":"T", + // "fee":"0", + // "instrument_id":"ETH-USDT", + // "ledger_id":"10562924352", + // "liquidity":"T", + // "order_id":"4636470489136128", + // "price":"129.13", + // "product_id":"ETH-USDT", + // "side":"sell", + // "size":"0.23996099", + // "timestamp":"2020-03-29T11:55:25.000Z", + // "trade_id":"18551601" + // }, + // // buy + // { + // "created_at":"2020-03-29T11:55:16.000Z", + // "currency":"ETH", + // "exec_type":"T", + // "fee":"-0.00036049", + // "instrument_id":"ETH-USDT", + // "ledger_id":"10562922669", + // "liquidity":"T", + // "order_id": "4636469894136832", + // "price":"129.16", + // "product_id":"ETH-USDT", + // "side":"buy", + // "size":"0.240322", + // "timestamp":"2020-03-29T11:55:16.000Z", + // "trade_id":"18551600" + // }, + // { + // "created_at":"2020-03-29T11:55:16.000Z", + // "currency":"USDT", + // "exec_type":"T", + // "fee":"0", + // "instrument_id":"ETH-USDT", + // "ledger_id":"10562922668", + // "liquidity":"T", + // "order_id":"4636469894136832", + // "price":"129.16", + // "product_id":"ETH-USDT", + // "side":"sell", + // "size":"31.03998952", + // "timestamp":"2020-03-29T11:55:16.000Z", + // "trade_id":"18551600" + // } + // ] + // + return this.parseMyTrades (response, market, since, limit, params); + } + + async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { + const request = { + // 'instrument_id': market['id'], + 'order_id': id, + // 'after': '1', // return the page after the specified page number + // 'before': '1', // return the page before the specified page number + // 'limit': limit, // optional, number of results per request, default = maximum = 100 + }; + return await this.fetchMyTrades (symbol, since, limit, this.extend (request, params)); + } + + async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) { + await this.loadMarkets (); + const defaultType = this.safeString2 (this.options, 'fetchLedger', 'defaultType'); + const type = this.safeString (params, 'type', defaultType); + const query = this.omit (params, 'type'); + const suffix = (type === 'account') ? '' : 'Accounts'; + let argument = ''; + const request = { + // 'from': 'id', + // 'to': 'id', + }; + if (limit !== undefined) { + request['limit'] = limit; + } + let currency = undefined; + if ((type === 'spot') || (type === 'futures')) { + if (code === undefined) { + throw new ArgumentsRequired (this.id + " fetchLedger requires a currency code argument for '" + type + "' markets"); + } + argument = 'Currency'; + currency = this.currency (code); + request['currency'] = currency['id']; + } else if ((type === 'margin') || (type === 'swap')) { + if (code === undefined) { + throw new ArgumentsRequired (this.id + " fetchLedger requires a code argument (a market symbol) for '" + type + "' markets"); + } + argument = 'InstrumentId'; + const market = this.market (code); // we intentionally put a market inside here for the margin and swap ledgers + currency = this.currency (market['base']); + request['instrument_id'] = market['id']; + // + // if (type === 'margin') { + // // + // // 3. Borrow + // // 4. Repayment + // // 5. Interest + // // 7. Buy + // // 8. Sell + // // 9. From capital account + // // 10. From C2C + // // 11. From Futures + // // 12. From Spot + // // 13. From ETT + // // 14. To capital account + // // 15. To C2C + // // 16. To Spot + // // 17. To Futures + // // 18. To ETT + // // 19. Mandatory Repayment + // // 20. From Piggybank + // // 21. To Piggybank + // // 22. From Perpetual + // // 23. To Perpetual + // // 24. Liquidation Fee + // // 54. Clawback + // // 59. Airdrop Return. + // // + // request['type'] = 'number'; // All types will be returned if this filed is left blank + // } + // + } else if (type === 'account') { + if (code !== undefined) { + currency = this.currency (code); + request['currency'] = currency['id']; + } + // + // // + // // 1. deposit + // // 2. withdrawal + // // 13. cancel withdrawal + // // 18. into futures account + // // 19. out of futures account + // // 20. into sub account + // // 21. out of sub account + // // 28. claim + // // 29. into ETT account + // // 30. out of ETT account + // // 31. into C2C account + // // 32. out of C2C account + // // 33. into margin account + // // 34. out of margin account + // // 37. into spot account + // // 38. out of spot account + // // + // request['type'] = 'number'; + // + } else { + throw new NotSupported (this.id + " fetchLedger does not support the '" + type + "' type (the type must be one of 'account', 'spot', 'margin', 'futures', 'swap')"); + } + const method = type + 'Get' + suffix + argument + 'Ledger'; + const response = await this[method] (this.extend (request, query)); + // + // transfer funds transfer in/out + // trade funds moved as a result of a trade, spot and margin accounts only + // rebate fee rebate as per fee schedule, spot and margin accounts only + // match open long/open short/close long/close short (futures) or a change in the amount because of trades (swap) + // fee fee, futures only + // settlement settlement/clawback/settle long/settle short + // liquidation force close long/force close short/deliver close long/deliver close short + // funding funding fee, swap only + // margin a change in the amount after adjusting margin, swap only + // + // account + // + // [ + // { + // "amount":0.00051843, + // "balance":0.00100941, + // "currency":"BTC", + // "fee":0, + // "ledger_id":8987285, + // "timestamp":"2018-10-12T11:01:14.000Z", + // "typename":"Get from activity" + // } + // ] + // + // spot + // + // [ + // { + // "timestamp":"2019-03-18T07:08:25.000Z", + // "ledger_id":"3995334780", + // "created_at":"2019-03-18T07:08:25.000Z", + // "currency":"BTC", + // "amount":"0.0009985", + // "balance":"0.0029955", + // "type":"trade", + // "details":{ + // "instrument_id":"BTC-USDT", + // "order_id":"2500650881647616", + // "product_id":"BTC-USDT" + // } + // } + // ] + // + // margin + // + // [ + // [ + // { + // "created_at":"2019-03-20T03:45:05.000Z", + // "ledger_id":"78918186", + // "timestamp":"2019-03-20T03:45:05.000Z", + // "currency":"EOS", + // "amount":"0", // ? + // "balance":"0.59957711", + // "type":"transfer", + // "details":{ + // "instrument_id":"EOS-USDT", + // "order_id":"787057", + // "product_id":"EOS-USDT" + // } + // } + // ], + // { + // "before":"78965766", + // "after":"78918186" + // } + // ] + // + // futures + // + // [ + // { + // "ledger_id":"2508090544914461", + // "timestamp":"2019-03-19T14:40:24.000Z", + // "amount":"-0.00529521", + // "balance":"0", + // "currency":"EOS", + // "type":"fee", + // "details":{ + // "order_id":"2506982456445952", + // "instrument_id":"EOS-USD-190628" + // } + // } + // ] + // + // swap + // + // [ + // { + // "amount":"0.004742", + // "fee":"-0.000551", + // "type":"match", + // "instrument_id":"EOS-USD-SWAP", + // "ledger_id":"197429674941902848", + // "timestamp":"2019-03-25T05:56:31.286Z" + // }, + // ] + // + const isArray = Array.isArray (response[0]); + const isMargin = (type === 'margin'); + const entries = (isMargin && isArray) ? response[0] : response; + return this.parseLedger (entries, currency, since, limit); + } + + parseLedgerEntryType (type) { + const types = { + 'transfer': 'transfer', // // funds transfer in/out + 'trade': 'trade', // funds moved as a result of a trade, spot and margin accounts only + 'rebate': 'rebate', // fee rebate as per fee schedule, spot and margin accounts only + 'match': 'trade', // open long/open short/close long/close short (futures) or a change in the amount because of trades (swap) + 'fee': 'fee', // fee, futures only + 'settlement': 'trade', // settlement/clawback/settle long/settle short + 'liquidation': 'trade', // force close long/force close short/deliver close long/deliver close short + 'funding': 'fee', // funding fee, swap only + 'margin': 'margin', // a change in the amount after adjusting margin, swap only + }; + return this.safeString (types, type, type); + } + + parseLedgerEntry (item, currency = undefined) { + // + // + // account + // + // { + // "amount":0.00051843, + // "balance":0.00100941, + // "currency":"BTC", + // "fee":0, + // "ledger_id":8987285, + // "timestamp":"2018-10-12T11:01:14.000Z", + // "typename":"Get from activity" + // } + // + // spot + // + // { + // "timestamp":"2019-03-18T07:08:25.000Z", + // "ledger_id":"3995334780", + // "created_at":"2019-03-18T07:08:25.000Z", + // "currency":"BTC", + // "amount":"0.0009985", + // "balance":"0.0029955", + // "type":"trade", + // "details":{ + // "instrument_id":"BTC-USDT", + // "order_id":"2500650881647616", + // "product_id":"BTC-USDT" + // } + // } + // + // margin + // + // { + // "created_at":"2019-03-20T03:45:05.000Z", + // "ledger_id":"78918186", + // "timestamp":"2019-03-20T03:45:05.000Z", + // "currency":"EOS", + // "amount":"0", // ? + // "balance":"0.59957711", + // "type":"transfer", + // "details":{ + // "instrument_id":"EOS-USDT", + // "order_id":"787057", + // "product_id":"EOS-USDT" + // } + // } + // + // futures + // + // { + // "ledger_id":"2508090544914461", + // "timestamp":"2019-03-19T14:40:24.000Z", + // "amount":"-0.00529521", + // "balance":"0", + // "currency":"EOS", + // "type":"fee", + // "details":{ + // "order_id":"2506982456445952", + // "instrument_id":"EOS-USD-190628" + // } + // } + // + // swap + // + // { + // "amount":"0.004742", + // "fee":"-0.000551", + // "type":"match", + // "instrument_id":"EOS-USD-SWAP", + // "ledger_id":"197429674941902848", + // "timestamp":"2019-03-25T05:56:31.286Z" + // }, + // + const id = this.safeString (item, 'ledger_id'); + const account = undefined; + const details = this.safeValue (item, 'details', {}); + const referenceId = this.safeString (details, 'order_id'); + const referenceAccount = undefined; + const type = this.parseLedgerEntryType (this.safeString (item, 'type')); + const code = this.safeCurrencyCode (this.safeString (item, 'currency'), currency); + const amount = this.safeFloat (item, 'amount'); + const timestamp = this.parse8601 (this.safeString (item, 'timestamp')); + const fee = { + 'cost': this.safeFloat (item, 'fee'), + 'currency': code, + }; + const before = undefined; + const after = this.safeFloat (item, 'balance'); + const status = 'ok'; + return { + 'info': item, + 'id': id, + 'account': account, + 'referenceId': referenceId, + 'referenceAccount': referenceAccount, + 'type': type, + 'currency': code, + 'amount': amount, + 'before': before, // balance before + 'after': after, // balance after + 'status': status, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'fee': fee, + }; + } + + sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { + const isArray = Array.isArray (params); + let request = '/api/' + api + '/' + this.version + '/'; + request += isArray ? path : this.implodeParams (path, params); + const query = isArray ? params : this.omit (params, this.extractParams (path)); + let url = this.implodeParams (this.urls['api']['rest'], { 'hostname': this.hostname }) + request; + const type = this.getPathAuthenticationType (path); + if (type === 'public') { + if (Object.keys (query).length) { + url += '?' + this.urlencode (query); + } + } else if (type === 'private') { + this.checkRequiredCredentials (); + const timestamp = this.iso8601 (this.milliseconds ()); + headers = { + 'OK-ACCESS-KEY': this.apiKey, + 'OK-ACCESS-PASSPHRASE': this.password, + 'OK-ACCESS-TIMESTAMP': timestamp, + // 'OK-FROM': '', + // 'OK-TO': '', + // 'OK-LIMIT': '', + }; + let auth = timestamp + method + request; + if (method === 'GET') { + if (Object.keys (query).length) { + const urlencodedQuery = '?' + this.urlencode (query); + url += urlencodedQuery; + auth += urlencodedQuery; + } + } else { + if (isArray || Object.keys (query).length) { + body = this.json (query); + auth += body; + } + headers['Content-Type'] = 'application/json'; + } + const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256', 'base64'); + headers['OK-ACCESS-SIGN'] = this.decode (signature); + } + return { 'url': url, 'method': method, 'body': body, 'headers': headers }; + } + + getPathAuthenticationType (path) { + // https://github.com/ccxt/ccxt/issues/6651 + // a special case to handle the optionGetUnderlying interefering with + // other endpoints containing this keyword + if (path === 'underlying') { + return 'public'; + } + const auth = this.safeValue (this.options, 'auth', {}); + const key = this.findBroadlyMatchedKey (auth, path); + return this.safeString (auth, key, 'private'); + } + + handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { + const feedback = this.id + ' ' + body; + if (code === 503) { + // {"message":"name resolution failed"} + throw new ExchangeNotAvailable (feedback); + } + if (!response) { + return; // fallback to default error handler + } + const message = this.safeString (response, 'message'); + const errorCode = this.safeString2 (response, 'code', 'error_code'); + if (message !== undefined) { + this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback); + this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback); + this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback); + const nonEmptyMessage = (message !== ''); + const nonZeroErrorCode = (errorCode !== undefined) && (errorCode !== '0'); + if (nonZeroErrorCode || nonEmptyMessage) { + throw new ExchangeError (feedback); // unknown message + } + } + } }; diff --git a/TaskServer/node_modules/ccxt/js/okex3.js b/TaskServer/node_modules/ccxt/js/okex3.js deleted file mode 100644 index 22c83cce3..000000000 --- a/TaskServer/node_modules/ccxt/js/okex3.js +++ /dev/null @@ -1,2722 +0,0 @@ -'use strict'; - -// --------------------------------------------------------------------------- - -const Exchange = require ('./base/Exchange'); -const { ExchangeError, ExchangeNotAvailable, ArgumentsRequired, BadRequest, AccountSuspended, InvalidAddress, PermissionDenied, DDoSProtection, InsufficientFunds, InvalidNonce, CancelPending, InvalidOrder, OrderNotFound, AuthenticationError, RequestTimeout, NotSupported, BadSymbol } = require ('./base/errors'); - -// --------------------------------------------------------------------------- - -module.exports = class okex3 extends Exchange { - describe () { - return this.deepExtend (super.describe (), { - 'id': 'okex3', - 'name': 'OKEX', - 'countries': [ 'CN', 'US' ], - 'version': 'v3', - 'rateLimit': 1000, // up to 3000 requests per 5 minutes ≈ 600 requests per minute ≈ 10 requests per second ≈ 100 ms - 'has': { - 'CORS': false, - 'fetchOHLCV': true, - 'fetchOrder': true, - 'fetchOrders': false, - 'fetchOpenOrders': true, - 'fetchClosedOrders': true, - 'fetchCurrencies': false, // see below - 'fetchDeposits': true, - 'fetchWithdrawals': true, - 'fetchTime': true, - 'fetchTransactions': false, - 'fetchMyTrades': false, // they don't have it - 'fetchDepositAddress': true, - 'fetchOrderTrades': true, - 'fetchTickers': true, - 'fetchLedger': true, - 'withdraw': true, - 'futures': true, - }, - 'timeframes': { - '1m': '60', - '3m': '180', - '5m': '300', - '15m': '900', - '30m': '1800', - '1h': '3600', - '2h': '7200', - '4h': '14400', - '6h': '21600', - '12h': '43200', - '1d': '86400', - '1w': '604800', - }, - 'urls': { - 'logo': 'https://user-images.githubusercontent.com/1294454/32552768-0d6dd3c6-c4a6-11e7-90f8-c043b64756a7.jpg', - 'api': 'https://www.okex.com', - 'www': 'https://www.okex.com', - 'doc': 'https://www.okex.com/docs/en/', - 'fees': 'https://www.okex.com/pages/products/fees.html', - }, - 'api': { - 'general': { - 'get': [ - 'time', - ], - }, - 'account': { - 'get': [ - 'currencies', - 'wallet', - 'wallet/{currency}', - 'withdrawal/fee', - 'withdrawal/history', - 'withdrawal/history/{currency}', - 'ledger', - 'deposit/address', - 'deposit/history', - 'deposit/history/{currency}', - ], - 'post': [ - 'transfer', - 'withdrawal', - ], - }, - 'spot': { - 'get': [ - 'accounts', - 'accounts/{currency}', - 'accounts/{currency}/ledger', - 'orders', - 'orders_pending', - 'orders/{order_id}', - 'orders/{client_oid}', - 'fills', - 'algo', - // public - 'instruments', - 'instruments/{instrument_id}/book', - 'instruments/ticker', - 'instruments/{instrument_id}/ticker', - 'instruments/{instrument_id}/trades', - 'instruments/{instrument_id}/candles', - ], - 'post': [ - 'order_algo', - 'orders', - 'batch_orders', - 'cancel_orders/{order_id}', - 'cancel_orders/{client_oid}', - 'cancel_batch_algos', - 'cancel_batch_orders', - ], - }, - 'margin': { - 'get': [ - 'accounts', - 'accounts/{instrument_id}', - 'accounts/{instrument_id}/ledger', - 'accounts/availability', - 'accounts/{instrument_id}/availability', - 'accounts/borrowed', - 'accounts/{instrument_id}/borrowed', - 'orders', - 'orders/{order_id}', - 'orders/{client_oid}', - 'orders_pending', - 'fills', - ], - 'post': [ - 'accounts/borrow', - 'accounts/repayment', - 'orders', - 'batch_orders', - 'cancel_orders', - 'cancel_orders/{order_id}', - 'cancel_orders/{client_oid}', - 'cancel_batch_orders', - ], - }, - 'futures': { - 'get': [ - 'position', - '{instrument_id}/position', - 'accounts', - 'accounts/{currency}', - 'accounts/{currency}/leverage', - 'accounts/{currency}/ledger', - 'order_algo/{instrument_id}', - 'orders/{instrument_id}', - 'orders/{instrument_id}/{order_id}', - 'orders/{instrument_id}/{client_oid}', - 'fills', - // public - 'instruments', - 'instruments/{instrument_id}/book', - 'instruments/ticker', - 'instruments/{instrument_id}/ticker', - 'instruments/{instrument_id}/trades', - 'instruments/{instrument_id}/candles', - 'accounts/{instrument_id}/holds', - 'instruments/{instrument_id}/index', - 'rate', - 'instruments/{instrument_id}/estimated_price', - 'instruments/{instrument_id}/open_interest', - 'instruments/{instrument_id}/price_limit', - 'instruments/{instrument_id}/liquidation', - 'instruments/{instrument_id}/mark_price', - ], - 'post': [ - 'accounts/{currency}/leverage', - 'accounts/margin_mode', - 'order', - 'orders', - 'order_algo', - 'cancel_algos', - 'cancel_order/{instrument_id}/{order_id}', - 'cancel_order/{instrument_id}/{client_oid}', - 'cancel_batch_orders/{instrument_id}', - 'close_position', - 'cancel_all', - ], - }, - 'swap': { - 'get': [ - 'position', - '{instrument_id}/position', - 'accounts', - '{instrument_id}/accounts', - 'accounts/{instrument_id}/settings', - 'accounts/{instrument_id}/ledger', - 'accounts/{instrument_id}/holds', - 'order_algo/{instrument_id}', - 'orders/{instrument_id}', - 'orders/{instrument_id}/{order_id}', - 'orders/{instrument_id}/{client_oid}', - 'fills', - // public - 'instruments', - 'instruments/{instrument_id}/depth', - 'instruments/ticker', - 'instruments/{instrument_id}/ticker', - 'instruments/{instrument_id}/trades', - 'instruments/{instrument_id}/candles', - 'instruments/{instrument_id}/index', - 'rate', - 'instruments/{instrument_id}/open_interest', - 'instruments/{instrument_id}/price_limit', - 'instruments/{instrument_id}/liquidation', - 'instruments/{instrument_id}/funding_time', - 'instruments/{instrument_id}/mark_price', - 'instruments/{instrument_id}/historical_funding_rate', - ], - 'post': [ - 'accounts/{instrument_id}/leverage', - 'order', - 'order_algo', - 'orders', - 'cancel_algos', - 'cancel_order/{instrument_id}/{order_id}', - 'cancel_order/{instrument_id}/{client_oid}', - 'cancel_batch_orders/{instrument_id}', - ], - }, - // they have removed this part from public - 'ett': { - 'get': [ - 'accounts', - 'accounts/{currency}', - 'accounts/{currency}/ledger', - 'orders', // fetchOrder, fetchOrders - // public - 'constituents/{ett}', - 'define-price/{ett}', - ], - 'post': [ - 'orders', - 'orders/{order_id}', - ], - }, - }, - 'fees': { - 'trading': { - 'taker': 0.0015, - 'maker': 0.0010, - }, - 'spot': { - 'taker': 0.0015, - 'maker': 0.0010, - }, - 'futures': { - 'taker': 0.0005, - 'maker': 0.0002, - }, - 'swap': { - 'taker': 0.00075, - 'maker': 0.00020, - }, - }, - 'requiredCredentials': { - 'apiKey': true, - 'secret': true, - 'password': true, - }, - 'exceptions': { - // http error codes - // 400 Bad Request — Invalid request format - // 401 Unauthorized — Invalid API Key - // 403 Forbidden — You do not have access to the requested resource - // 404 Not Found - // 500 Internal Server Error — We had a problem with our server - 'exact': { - '1': ExchangeError, // { "code": 1, "message": "System error" } - // undocumented - 'failure to get a peer from the ring-balancer': ExchangeNotAvailable, // { "message": "failure to get a peer from the ring-balancer" } - '4010': PermissionDenied, // { "code": 4010, "message": "For the security of your funds, withdrawals are not permitted within 24 hours after changing fund password / mobile number / Google Authenticator settings " } - // common - '30001': AuthenticationError, // { "code": 30001, "message": 'request header "OK_ACCESS_KEY" cannot be blank'} - '30002': AuthenticationError, // { "code": 30002, "message": 'request header "OK_ACCESS_SIGN" cannot be blank'} - '30003': AuthenticationError, // { "code": 30003, "message": 'request header "OK_ACCESS_TIMESTAMP" cannot be blank'} - '30004': AuthenticationError, // { "code": 30004, "message": 'request header "OK_ACCESS_PASSPHRASE" cannot be blank'} - '30005': InvalidNonce, // { "code": 30005, "message": "invalid OK_ACCESS_TIMESTAMP" } - '30006': AuthenticationError, // { "code": 30006, "message": "invalid OK_ACCESS_KEY" } - '30007': BadRequest, // { "code": 30007, "message": 'invalid Content_Type, please use "application/json" format'} - '30008': RequestTimeout, // { "code": 30008, "message": "timestamp request expired" } - '30009': ExchangeError, // { "code": 30009, "message": "system error" } - '30010': AuthenticationError, // { "code": 30010, "message": "API validation failed" } - '30011': PermissionDenied, // { "code": 30011, "message": "invalid IP" } - '30012': AuthenticationError, // { "code": 30012, "message": "invalid authorization" } - '30013': AuthenticationError, // { "code": 30013, "message": "invalid sign" } - '30014': DDoSProtection, // { "code": 30014, "message": "request too frequent" } - '30015': AuthenticationError, // { "code": 30015, "message": 'request header "OK_ACCESS_PASSPHRASE" incorrect'} - '30016': ExchangeError, // { "code": 30015, "message": "you are using v1 apiKey, please use v1 endpoint. If you would like to use v3 endpoint, please subscribe to v3 apiKey" } - '30017': ExchangeError, // { "code": 30017, "message": "apikey's broker id does not match" } - '30018': ExchangeError, // { "code": 30018, "message": "apikey's domain does not match" } - '30019': ExchangeNotAvailable, // { "code": 30019, "message": "Api is offline or unavailable" } - '30020': BadRequest, // { "code": 30020, "message": "body cannot be blank" } - '30021': BadRequest, // { "code": 30021, "message": "Json data format error" }, { "code": 30021, "message": "json data format error" } - '30022': PermissionDenied, // { "code": 30022, "message": "Api has been frozen" } - '30023': BadRequest, // { "code": 30023, "message": "{0} parameter cannot be blank" } - '30024': BadSymbol, // {"code":30024,"message":"\"instrument_id\" is an invalid parameter"} - '30025': BadRequest, // { "code": 30025, "message": "{0} parameter category error" } - '30026': DDoSProtection, // { "code": 30026, "message": "requested too frequent" } - '30027': AuthenticationError, // { "code": 30027, "message": "login failure" } - '30028': PermissionDenied, // { "code": 30028, "message": "unauthorized execution" } - '30029': AccountSuspended, // { "code": 30029, "message": "account suspended" } - '30030': ExchangeError, // { "code": 30030, "message": "endpoint request failed. Please try again" } - '30031': BadRequest, // { "code": 30031, "message": "token does not exist" } - '30032': BadSymbol, // { "code": 30032, "message": "pair does not exist" } - '30033': BadRequest, // { "code": 30033, "message": "exchange domain does not exist" } - '30034': ExchangeError, // { "code": 30034, "message": "exchange ID does not exist" } - '30035': ExchangeError, // { "code": 30035, "message": "trading is not supported in this website" } - '30036': ExchangeError, // { "code": 30036, "message": "no relevant data" } - '30038': AuthenticationError, // { "code": 30038, "message": "user does not exist" } - '30037': ExchangeNotAvailable, // { "code": 30037, "message": "endpoint is offline or unavailable" } - // futures - '32001': AccountSuspended, // { "code": 32001, "message": "futures account suspended" } - '32002': PermissionDenied, // { "code": 32002, "message": "futures account does not exist" } - '32003': CancelPending, // { "code": 32003, "message": "canceling, please wait" } - '32004': ExchangeError, // { "code": 32004, "message": "you have no unfilled orders" } - '32005': InvalidOrder, // { "code": 32005, "message": "max order quantity" } - '32006': InvalidOrder, // { "code": 32006, "message": "the order price or trigger price exceeds USD 1 million" } - '32007': InvalidOrder, // { "code": 32007, "message": "leverage level must be the same for orders on the same side of the contract" } - '32008': InvalidOrder, // { "code": 32008, "message": "Max. positions to open (cross margin)" } - '32009': InvalidOrder, // { "code": 32009, "message": "Max. positions to open (fixed margin)" } - '32010': ExchangeError, // { "code": 32010, "message": "leverage cannot be changed with open positions" } - '32011': ExchangeError, // { "code": 32011, "message": "futures status error" } - '32012': ExchangeError, // { "code": 32012, "message": "futures order update error" } - '32013': ExchangeError, // { "code": 32013, "message": "token type is blank" } - '32014': ExchangeError, // { "code": 32014, "message": "your number of contracts closing is larger than the number of contracts available" } - '32015': ExchangeError, // { "code": 32015, "message": "margin ratio is lower than 100% before opening positions" } - '32016': ExchangeError, // { "code": 32016, "message": "margin ratio is lower than 100% after opening position" } - '32017': ExchangeError, // { "code": 32017, "message": "no BBO" } - '32018': ExchangeError, // { "code": 32018, "message": "the order quantity is less than 1, please try again" } - '32019': ExchangeError, // { "code": 32019, "message": "the order price deviates from the price of the previous minute by more than 3%" } - '32020': ExchangeError, // { "code": 32020, "message": "the price is not in the range of the price limit" } - '32021': ExchangeError, // { "code": 32021, "message": "leverage error" } - '32022': ExchangeError, // { "code": 32022, "message": "this function is not supported in your country or region according to the regulations" } - '32023': ExchangeError, // { "code": 32023, "message": "this account has outstanding loan" } - '32024': ExchangeError, // { "code": 32024, "message": "order cannot be placed during delivery" } - '32025': ExchangeError, // { "code": 32025, "message": "order cannot be placed during settlement" } - '32026': ExchangeError, // { "code": 32026, "message": "your account is restricted from opening positions" } - '32029': ExchangeError, // { "code": 32029, "message": "order info does not exist" } - '32028': ExchangeError, // { "code": 32028, "message": "account is suspended and liquidated" } - '32027': ExchangeError, // { "code": 32027, "message": "cancelled over 20 orders" } - '32044': ExchangeError, // { "code": 32044, "message": "The margin ratio after submitting this order is lower than the minimum requirement ({0}) for your tier." } - // token and margin trading - '33001': PermissionDenied, // { "code": 33001, "message": "margin account for this pair is not enabled yet" } - '33002': AccountSuspended, // { "code": 33002, "message": "margin account for this pair is suspended" } - '33003': InsufficientFunds, // { "code": 33003, "message": "no loan balance" } - '33004': ExchangeError, // { "code": 33004, "message": "loan amount cannot be smaller than the minimum limit" } - '33005': ExchangeError, // { "code": 33005, "message": "repayment amount must exceed 0" } - '33006': ExchangeError, // { "code": 33006, "message": "loan order not found" } - '33007': ExchangeError, // { "code": 33007, "message": "status not found" } - '33008': ExchangeError, // { "code": 33008, "message": "loan amount cannot exceed the maximum limit" } - '33009': ExchangeError, // { "code": 33009, "message": "user ID is blank" } - '33010': ExchangeError, // { "code": 33010, "message": "you cannot cancel an order during session 2 of call auction" } - '33011': ExchangeError, // { "code": 33011, "message": "no new market data" } - '33012': ExchangeError, // { "code": 33012, "message": "order cancellation failed" } - '33013': InvalidOrder, // { "code": 33013, "message": "order placement failed" } - '33014': OrderNotFound, // { "code": 33014, "message": "order does not exist" } - '33015': InvalidOrder, // { "code": 33015, "message": "exceeded maximum limit" } - '33016': ExchangeError, // { "code": 33016, "message": "margin trading is not open for this token" } - '33017': InsufficientFunds, // { "code": 33017, "message": "insufficient balance" } - '33018': ExchangeError, // { "code": 33018, "message": "this parameter must be smaller than 1" } - '33020': ExchangeError, // { "code": 33020, "message": "request not supported" } - '33021': BadRequest, // { "code": 33021, "message": "token and the pair do not match" } - '33022': InvalidOrder, // { "code": 33022, "message": "pair and the order do not match" } - '33023': ExchangeError, // { "code": 33023, "message": "you can only place market orders during call auction" } - '33024': InvalidOrder, // { "code": 33024, "message": "trading amount too small" } - '33025': InvalidOrder, // { "code": 33025, "message": "base token amount is blank" } - '33026': ExchangeError, // { "code": 33026, "message": "transaction completed" } - '33027': InvalidOrder, // { "code": 33027, "message": "cancelled order or order cancelling" } - '33028': InvalidOrder, // { "code": 33028, "message": "the decimal places of the trading price exceeded the limit" } - '33029': InvalidOrder, // { "code": 33029, "message": "the decimal places of the trading size exceeded the limit" } - '33034': ExchangeError, // { "code": 33034, "message": "You can only place limit order after Call Auction has started" } - '33059': BadRequest, // { "code": 33059, "message": "client_oid or order_id is required" } - '33060': BadRequest, // { "code": 33060, "message": "Only fill in either parameter client_oid or order_id" } - // account - '34001': PermissionDenied, // { "code": 34001, "message": "withdrawal suspended" } - '34002': InvalidAddress, // { "code": 34002, "message": "please add a withdrawal address" } - '34003': ExchangeError, // { "code": 34003, "message": "sorry, this token cannot be withdrawn to xx at the moment" } - '34004': ExchangeError, // { "code": 34004, "message": "withdrawal fee is smaller than minimum limit" } - '34005': ExchangeError, // { "code": 34005, "message": "withdrawal fee exceeds the maximum limit" } - '34006': ExchangeError, // { "code": 34006, "message": "withdrawal amount is lower than the minimum limit" } - '34007': ExchangeError, // { "code": 34007, "message": "withdrawal amount exceeds the maximum limit" } - '34008': InsufficientFunds, // { "code": 34008, "message": "insufficient balance" } - '34009': ExchangeError, // { "code": 34009, "message": "your withdrawal amount exceeds the daily limit" } - '34010': ExchangeError, // { "code": 34010, "message": "transfer amount must be larger than 0" } - '34011': ExchangeError, // { "code": 34011, "message": "conditions not met" } - '34012': ExchangeError, // { "code": 34012, "message": "the minimum withdrawal amount for NEO is 1, and the amount must be an integer" } - '34013': ExchangeError, // { "code": 34013, "message": "please transfer" } - '34014': ExchangeError, // { "code": 34014, "message": "transfer limited" } - '34015': ExchangeError, // { "code": 34015, "message": "subaccount does not exist" } - '34016': PermissionDenied, // { "code": 34016, "message": "transfer suspended" } - '34017': AccountSuspended, // { "code": 34017, "message": "account suspended" } - '34018': AuthenticationError, // { "code": 34018, "message": "incorrect trades password" } - '34019': PermissionDenied, // { "code": 34019, "message": "please bind your email before withdrawal" } - '34020': PermissionDenied, // { "code": 34020, "message": "please bind your funds password before withdrawal" } - '34021': InvalidAddress, // { "code": 34021, "message": "Not verified address" } - '34022': ExchangeError, // { "code": 34022, "message": "Withdrawals are not available for sub accounts" } - '34023': PermissionDenied, // { "code": 34023, "message": "Please enable futures trading before transferring your funds" } - // swap - '35001': ExchangeError, // { "code": 35001, "message": "Contract does not exist" } - '35002': ExchangeError, // { "code": 35002, "message": "Contract settling" } - '35003': ExchangeError, // { "code": 35003, "message": "Contract paused" } - '35004': ExchangeError, // { "code": 35004, "message": "Contract pending settlement" } - '35005': AuthenticationError, // { "code": 35005, "message": "User does not exist" } - '35008': InvalidOrder, // { "code": 35008, "message": "Risk ratio too high" } - '35010': InvalidOrder, // { "code": 35010, "message": "Position closing too large" } - '35012': InvalidOrder, // { "code": 35012, "message": "Incorrect order size" } - '35014': InvalidOrder, // { "code": 35014, "message": "Order price is not within limit" } - '35015': InvalidOrder, // { "code": 35015, "message": "Invalid leverage level" } - '35017': ExchangeError, // { "code": 35017, "message": "Open orders exist" } - '35019': InvalidOrder, // { "code": 35019, "message": "Order size too large" } - '35020': InvalidOrder, // { "code": 35020, "message": "Order price too high" } - '35021': InvalidOrder, // { "code": 35021, "message": "Order size exceeded current tier limit" } - '35022': ExchangeError, // { "code": 35022, "message": "Contract status error" } - '35024': ExchangeError, // { "code": 35024, "message": "Contract not initialized" } - '35025': InsufficientFunds, // { "code": 35025, "message": "No account balance" } - '35026': ExchangeError, // { "code": 35026, "message": "Contract settings not initialized" } - '35029': OrderNotFound, // { "code": 35029, "message": "Order does not exist" } - '35030': InvalidOrder, // { "code": 35030, "message": "Order size too large" } - '35031': InvalidOrder, // { "code": 35031, "message": "Cancel order size too large" } - '35032': ExchangeError, // { "code": 35032, "message": "Invalid user status" } - '35039': ExchangeError, // { "code": 35039, "message": "Open order quantity exceeds limit" } - '35040': InvalidOrder, // {"error_message":"Invalid order type","result":"true","error_code":"35040","order_id":"-1"} - '35044': ExchangeError, // { "code": 35044, "message": "Invalid order status" } - '35046': InsufficientFunds, // { "code": 35046, "message": "Negative account balance" } - '35047': InsufficientFunds, // { "code": 35047, "message": "Insufficient account balance" } - '35048': ExchangeError, // { "code": 35048, "message": "User contract is frozen and liquidating" } - '35049': InvalidOrder, // { "code": 35049, "message": "Invalid order type" } - '35050': InvalidOrder, // { "code": 35050, "message": "Position settings are blank" } - '35052': InsufficientFunds, // { "code": 35052, "message": "Insufficient cross margin" } - '35053': ExchangeError, // { "code": 35053, "message": "Account risk too high" } - '35055': InsufficientFunds, // { "code": 35055, "message": "Insufficient account balance" } - '35057': ExchangeError, // { "code": 35057, "message": "No last traded price" } - '35058': ExchangeError, // { "code": 35058, "message": "No limit" } - '35059': BadRequest, // { "code": 35059, "message": "client_oid or order_id is required" } - '35060': BadRequest, // { "code": 35060, "message": "Only fill in either parameter client_oid or order_id" } - '35061': BadRequest, // { "code": 35061, "message": "Invalid instrument_id" } - '35062': InvalidOrder, // { "code": 35062, "message": "Invalid match_price" } - '35063': InvalidOrder, // { "code": 35063, "message": "Invalid order_size" } - '35064': InvalidOrder, // { "code": 35064, "message": "Invalid client_oid" } - }, - 'broad': { - }, - }, - 'options': { - 'createMarketBuyOrderRequiresPrice': true, - 'fetchMarkets': [ 'spot', 'futures', 'swap' ], - 'defaultType': 'spot', // 'account', 'spot', 'margin', 'futures', 'swap' - 'auth': { - 'time': 'public', - 'currencies': 'private', - 'instruments': 'public', - 'rate': 'public', - 'constituents/{ett}': 'public', - 'define-price/{ett}': 'public', - }, - }, - 'commonCurrencies': { - // OKEX refers to ERC20 version of Aeternity (AEToken) - 'AE': 'AET', // https://github.com/ccxt/ccxt/issues/4981 - 'HOT': 'Hydro Protocol', - 'HSR': 'HC', - 'MAG': 'Maggie', - 'YOYO': 'YOYOW', - 'WIN': 'WinToken', // https://github.com/ccxt/ccxt/issues/5701 - }, - }); - } - - async fetchTime (params = {}) { - const response = await this.generalGetTime (params); - // - // { - // "iso": "2015-01-07T23:47:25.201Z", - // "epoch": 1420674445.201 - // } - // - return this.parse8601 (this.safeString (response, 'iso')); - } - - async fetchMarkets (params = {}) { - const types = this.safeValue (this.options, 'fetchMarkets'); - let result = []; - for (let i = 0; i < types.length; i++) { - const markets = await this.fetchMarketsByType (types[i], params); - result = this.arrayConcat (result, markets); - } - return result; - } - - parseMarkets (markets) { - const result = []; - for (let i = 0; i < markets.length; i++) { - result.push (this.parseMarket (markets[i])); - } - return result; - } - - parseMarket (market) { - // - // spot markets - // - // [ { base_currency: "EOS", - // instrument_id: "EOS-OKB", - // min_size: "0.01", - // product_id: "EOS-OKB", - // quote_currency: "OKB", - // size_increment: "0.000001", - // tick_size: "0.0001" }, - // - // ..., // the spot endpoint also returns ETT instruments - // - // { base_currency: "OK06ETT", - // base_increment: "0.00000001", - // base_min_size: "0.01", - // instrument_id: "OK06ETT-USDT", - // min_size: "0.01", - // product_id: "OK06ETT-USDT", - // quote_currency: "USDT", - // quote_increment: "0.0001", - // size_increment: "0.00000001", - // tick_size: "0.0001" } ] - // - // futures markets - // - // [ { instrument_id: "BTG-USD-190329", - // underlying_index: "BTG", - // quote_currency: "USD", - // tick_size: "0.01", - // contract_val: "10", - // listing: "2018-12-14", - // delivery: "2019-03-29", - // trade_increment: "1" } ] - // - // swap markets - // - // [ { instrument_id: "BTC-USD-SWAP", - // underlying_index: "BTC", - // quote_currency: "USD", - // coin: "BTC", - // contract_val: "100", - // listing: "2018-10-23T20:11:00.443Z", - // delivery: "2018-10-24T20:11:00.443Z", - // size_increment: "4", - // tick_size: "4" } ] - // - const id = this.safeString (market, 'instrument_id'); - let marketType = 'spot'; - let spot = true; - let future = false; - let swap = false; - let baseId = this.safeString (market, 'base_currency'); - const contractVal = this.safeFloat (market, 'contract_val'); - if (contractVal !== undefined) { - marketType = 'swap'; - spot = false; - swap = true; - baseId = this.safeString (market, 'coin'); - const futuresAlias = this.safeString (market, 'alias'); - if (futuresAlias !== undefined) { - swap = false; - future = true; - marketType = 'futures'; - baseId = this.safeString (market, 'underlying_index'); - } - } - const quoteId = this.safeString (market, 'quote_currency'); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - const symbol = spot ? (base + '/' + quote) : id; - let amountPrecision = this.safeString (market, 'size_increment'); - if (amountPrecision !== undefined) { - amountPrecision = this.precisionFromString (amountPrecision); - } - let pricePrecision = this.safeString (market, 'tick_size'); - if (pricePrecision !== undefined) { - pricePrecision = this.precisionFromString (pricePrecision); - } - const precision = { - 'amount': amountPrecision, - 'price': pricePrecision, - }; - const minAmount = this.safeFloat2 (market, 'min_size', 'base_min_size'); - let minPrice = this.safeFloat (market, 'tick_size'); - if (precision['price'] !== undefined) { - minPrice = Math.pow (10, -precision['price']); - } - let minCost = undefined; - if (minAmount !== undefined && minPrice !== undefined) { - minCost = minAmount * minPrice; - } - const active = true; - const fees = this.safeValue2 (this.fees, marketType, 'trading', {}); - return this.extend (fees, { - 'id': id, - 'symbol': symbol, - 'base': base, - 'quote': quote, - 'baseId': baseId, - 'quoteId': quoteId, - 'info': market, - 'type': marketType, - 'spot': spot, - 'futures': future, - 'swap': swap, - 'active': active, - 'precision': precision, - 'limits': { - 'amount': { - 'min': minAmount, - 'max': undefined, - }, - 'price': { - 'min': minPrice, - 'max': undefined, - }, - 'cost': { - 'min': minCost, - 'max': undefined, - }, - }, - }); - } - - async fetchMarketsByType (type, params = {}) { - const method = type + 'GetInstruments'; - const response = await this[method] (params); - // - // spot markets - // - // [ { base_currency: "EOS", - // base_increment: "0.000001", - // base_min_size: "0.01", - // instrument_id: "EOS-OKB", - // min_size: "0.01", - // product_id: "EOS-OKB", - // quote_currency: "OKB", - // quote_increment: "0.0001", - // size_increment: "0.000001", - // tick_size: "0.0001" } ] - // - // futures markets - // - // [ { instrument_id: "BTG-USD-190329", - // underlying_index: "BTG", - // quote_currency: "USD", - // tick_size: "0.01", - // contract_val: "10", - // listing: "2018-12-14", - // delivery: "2019-03-29", - // trade_increment: "1" } ] - // - // swap markets - // - // [ { instrument_id: "BTC-USD-SWAP", - // underlying_index: "BTC", - // quote_currency: "USD", - // coin: "BTC", - // contract_val: "100", - // listing: "2018-10-23T20:11:00.443Z", - // delivery: "2018-10-24T20:11:00.443Z", - // size_increment: "4", - // tick_size: "4" } ] - // - return this.parseMarkets (response); - } - - async fetchCurrencies (params = {}) { - // has['fetchCurrencies'] is currently set to false - // despite that their docs say these endpoints are public: - // https://www.okex.com/api/account/v3/withdrawal/fee - // https://www.okex.com/api/account/v3/currencies - // it will still reply with { "code":30001, "message": "OK-ACCESS-KEY header is required" } - // if you attempt to access it without authentication - const response = await this.accountGetCurrencies (params); - // - // [ - // { - // name: '', - // currency: 'BTC', - // can_withdraw: '1', - // can_deposit: '1', - // min_withdrawal: '0.0100000000000000' - // }, - // ] - // - const result = {}; - for (let i = 0; i < response.length; i++) { - const currency = response[i]; - const id = this.safeString (currency, 'currency'); - const code = this.safeCurrencyCode (id); - const precision = 8; // default precision, todo: fix "magic constants" - const name = this.safeString (currency, 'name'); - const canDeposit = this.safeInteger (currency, 'can_deposit'); - const canWithdraw = this.safeInteger (currency, 'can_withdraw'); - const active = canDeposit && canWithdraw; - result[code] = { - 'id': id, - 'code': code, - 'info': currency, - 'type': undefined, - 'name': name, - 'active': active, - 'fee': undefined, // todo: redesign - 'precision': precision, - 'limits': { - 'amount': { 'min': undefined, 'max': undefined }, - 'price': { 'min': undefined, 'max': undefined }, - 'cost': { 'min': undefined, 'max': undefined }, - 'withdraw': { - 'min': this.safeFloat (currency, 'min_withdrawal'), - 'max': undefined, - }, - }, - }; - } - return result; - } - - async fetchOrderBook (symbol, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - let method = market['type'] + 'GetInstrumentsInstrumentId'; - method += (market['type'] === 'swap') ? 'Depth' : 'Book'; - const request = { - 'instrument_id': market['id'], - }; - if (limit !== undefined) { - request['size'] = limit; // max 200 - } - const response = await this[method] (this.extend (request, params)); - // - // { asks: [ ["0.02685268", "0.242571", "1"], - // ["0.02685493", "0.164085", "1"], - // ... - // ["0.02779", "1.039", "1"], - // ["0.027813", "0.0876", "1"] ], - // bids: [ ["0.02684052", "10.371849", "1"], - // ["0.02684051", "3.707", "4"], - // ... - // ["0.02634963", "0.132934", "1"], - // ["0.02634962", "0.264838", "2"] ], - // timestamp: "2018-12-17T20:24:16.159Z" } - // - const timestamp = this.parse8601 (this.safeString (response, 'timestamp')); - return this.parseOrderBook (response, timestamp); - } - - parseTicker (ticker, market = undefined) { - // - // { best_ask: "0.02665472", - // best_bid: "0.02665221", - // instrument_id: "ETH-BTC", - // product_id: "ETH-BTC", - // last: "0.02665472", - // ask: "0.02665472", // missing in the docs - // bid: "0.02665221", // not mentioned in the docs - // open_24h: "0.02645482", - // high_24h: "0.02714633", - // low_24h: "0.02614109", - // base_volume_24h: "572298.901923", - // timestamp: "2018-12-17T21:20:07.856Z", - // quote_volume_24h: "15094.86831261" } - // - const timestamp = this.parse8601 (this.safeString (ticker, 'timestamp')); - let symbol = undefined; - const marketId = this.safeString (ticker, 'instrument_id'); - if (marketId in this.markets_by_id) { - market = this.markets_by_id[marketId]; - } else if (marketId !== undefined) { - const parts = marketId.split ('-'); - const numParts = parts.length; - if (numParts === 2) { - const [ baseId, quoteId ] = parts; - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - symbol = base + '/' + quote; - } else { - symbol = marketId; - } - } - if (market !== undefined) { - symbol = market['symbol']; - } - const last = this.safeFloat (ticker, 'last'); - const open = this.safeFloat (ticker, 'open_24h'); - return { - 'symbol': symbol, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'high': this.safeFloat (ticker, 'high_24h'), - 'low': this.safeFloat (ticker, 'low_24h'), - 'bid': this.safeFloat (ticker, 'best_bid'), - 'bidVolume': undefined, - 'ask': this.safeFloat (ticker, 'best_ask'), - 'askVolume': undefined, - 'vwap': undefined, - 'open': open, - 'close': last, - 'last': last, - 'previousClose': undefined, - 'change': undefined, - 'percentage': undefined, - 'average': undefined, - 'baseVolume': this.safeFloat (ticker, 'base_volume_24h'), - 'quoteVolume': this.safeFloat (ticker, 'quote_volume_24h'), - 'info': ticker, - }; - } - - async fetchTicker (symbol, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['type'] + 'GetInstrumentsInstrumentIdTicker'; - const request = { - 'instrument_id': market['id'], - }; - const response = await this[method] (this.extend (request, params)); - // - // { best_ask: "0.02665472", - // best_bid: "0.02665221", - // instrument_id: "ETH-BTC", - // product_id: "ETH-BTC", - // last: "0.02665472", - // ask: "0.02665472", - // bid: "0.02665221", - // open_24h: "0.02645482", - // high_24h: "0.02714633", - // low_24h: "0.02614109", - // base_volume_24h: "572298.901923", - // timestamp: "2018-12-17T21:20:07.856Z", - // quote_volume_24h: "15094.86831261" } - // - return this.parseTicker (response); - } - - async fetchTickersByType (type, symbols = undefined, params = {}) { - await this.loadMarkets (); - const method = type + 'GetInstrumentsTicker'; - const response = await this[method] (params); - const result = {}; - for (let i = 0; i < response.length; i++) { - const ticker = this.parseTicker (response[i]); - const symbol = ticker['symbol']; - result[symbol] = ticker; - } - return result; - } - - async fetchTickers (symbols = undefined, params = {}) { - const defaultType = this.safeString2 (this.options, 'fetchTickers', 'defaultType'); - const type = this.safeString (params, 'type', defaultType); - return await this.fetchTickersByType (type, symbols, this.omit (params, 'type')); - } - - parseTrade (trade, market = undefined) { - // - // fetchTrades (public) - // - // spot trades - // - // { - // time: "2018-12-17T23:31:08.268Z", - // timestamp: "2018-12-17T23:31:08.268Z", - // trade_id: "409687906", - // price: "0.02677805", - // size: "0.923467", - // side: "sell" - // } - // - // futures trades, swap trades - // - // { - // trade_id: "1989230840021013", - // side: "buy", - // price: "92.42", - // qty: "184", // missing in swap markets - // size: "5", // missing in futures markets - // timestamp: "2018-12-17T23:26:04.613Z" - // } - // - // fetchOrderTrades (private) - // - // spot trades, margin trades - // - // { - // "created_at":"2019-03-15T02:52:56.000Z", - // "exec_type":"T", // whether the order is taker or maker - // "fee":"0.00000082", - // "instrument_id":"BTC-USDT", - // "ledger_id":"3963052721", - // "liquidity":"T", // whether the order is taker or maker - // "order_id":"2482659399697408", - // "price":"3888.6", - // "product_id":"BTC-USDT", - // "side":"buy", - // "size":"0.00055306", - // "timestamp":"2019-03-15T02:52:56.000Z" - // }, - // - // futures trades, swap trades - // - // { - // "trade_id":"197429674631450625", - // "instrument_id":"EOS-USD-SWAP", - // "order_id":"6a-7-54d663a28-0", - // "price":"3.633", - // "order_qty":"1.0000", - // "fee":"-0.000551", - // "created_at":"2019-03-21T04:41:58.0Z", // missing in swap trades - // "timestamp":"2019-03-25T05:56:31.287Z", // missing in futures trades - // "exec_type":"M", // whether the order is taker or maker - // "side":"short", // "buy" in futures trades - // } - // - let symbol = undefined; - if (market !== undefined) { - symbol = market['symbol']; - } - const timestamp = this.parse8601 (this.safeString2 (trade, 'timestamp', 'created_at')); - const price = this.safeFloat (trade, 'price'); - let amount = this.safeFloat2 (trade, 'size', 'qty'); - amount = this.safeFloat (trade, 'order_qty', amount); - let takerOrMaker = this.safeString2 (trade, 'exec_type', 'liquidity'); - if (takerOrMaker === 'M') { - takerOrMaker = 'maker'; - } else if (takerOrMaker === 'T') { - takerOrMaker = 'taker'; - } - const side = this.safeString (trade, 'side'); - let cost = undefined; - if (amount !== undefined) { - if (price !== undefined) { - cost = amount * price; - } - } - const feeCost = this.safeFloat (trade, 'fee'); - let fee = undefined; - if (feeCost !== undefined) { - let feeCurrency = undefined; - if (market !== undefined) { - feeCurrency = (side === 'buy') ? market['base'] : market['quote']; - } - fee = { - // fee is either a positive number (invitation rebate) - // or a negative number (transaction fee deduction) - // therefore we need to invert the fee - // more about it https://github.com/ccxt/ccxt/issues/5909 - 'cost': -feeCost, - 'currency': feeCurrency, - }; - } - const orderId = this.safeString (trade, 'order_id'); - return { - 'info': trade, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': symbol, - 'id': this.safeString2 (trade, 'trade_id', 'ledger_id'), - 'order': orderId, - 'type': undefined, - 'takerOrMaker': takerOrMaker, - 'side': side, - 'price': price, - 'amount': amount, - 'cost': cost, - 'fee': fee, - }; - } - - async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['type'] + 'GetInstrumentsInstrumentIdTrades'; - if ((limit === undefined) || (limit > 100)) { - limit = 100; // maximum = default = 100 - } - const request = { - 'instrument_id': market['id'], - 'limit': limit, - // from: 'id', - // to: 'id', - }; - const response = await this[method] (this.extend (request, params)); - // - // spot markets - // - // [ - // { - // time: "2018-12-17T23:31:08.268Z", - // timestamp: "2018-12-17T23:31:08.268Z", - // trade_id: "409687906", - // price: "0.02677805", - // size: "0.923467", - // side: "sell" - // } - // ] - // - // futures markets, swap markets - // - // [ - // { - // trade_id: "1989230840021013", - // side: "buy", - // price: "92.42", - // qty: "184", // missing in swap markets - // size: "5", // missing in futures markets - // timestamp: "2018-12-17T23:26:04.613Z" - // } - // ] - // - return this.parseTrades (response, market, since, limit); - } - - parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) { - // - // spot markets - // - // { - // close: "0.02684545", - // high: "0.02685084", - // low: "0.02683312", - // open: "0.02683894", - // time: "2018-12-17T20:28:00.000Z", - // volume: "101.457222" - // } - // - // futures markets - // - // [ - // 1545072720000, - // 0.3159, - // 0.3161, - // 0.3144, - // 0.3149, - // 22886, - // 725179.26172331, - // ] - // - if (Array.isArray (ohlcv)) { - const numElements = ohlcv.length; - const volumeIndex = (numElements > 6) ? 6 : 5; - let timestamp = ohlcv[0]; - if (typeof timestamp === 'string') { - timestamp = this.parse8601 (timestamp); - } - return [ - timestamp, // timestamp - parseFloat (ohlcv[1]), // Open - parseFloat (ohlcv[2]), // High - parseFloat (ohlcv[3]), // Low - parseFloat (ohlcv[4]), // Close - // parseFloat (ohlcv[5]), // Quote Volume - // parseFloat (ohlcv[6]), // Base Volume - parseFloat (ohlcv[volumeIndex]), // Volume, okex will return base volume in the 7th element for future markets - ]; - } else { - return [ - this.parse8601 (this.safeString (ohlcv, 'time')), - this.safeFloat (ohlcv, 'open'), // Open - this.safeFloat (ohlcv, 'high'), // High - this.safeFloat (ohlcv, 'low'), // Low - this.safeFloat (ohlcv, 'close'), // Close - this.safeFloat (ohlcv, 'volume'), // Base Volume - ]; - } - } - - async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - const method = market['type'] + 'GetInstrumentsInstrumentIdCandles'; - const request = { - 'instrument_id': market['id'], - 'granularity': this.timeframes[timeframe], - }; - if (since !== undefined) { - request['start'] = this.iso8601 (since); - } - const response = await this[method] (this.extend (request, params)); - // - // spot markets - // - // [ { close: "0.02683401", - // high: "0.02683401", - // low: "0.02683401", - // open: "0.02683401", - // time: "2018-12-17T23:47:00.000Z", - // volume: "0" }, - // ... - // { close: "0.02684545", - // high: "0.02685084", - // low: "0.02683312", - // open: "0.02683894", - // time: "2018-12-17T20:28:00.000Z", - // volume: "101.457222" } ] - // - // futures - // - // [ [ 1545090660000, - // 0.3171, - // 0.3174, - // 0.3171, - // 0.3173, - // 1648, - // 51930.38579450868 ], - // ... - // [ 1545072720000, - // 0.3159, - // 0.3161, - // 0.3144, - // 0.3149, - // 22886, - // 725179.26172331 ] ] - // - return this.parseOHLCVs (response, market, timeframe, since, limit); - } - - parseAccountBalance (response) { - // - // account - // - // [ - // { - // balance: 0, - // available: 0, - // currency: "BTC", - // hold: 0 - // }, - // { - // balance: 0, - // available: 0, - // currency: "ETH", - // hold: 0 - // } - // ] - // - // spot - // - // [ - // { - // frozen: "0", - // hold: "0", - // id: "2149632", - // currency: "BTC", - // balance: "0.0000000497717339", - // available: "0.0000000497717339", - // holds: "0" - // }, - // { - // frozen: "0", - // hold: "0", - // id: "2149632", - // currency: "ICN", - // balance: "0.00000000925", - // available: "0.00000000925", - // holds: "0" - // } - // ] - // - const result = { 'info': response }; - for (let i = 0; i < response.length; i++) { - const balance = response[i]; - const currencyId = this.safeString (balance, 'currency'); - const code = this.safeCurrencyCode (currencyId); - const account = this.account (); - account['total'] = this.safeFloat (balance, 'balance'); - account['used'] = this.safeFloat (balance, 'hold'); - account['free'] = this.safeFloat (balance, 'available'); - result[code] = account; - } - return this.parseBalance (result); - } - - parseMarginBalance (response) { - // - // [ - // { - // "currency:BTC": { - // "available":"0", - // "balance":"0", - // "borrowed":"0", - // "can_withdraw":"0", - // "frozen":"0", - // "hold":"0", - // "holds":"0", - // "lending_fee":"0" - // }, - // "currency:USDT": { - // "available":"100", - // "balance":"100", - // "borrowed":"0", - // "can_withdraw":"100", - // "frozen":"0", - // "hold":"0", - // "holds":"0", - // "lending_fee":"0" - // }, - // "instrument_id":"BTC-USDT", - // "liquidation_price":"0", - // "product_id":"BTC-USDT", - // "risk_rate":"" - // }, - // ] - // - const result = { 'info': response }; - for (let i = 0; i < response.length; i++) { - const balance = response[i]; - const marketId = this.safeString (balance, 'instrument_id'); - const market = this.safeValue (this.markets_by_id, marketId); - let symbol = undefined; - if (market === undefined) { - const [ baseId, quoteId ] = marketId.split ('-'); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - symbol = base + '/' + quote; - } else { - symbol = market['symbol']; - } - const omittedBalance = this.omit (balance, [ - 'instrument_id', - 'liquidation_price', - 'product_id', - 'risk_rate', - 'margin_ratio', - 'maint_margin_ratio', - 'tiers', - ]); - const keys = Object.keys (omittedBalance); - const accounts = {}; - for (let k = 0; k < keys.length; k++) { - const key = keys[k]; - const marketBalance = balance[key]; - if (key.indexOf (':') >= 0) { - const parts = key.split (':'); - const currencyId = parts[1]; - const code = this.safeCurrencyCode (currencyId); - const account = this.account (); - account['total'] = this.safeFloat (marketBalance, 'balance'); - account['used'] = this.safeFloat (marketBalance, 'hold'); - account['free'] = this.safeFloat (marketBalance, 'available'); - accounts[code] = account; - } else { - throw new NotSupported (this.id + ' margin balance response format has changed!'); - } - } - result[symbol] = this.parseBalance (accounts); - } - return result; - } - - parseFuturesBalance (response) { - // - // { - // "info":{ - // "eos":{ - // "auto_margin":"0", - // "contracts": [ - // { - // "available_qty":"40.37069445", - // "fixed_balance":"0", - // "instrument_id":"EOS-USD-190329", - // "margin_for_unfilled":"0", - // "margin_frozen":"0", - // "realized_pnl":"0", - // "unrealized_pnl":"0" - // }, - // { - // "available_qty":"40.37069445", - // "fixed_balance":"14.54895721", - // "instrument_id":"EOS-USD-190628", - // "margin_for_unfilled":"0", - // "margin_frozen":"10.64042157", - // "realized_pnl":"-3.90853564", - // "unrealized_pnl":"-0.259" - // }, - // ], - // "equity":"50.75220665", - // "margin_mode":"fixed", - // "total_avail_balance":"40.37069445" - // }, - // } - // } - // - // their root field name is "info", so our info will contain their info - const result = { 'info': response }; - const info = this.safeValue (response, 'info', {}); - const ids = Object.keys (info); - for (let i = 0; i < ids.length; i++) { - const id = ids[i]; - const code = this.safeCurrencyCode (id); - const balance = this.safeValue (info, id, {}); - const account = this.account (); - // it may be incorrect to use total, free and used for swap accounts - account['total'] = this.safeFloat (balance, 'equity'); - account['free'] = this.safeFloat (balance, 'total_avail_balance'); - result[code] = account; - } - return this.parseBalance (result); - } - - parseSwapBalance (response) { - // - // { - // "info": [ - // { - // "equity":"3.0139", - // "fixed_balance":"0.0000", - // "instrument_id":"EOS-USD-SWAP", - // "margin":"0.5523", - // "margin_frozen":"0.0000", - // "margin_mode":"crossed", - // "margin_ratio":"1.0913", - // "realized_pnl":"-0.0006", - // "timestamp":"2019-03-25T03:46:10.336Z", - // "total_avail_balance":"3.0000", - // "unrealized_pnl":"0.0145" - // } - // ] - // } - // - // their root field name is "info", so our info will contain their info - const result = { 'info': response }; - const info = this.safeValue (response, 'info', []); - for (let i = 0; i < info.length; i++) { - const balance = info[i]; - const marketId = this.safeString (balance, 'instrument_id'); - let symbol = marketId; - if (marketId in this.markets_by_id) { - symbol = this.markets_by_id[marketId]['symbol']; - } - const account = this.account (); - // it may be incorrect to use total, free and used for swap accounts - account['total'] = this.safeFloat (balance, 'equity'); - account['free'] = this.safeFloat (balance, 'total_avail_balance'); - result[symbol] = account; - } - return this.parseBalance (result); - } - - async fetchBalance (params = {}) { - await this.loadMarkets (); - const defaultType = this.safeString2 (this.options, 'fetchBalance', 'defaultType'); - const type = this.safeString (params, 'type', defaultType); - if (type === undefined) { - throw new ArgumentsRequired (this.id + " fetchBalance requires a type parameter (one of 'account', 'spot', 'margin', 'futures', 'swap')"); - } - const suffix = (type === 'account') ? 'Wallet' : 'Accounts'; - const method = type + 'Get' + suffix; - const query = this.omit (params, 'type'); - const response = await this[method] (query); - // - // account - // - // [ - // { - // balance: 0, - // available: 0, - // currency: "BTC", - // hold: 0 - // }, - // { - // balance: 0, - // available: 0, - // currency: "ETH", - // hold: 0 - // } - // ] - // - // spot - // - // [ - // { - // frozen: "0", - // hold: "0", - // id: "2149632", - // currency: "BTC", - // balance: "0.0000000497717339", - // available: "0.0000000497717339", - // holds: "0" - // }, - // { - // frozen: "0", - // hold: "0", - // id: "2149632", - // currency: "ICN", - // balance: "0.00000000925", - // available: "0.00000000925", - // holds: "0" - // } - // ] - // - // margin - // - // [ - // { - // "currency:BTC": { - // "available":"0", - // "balance":"0", - // "borrowed":"0", - // "can_withdraw":"0", - // "frozen":"0", - // "hold":"0", - // "holds":"0", - // "lending_fee":"0" - // }, - // "currency:USDT": { - // "available":"100", - // "balance":"100", - // "borrowed":"0", - // "can_withdraw":"100", - // "frozen":"0", - // "hold":"0", - // "holds":"0", - // "lending_fee":"0" - // }, - // "instrument_id":"BTC-USDT", - // "liquidation_price":"0", - // "product_id":"BTC-USDT", - // "risk_rate":"" - // }, - // ] - // - // futures - // - // { - // "info":{ - // "eos":{ - // "auto_margin":"0", - // "contracts": [ - // { - // "available_qty":"40.37069445", - // "fixed_balance":"0", - // "instrument_id":"EOS-USD-190329", - // "margin_for_unfilled":"0", - // "margin_frozen":"0", - // "realized_pnl":"0", - // "unrealized_pnl":"0" - // }, - // { - // "available_qty":"40.37069445", - // "fixed_balance":"14.54895721", - // "instrument_id":"EOS-USD-190628", - // "margin_for_unfilled":"0", - // "margin_frozen":"10.64042157", - // "realized_pnl":"-3.90853564", - // "unrealized_pnl":"-0.259" - // }, - // ], - // "equity":"50.75220665", - // "margin_mode":"fixed", - // "total_avail_balance":"40.37069445" - // }, - // } - // } - // - // swap - // - // { - // "info": [ - // { - // "equity":"3.0139", - // "fixed_balance":"0.0000", - // "instrument_id":"EOS-USD-SWAP", - // "margin":"0.5523", - // "margin_frozen":"0.0000", - // "margin_mode":"crossed", - // "margin_ratio":"1.0913", - // "realized_pnl":"-0.0006", - // "timestamp":"2019-03-25T03:46:10.336Z", - // "total_avail_balance":"3.0000", - // "unrealized_pnl":"0.0145" - // } - // ] - // } - // - if ((type === 'account') || (type === 'spot')) { - return this.parseAccountBalance (response); - } else if (type === 'margin') { - return this.parseMarginBalance (response); - } else if (type === 'futures') { - return this.parseFuturesBalance (response); - } else if (type === 'swap') { - return this.parseSwapBalance (response); - } - throw new NotSupported (this.id + " fetchBalance does not support the '" + type + "' type (the type must be one of 'account', 'spot', 'margin', 'futures', 'swap')"); - } - - async createOrder (symbol, type, side, amount, price = undefined, params = {}) { - await this.loadMarkets (); - const market = this.market (symbol); - let request = { - 'instrument_id': market['id'], - // 'client_oid': 'abcdef1234567890', // [a-z0-9]{1,32} - // 'order_type': '0', // 0: Normal limit order (Unfilled and 0 represent normal limit order) 1: Post only 2: Fill Or Kill 3: Immediatel Or Cancel - }; - let method = undefined; - if (market['futures'] || market['swap']) { - const size = market['futures'] ? this.numberToString (amount) : this.amountToPrecision (symbol, amount); - request = this.extend (request, { - 'type': type, // 1:open long 2:open short 3:close long 4:close short for futures - 'size': size, - 'price': this.priceToPrecision (symbol, price), - // 'match_price': '0', // Order at best counter party price? (0:no 1:yes). The default is 0. If it is set as 1, the price parameter will be ignored. When posting orders at best bid price, order_type can only be 0 (regular order). - }); - if (market['futures']) { - request['leverage'] = '10'; // or '20' - } - method = market['type'] + 'PostOrder'; - } else { - const marginTrading = this.safeString (params, 'margin_trading', '1'); // 1 = spot, 2 = margin - request = this.extend (request, { - 'side': side, - 'type': type, // limit/market - 'margin_trading': marginTrading, // 1 = spot, 2 = margin - }); - if (type === 'limit') { - request['price'] = this.priceToPrecision (symbol, price); - request['size'] = this.amountToPrecision (symbol, amount); - } else if (type === 'market') { - // for market buy it requires the amount of quote currency to spend - if (side === 'buy') { - let notional = this.safeFloat (params, 'notional'); - const createMarketBuyOrderRequiresPrice = this.safeValue (this.options, 'createMarketBuyOrderRequiresPrice', true); - if (createMarketBuyOrderRequiresPrice) { - if (price !== undefined) { - if (notional === undefined) { - notional = amount * price; - } - } else if (notional === undefined) { - throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'notional' extra parameter (the exchange-specific behaviour)"); - } - } - request['notional'] = this.costToPrecision (symbol, notional); - } else { - request['size'] = this.amountToPrecision (symbol, amount); - } - } - method = (marginTrading === '2') ? 'marginPostOrders' : 'spotPostOrders'; - } - const response = await this[method] (this.extend (request, params)); - // - // { - // "client_oid":"oktspot79", - // "error_code":"", - // "error_message":"", - // "order_id":"2510789768709120", - // "result":true - // } - // - const timestamp = this.milliseconds (); - const id = this.safeString (response, 'order_id'); - return { - 'info': response, - 'id': id, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'lastTradeTimestamp': undefined, - 'status': undefined, - 'symbol': symbol, - 'type': type, - 'side': side, - 'price': price, - 'amount': amount, - 'filled': undefined, - 'remaining': undefined, - 'cost': undefined, - 'trades': undefined, - 'fee': undefined, - }; - } - - async cancelOrder (id, symbol = undefined, params = {}) { - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument'); - } - await this.loadMarkets (); - const market = this.market (symbol); - const type = market['type']; - let method = type + 'PostCancelOrder'; - const request = { - 'instrument_id': market['id'], - }; - if (market['futures'] || market['swap']) { - method += 'InstrumentId'; - } else { - method += 's'; - } - const clientOid = this.safeString (params, 'client_oid'); - if (clientOid !== undefined) { - method += 'ClientOid'; - request['client_oid'] = clientOid; - } else { - method += 'OrderId'; - request['order_id'] = id; - } - const query = this.omit (params, 'type'); - const response = await this[method] (this.extend (request, query)); - const result = ('result' in response) ? response : this.safeValue (response, market['id'], {}); - // - // spot, margin - // - // { - // "btc-usdt": [ - // { - // "result":true, - // "client_oid":"a123", - // "order_id": "2510832677225473" - // } - // ] - // } - // - // futures, swap - // - // { - // "result": true, - // "client_oid": "oktfuture10", // missing if requested by order_id - // "order_id": "2517535534836736", - // "instrument_id": "EOS-USD-190628" - // } - // - return this.parseOrder (result, market); - } - - parseOrderStatus (status) { - const statuses = { - '-2': 'failed', - '-1': 'canceled', - '0': 'open', - '1': 'open', - '2': 'closed', - '3': 'open', - '4': 'canceled', - }; - return this.safeString (statuses, status, status); - } - - parseOrderSide (side) { - const sides = { - '1': 'buy', // open long - '2': 'sell', // open short - '3': 'sell', // close long - '4': 'buy', // close short - }; - return this.safeString (sides, side, side); - } - - parseOrder (order, market = undefined) { - // - // createOrder - // - // { - // "client_oid":"oktspot79", - // "error_code":"", - // "error_message":"", - // "order_id":"2510789768709120", - // "result":true - // } - // - // cancelOrder - // - // { - // "result": true, - // "client_oid": "oktfuture10", // missing if requested by order_id - // "order_id": "2517535534836736", - // // instrument_id is missing for spot/margin orders - // // available in futures and swap orders only - // "instrument_id": "EOS-USD-190628", - // } - // - // fetchOrder, fetchOrdersByState, fetchOpenOrders, fetchClosedOrders - // - // // spot and margin orders - // - // { - // "client_oid":"oktspot76", - // "created_at":"2019-03-18T07:26:49.000Z", - // "filled_notional":"3.9734", - // "filled_size":"0.001", // filled_qty in futures and swap orders - // "funds":"", // this is most likely the same as notional - // "instrument_id":"BTC-USDT", - // "notional":"", - // "order_id":"2500723297813504", - // "order_type":"0", - // "price":"4013", - // "product_id":"BTC-USDT", // missing in futures and swap orders - // "side":"buy", - // "size":"0.001", - // "status":"filled", - // "state": "2", - // "timestamp":"2019-03-18T07:26:49.000Z", - // "type":"limit" - // } - // - // // futures and swap orders - // - // { - // "instrument_id":"EOS-USD-190628", - // "size":"10", - // "timestamp":"2019-03-20T10:04:55.000Z", - // "filled_qty":"10", // filled_size in spot and margin orders - // "fee":"-0.00841043", - // "order_id":"2512669605501952", - // "price":"3.668", - // "price_avg":"3.567", // missing in spot and margin orders - // "status":"2", - // "state": "2", - // "type":"4", - // "contract_val":"10", - // "leverage":"10", // missing in swap, spot and margin orders - // "client_oid":"", - // "pnl":"1.09510794", // missing in swap, spo and margin orders - // "order_type":"0" - // } - // - const id = this.safeString (order, 'order_id'); - const timestamp = this.parse8601 (this.safeString (order, 'timestamp')); - let side = this.safeString (order, 'side'); - let type = this.safeString (order, 'type'); - if ((side !== 'buy') && (side !== 'sell')) { - side = this.parseOrderSide (type); - } - if ((type !== 'limit') && (type !== 'market')) { - if ('pnl' in order) { - type = 'futures'; - } else { - type = 'swap'; - } - } - let symbol = undefined; - const marketId = this.safeString (order, 'instrument_id'); - if (marketId in this.markets_by_id) { - market = this.markets_by_id[marketId]; - symbol = market['symbol']; - } else { - symbol = marketId; - } - if (market !== undefined) { - if (symbol === undefined) { - symbol = market['symbol']; - } - } - let amount = this.safeFloat (order, 'size'); - const filled = this.safeFloat2 (order, 'filled_size', 'filled_qty'); - let remaining = undefined; - if (amount !== undefined) { - if (filled !== undefined) { - amount = Math.max (amount, filled); - remaining = Math.max (0, amount - filled); - } - } - if (type === 'market') { - remaining = 0; - } - let cost = this.safeFloat2 (order, 'filled_notional', 'funds'); - const price = this.safeFloat (order, 'price'); - let average = this.safeFloat (order, 'price_avg'); - if (cost === undefined) { - if (filled !== undefined && average !== undefined) { - cost = average * filled; - } - } else { - if ((average === undefined) && (filled !== undefined) && (filled > 0)) { - average = cost / filled; - } - } - const status = this.parseOrderStatus (this.safeString (order, 'state')); - const feeCost = this.safeFloat (order, 'fee'); - let fee = undefined; - if (feeCost !== undefined) { - const feeCurrency = undefined; - fee = { - 'cost': feeCost, - 'currency': feeCurrency, - }; - } - return { - 'info': order, - 'id': id, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'lastTradeTimestamp': undefined, - 'symbol': symbol, - 'type': type, - 'side': side, - 'price': price, - 'average': average, - 'cost': cost, - 'amount': amount, - 'filled': filled, - 'remaining': remaining, - 'status': status, - 'fee': fee, - }; - } - - async fetchOrder (id, symbol = undefined, params = {}) { - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument'); - } - await this.loadMarkets (); - const market = this.market (symbol); - const defaultType = this.safeString2 (this.options, 'fetchOrder', 'defaultType', market['type']); - const type = this.safeString (params, 'type', defaultType); - if (type === undefined) { - throw new ArgumentsRequired (this.id + " fetchOrder requires a type parameter (one of 'spot', 'margin', 'futures', 'swap')."); - } - const instrumentId = (market['futures'] || market['swap']) ? 'InstrumentId' : ''; - let method = type + 'GetOrders' + instrumentId; - const request = { - 'instrument_id': market['id'], - // 'client_oid': 'abcdef12345', // optional, [a-z0-9]{1,32} - // 'order_id': id, - }; - const clientOid = this.safeString (params, 'client_oid'); - if (clientOid !== undefined) { - method += 'ClientOid'; - request['client_oid'] = clientOid; - } else { - method += 'OrderId'; - request['order_id'] = id; - } - const query = this.omit (params, 'type'); - const response = await this[method] (this.extend (request, query)); - // - // spot, margin - // - // { - // "client_oid":"oktspot70", - // "created_at":"2019-03-15T02:52:56.000Z", - // "filled_notional":"3.8886", - // "filled_size":"0.001", - // "funds":"", - // "instrument_id":"BTC-USDT", - // "notional":"", - // "order_id":"2482659399697408", - // "order_type":"0", - // "price":"3927.3", - // "product_id":"BTC-USDT", - // "side":"buy", - // "size":"0.001", - // "status":"filled", - // "state": "2", - // "timestamp":"2019-03-15T02:52:56.000Z", - // "type":"limit" - // } - // - // futures, swap - // - // { - // "instrument_id":"EOS-USD-190628", - // "size":"10", - // "timestamp":"2019-03-20T02:46:38.000Z", - // "filled_qty":"10", - // "fee":"-0.0080819", - // "order_id":"2510946213248000", - // "price":"3.712", - // "price_avg":"3.712", - // "status":"2", - // "state": "2", - // "type":"2", - // "contract_val":"10", - // "leverage":"10", - // "client_oid":"", // missing in swap orders - // "pnl":"0", // missing in swap orders - // "order_type":"0" - // } - // - return this.parseOrder (response); - } - - async fetchOrdersByState (state, symbol = undefined, since = undefined, limit = undefined, params = {}) { - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchOrdersByState requires a symbol argument'); - } - await this.loadMarkets (); - const market = this.market (symbol); - const type = market['type']; - const request = { - 'instrument_id': market['id'], - // '-2': failed, - // '-1': cancelled, - // '0': open , - // '1': partially filled, - // '2': fully filled, - // '3': submitting, - // '4': cancelling, - // '6': incomplete(open+partially filled), - // '7': complete(cancelled+fully filled), - 'state': state, - }; - let method = type + 'GetOrders'; - if (market['futures'] || market['swap']) { - method += 'InstrumentId'; - } - const query = this.omit (params, 'type'); - const response = await this[method] (this.extend (request, query)); - // - // spot, margin - // - // [ - // // in fact, this documented API response does not correspond - // // to their actual API response for spot markets - // // OKEX v3 API returns a plain array of orders (see below) - // [ - // { - // "client_oid":"oktspot76", - // "created_at":"2019-03-18T07:26:49.000Z", - // "filled_notional":"3.9734", - // "filled_size":"0.001", - // "funds":"", - // "instrument_id":"BTC-USDT", - // "notional":"", - // "order_id":"2500723297813504", - // "order_type":"0", - // "price":"4013", - // "product_id":"BTC-USDT", - // "side":"buy", - // "size":"0.001", - // "status":"filled", - // "state": "2", - // "timestamp":"2019-03-18T07:26:49.000Z", - // "type":"limit" - // }, - // ], - // { - // "before":"2500723297813504", - // "after":"2500650881647616" - // } - // ] - // - // futures, swap - // - // { - // "result":true, // missing in swap orders - // "order_info": [ - // { - // "instrument_id":"EOS-USD-190628", - // "size":"10", - // "timestamp":"2019-03-20T10:04:55.000Z", - // "filled_qty":"10", - // "fee":"-0.00841043", - // "order_id":"2512669605501952", - // "price":"3.668", - // "price_avg":"3.567", - // "status":"2", - // "state": "2", - // "type":"4", - // "contract_val":"10", - // "leverage":"10", // missing in swap orders - // "client_oid":"", - // "pnl":"1.09510794", // missing in swap orders - // "order_type":"0" - // }, - // ] - // } - // - let orders = undefined; - if (market['type'] === 'swap' || market['type'] === 'futures') { - orders = this.safeValue (response, 'order_info', []); - } else { - orders = response; - const responseLength = response.length; - if (responseLength < 1) { - return []; - } - // in fact, this documented API response does not correspond - // to their actual API response for spot markets - // OKEX v3 API returns a plain array of orders - if (responseLength > 1) { - const before = this.safeValue (response[1], 'before'); - if (before !== undefined) { - orders = response[0]; - } - } - } - return this.parseOrders (orders, market, since, limit); - } - - async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - // '-2': failed, - // '-1': cancelled, - // '0': open , - // '1': partially filled, - // '2': fully filled, - // '3': submitting, - // '4': cancelling, - // '6': incomplete(open+partially filled), - // '7': complete(cancelled+fully filled), - return await this.fetchOrdersByState ('6', symbol, since, limit, params); - } - - async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { - // '-2': failed, - // '-1': cancelled, - // '0': open , - // '1': partially filled, - // '2': fully filled, - // '3': submitting, - // '4': cancelling, - // '6': incomplete(open+partially filled), - // '7': complete(cancelled+fully filled), - return await this.fetchOrdersByState ('7', symbol, since, limit, params); - } - - parseDepositAddresses (addresses) { - const result = []; - for (let i = 0; i < addresses.length; i++) { - result.push (this.parseDepositAddress (addresses[i])); - } - return result; - } - - parseDepositAddress (depositAddress, currency = undefined) { - // - // { - // address: '0x696abb81974a8793352cbd33aadcf78eda3cfdfa', - // currency: 'eth' - // tag: 'abcde12345', // will be missing if the token does not require a deposit tag - // payment_id: 'abcde12345', // will not be returned if the token does not require a payment_id - // // can_deposit: 1, // 0 or 1, documented but missing - // // can_withdraw: 1, // 0 or 1, documented but missing - // } - // - const address = this.safeString (depositAddress, 'address'); - let tag = this.safeString2 (depositAddress, 'tag', 'payment_id'); - tag = this.safeString (depositAddress, 'memo', tag); - const currencyId = this.safeString (depositAddress, 'currency'); - const code = this.safeCurrencyCode (currencyId); - this.checkAddress (address); - return { - 'currency': code, - 'address': address, - 'tag': tag, - 'info': depositAddress, - }; - } - - async fetchDepositAddress (code, params = {}) { - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'currency': currency['id'], - }; - const response = await this.accountGetDepositAddress (this.extend (request, params)); - // - // [ - // { - // address: '0x696abb81974a8793352cbd33aadcf78eda3cfdfa', - // currency: 'eth' - // } - // ] - // - const addresses = this.parseDepositAddresses (response); - const numAddresses = addresses.length; - if (numAddresses < 1) { - throw new InvalidAddress (this.id + ' fetchDepositAddress cannot return nonexistent addresses, you should create withdrawal addresses with the exchange website first'); - } - return addresses[0]; - } - - async withdraw (code, amount, address, tag = undefined, params = {}) { - this.checkAddress (address); - await this.loadMarkets (); - const currency = this.currency (code); - if (tag) { - address = address + ':' + tag; - } - const fee = this.safeString (params, 'fee'); - if (fee === undefined) { - throw new ExchangeError (this.id + " withdraw() requires a `fee` string parameter, network transaction fee must be ≥ 0. Withdrawals to OKCoin or OKEx are fee-free, please set '0'. Withdrawing to external digital asset address requires network transaction fee."); - } - const request = { - 'currency': currency['id'], - 'to_address': address, - 'destination': '4', // 2 = OKCoin International, 3 = OKEx 4 = others - 'amount': this.numberToString (amount), - 'fee': fee, // String. Network transaction fee ≥ 0. Withdrawals to OKCoin or OKEx are fee-free, please set as 0. Withdrawal to external digital asset address requires network transaction fee. - }; - if ('password' in params) { - request['trade_pwd'] = params['password']; - } else if ('trade_pwd' in params) { - request['trade_pwd'] = params['trade_pwd']; - } else if (this.password) { - request['trade_pwd'] = this.password; - } - const query = this.omit (params, [ 'fee', 'password', 'trade_pwd' ]); - if (!('trade_pwd' in request)) { - throw new ExchangeError (this.id + ' withdraw() requires this.password set on the exchange instance or a password / trade_pwd parameter'); - } - const response = await this.accountPostWithdrawal (this.extend (request, query)); - // - // { - // "amount":"0.1", - // "withdrawal_id":"67485", - // "currency":"btc", - // "result":true - // } - // - return { - 'info': response, - 'id': this.safeString (response, 'withdrawal_id'), - }; - } - - async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const request = {}; - let method = 'accountGetDepositHistory'; - let currency = undefined; - if (code !== undefined) { - currency = this.currency (code); - request['code'] = currency['code']; - method += 'Currency'; - } - const response = await this[method] (this.extend (request, params)); - return this.parseTransactions (response, currency, since, limit, params); - } - - async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const request = {}; - let method = 'accountGetWithdrawalHistory'; - let currency = undefined; - if (code !== undefined) { - currency = this.currency (code); - request['code'] = currency['code']; - method += 'Currency'; - } - const response = await this[method] (this.extend (request, params)); - return this.parseTransactions (response, currency, since, limit, params); - } - - parseTransactionStatus (status) { - // - // deposit statuses - // - // { - // '0': 'waiting for confirmation', - // '1': 'confirmation account', - // '2': 'recharge success' - // } - // - // withdrawal statues - // - // { - // '-3': 'pending cancel', - // '-2': 'cancelled', - // '-1': 'failed', - // '0': 'pending', - // '1': 'sending', - // '2': 'sent', - // '3': 'email confirmation', - // '4': 'manual confirmation', - // '5': 'awaiting identity confirmation' - // } - // - const statuses = { - '-3': 'pending', - '-2': 'pending', - '-1': 'failed', - '0': 'pending', - '1': 'pending', - '2': 'ok', - '3': 'pending', - '4': 'pending', - '5': 'pending', - }; - return this.safeString (statuses, status, status); - } - - parseTransaction (transaction, currency = undefined) { - // - // withdraw - // - // { - // "amount":"0.1", - // "withdrawal_id":"67485", - // "currency":"btc", - // "result":true - // } - // - // fetchWithdrawals - // - // { - // amount: "4.72100000", - // withdrawal_id: "1729116", - // fee: "0.01000000eth", - // txid: "0xf653125bbf090bcfe4b5e8e7b8f586a9d87aa7de94598702758c0802b…", - // currency: "ETH", - // from: "7147338839", - // to: "0x26a3CB49578F07000575405a57888681249c35Fd", - // timestamp: "2018-08-17T07:03:42.000Z", - // status: "2" - // } - // - // fetchDeposits - // - // { - // amount: "0.47847546", - // txid: "1723573_3_0_0_WALLET", - // currency: "BTC", - // to: "", - // timestamp: "2018-08-16T03:41:10.000Z", - // status: "2" - // } - // - let type = undefined; - let id = undefined; - let address = undefined; - const withdrawalId = this.safeString (transaction, 'withdrawal_id'); - const addressFrom = this.safeString (transaction, 'from'); - const addressTo = this.safeString (transaction, 'to'); - if (withdrawalId !== undefined) { - type = 'withdrawal'; - id = withdrawalId; - address = addressTo; - } else { - // the payment_id will appear on new deposits but appears to be removed from the response after 2 months - id = this.safeString (transaction, 'payment_id'); - type = 'deposit'; - address = addressTo; - } - const currencyId = this.safeString (transaction, 'currency'); - const code = this.safeCurrencyCode (currencyId); - const amount = this.safeFloat (transaction, 'amount'); - const status = this.parseTransactionStatus (this.safeString (transaction, 'status')); - const txid = this.safeString (transaction, 'txid'); - const timestamp = this.parse8601 (this.safeString (transaction, 'timestamp')); - let feeCost = undefined; - if (type === 'deposit') { - feeCost = 0; - } else { - if (currencyId !== undefined) { - const feeWithCurrencyId = this.safeString (transaction, 'fee'); - if (feeWithCurrencyId !== undefined) { - // https://github.com/ccxt/ccxt/pull/5748 - const lowercaseCurrencyId = currencyId.toLowerCase (); - const feeWithoutCurrencyId = feeWithCurrencyId.replace (lowercaseCurrencyId, ''); - feeCost = parseFloat (feeWithoutCurrencyId); - } - } - } - // todo parse tags - return { - 'info': transaction, - 'id': id, - 'currency': code, - 'amount': amount, - 'addressFrom': addressFrom, - 'addressTo': addressTo, - 'address': address, - 'tagFrom': undefined, - 'tagTo': undefined, - 'tag': undefined, - 'status': status, - 'type': type, - 'updated': undefined, - 'txid': txid, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'fee': { - 'currency': code, - 'cost': feeCost, - }, - }; - } - - async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) { - // okex actually returns ledger entries instead of fills here, so each fill in the order - // is represented by two trades with opposite buy/sell sides, not one :\ - // this aspect renders the 'fills' endpoint unusable for fetchOrderTrades - // until either OKEX fixes the API or we workaround this on our side somehow - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchOrderTrades requires a symbol argument'); - } - await this.loadMarkets (); - const market = this.market (symbol); - if ((limit === undefined) || (limit > 100)) { - limit = 100; - } - const request = { - 'instrument_id': market['id'], - 'order_id': id, - // from: '1', // return the page after the specified page number - // to: '1', // return the page before the specified page number - 'limit': limit, // optional, number of results per request, default = maximum = 100 - }; - const defaultType = this.safeString2 (this.options, 'fetchMyTrades', 'defaultType'); - const type = this.safeString (params, 'type', defaultType); - const query = this.omit (params, 'type'); - const method = type + 'GetFills'; - const response = await this[method] (this.extend (request, query)); - // - // spot trades, margin trades - // - // [ - // { - // "created_at":"2019-09-20T07:15:24.000Z", - // "exec_type":"T", - // "fee":"0", - // "instrument_id":"ETH-USDT", - // "ledger_id":"7173486113", - // "liquidity":"T", - // "order_id":"3553868136523776", - // "price":"217.59", - // "product_id":"ETH-USDT", - // "side":"sell", - // "size":"0.04619899", - // "timestamp":"2019-09-20T07:15:24.000Z" - // } - // ] - // - // futures trades, swap trades - // - // [ - // { - // "trade_id":"197429674631450625", - // "instrument_id":"EOS-USD-SWAP", - // "order_id":"6a-7-54d663a28-0", - // "price":"3.633", - // "order_qty":"1.0000", - // "fee":"-0.000551", - // "created_at":"2019-03-21T04:41:58.0Z", // missing in swap trades - // "timestamp":"2019-03-25T05:56:31.287Z", // missing in futures trades - // "exec_type":"M", // whether the order is taker or maker - // "side":"short", // "buy" in futures trades - // } - // ] - // - return this.parseTrades (response, market, since, limit); - } - - async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) { - await this.loadMarkets (); - const defaultType = this.safeString2 (this.options, 'fetchLedger', 'defaultType'); - const type = this.safeString (params, 'type', defaultType); - const query = this.omit (params, 'type'); - const suffix = (type === 'account') ? '' : 'Accounts'; - let argument = ''; - const request = { - // 'from': 'id', - // 'to': 'id', - }; - if (limit !== undefined) { - request['limit'] = limit; - } - let currency = undefined; - if ((type === 'spot') || (type === 'futures')) { - if (code === undefined) { - throw new ArgumentsRequired (this.id + " fetchLedger requires a currency code argument for '" + type + "' markets"); - } - argument = 'Currency'; - currency = this.currency (code); - request['currency'] = currency['id']; - } else if ((type === 'margin') || (type === 'swap')) { - if (code === undefined) { - throw new ArgumentsRequired (this.id + " fetchLedger requires a code argument (a market symbol) for '" + type + "' markets"); - } - argument = 'InstrumentId'; - const market = this.market (code); // we intentionally put a market inside here for the margin and swap ledgers - currency = this.currency (market['base']); - request['instrument_id'] = market['id']; - // - // if (type === 'margin') { - // // - // // 3. Borrow - // // 4. Repayment - // // 5. Interest - // // 7. Buy - // // 8. Sell - // // 9. From capital account - // // 10. From C2C - // // 11. From Futures - // // 12. From Spot - // // 13. From ETT - // // 14. To capital account - // // 15. To C2C - // // 16. To Spot - // // 17. To Futures - // // 18. To ETT - // // 19. Mandatory Repayment - // // 20. From Piggybank - // // 21. To Piggybank - // // 22. From Perpetual - // // 23. To Perpetual - // // 24. Liquidation Fee - // // 54. Clawback - // // 59. Airdrop Return. - // // - // request['type'] = 'number'; // All types will be returned if this filed is left blank - // } - // - } else if (type === 'account') { - if (code !== undefined) { - currency = this.currency (code); - request['currency'] = currency['id']; - } - // - // // - // // 1. deposit - // // 2. withdrawal - // // 13. cancel withdrawal - // // 18. into futures account - // // 19. out of futures account - // // 20. into sub account - // // 21. out of sub account - // // 28. claim - // // 29. into ETT account - // // 30. out of ETT account - // // 31. into C2C account - // // 32. out of C2C account - // // 33. into margin account - // // 34. out of margin account - // // 37. into spot account - // // 38. out of spot account - // // - // request['type'] = 'number'; - // - } else { - throw new NotSupported (this.id + " fetchLedger does not support the '" + type + "' type (the type must be one of 'account', 'spot', 'margin', 'futures', 'swap')"); - } - const method = type + 'Get' + suffix + argument + 'Ledger'; - const response = await this[method] (this.extend (request, query)); - // - // transfer funds transfer in/out - // trade funds moved as a result of a trade, spot and margin accounts only - // rebate fee rebate as per fee schedule, spot and margin accounts only - // match open long/open short/close long/close short (futures) or a change in the amount because of trades (swap) - // fee fee, futures only - // settlement settlement/clawback/settle long/settle short - // liquidation force close long/force close short/deliver close long/deliver close short - // funding funding fee, swap only - // margin a change in the amount after adjusting margin, swap only - // - // account - // - // [ - // { - // "amount":0.00051843, - // "balance":0.00100941, - // "currency":"BTC", - // "fee":0, - // "ledger_id":8987285, - // "timestamp":"2018-10-12T11:01:14.000Z", - // "typename":"Get from activity" - // } - // ] - // - // spot - // - // [ - // { - // "timestamp":"2019-03-18T07:08:25.000Z", - // "ledger_id":"3995334780", - // "created_at":"2019-03-18T07:08:25.000Z", - // "currency":"BTC", - // "amount":"0.0009985", - // "balance":"0.0029955", - // "type":"trade", - // "details":{ - // "instrument_id":"BTC-USDT", - // "order_id":"2500650881647616", - // "product_id":"BTC-USDT" - // } - // } - // ] - // - // margin - // - // [ - // [ - // { - // "created_at":"2019-03-20T03:45:05.000Z", - // "ledger_id":"78918186", - // "timestamp":"2019-03-20T03:45:05.000Z", - // "currency":"EOS", - // "amount":"0", // ? - // "balance":"0.59957711", - // "type":"transfer", - // "details":{ - // "instrument_id":"EOS-USDT", - // "order_id":"787057", - // "product_id":"EOS-USDT" - // } - // } - // ], - // { - // "before":"78965766", - // "after":"78918186" - // } - // ] - // - // futures - // - // [ - // { - // "ledger_id":"2508090544914461", - // "timestamp":"2019-03-19T14:40:24.000Z", - // "amount":"-0.00529521", - // "balance":"0", - // "currency":"EOS", - // "type":"fee", - // "details":{ - // "order_id":"2506982456445952", - // "instrument_id":"EOS-USD-190628" - // } - // } - // ] - // - // swap - // - // [ - // { - // "amount":"0.004742", - // "fee":"-0.000551", - // "type":"match", - // "instrument_id":"EOS-USD-SWAP", - // "ledger_id":"197429674941902848", - // "timestamp":"2019-03-25T05:56:31.286Z" - // }, - // ] - // - const isArray = Array.isArray (response[0]); - const isMargin = (type === 'margin'); - const entries = (isMargin && isArray) ? response[0] : response; - return this.parseLedger (entries, currency, since, limit); - } - - parseLedgerEntryType (type) { - const types = { - 'transfer': 'transfer', // // funds transfer in/out - 'trade': 'trade', // funds moved as a result of a trade, spot and margin accounts only - 'rebate': 'rebate', // fee rebate as per fee schedule, spot and margin accounts only - 'match': 'trade', // open long/open short/close long/close short (futures) or a change in the amount because of trades (swap) - 'fee': 'fee', // fee, futures only - 'settlement': 'trade', // settlement/clawback/settle long/settle short - 'liquidation': 'trade', // force close long/force close short/deliver close long/deliver close short - 'funding': 'fee', // funding fee, swap only - 'margin': 'margin', // a change in the amount after adjusting margin, swap only - }; - return this.safeString (types, type, type); - } - - parseLedgerEntry (item, currency = undefined) { - // - // - // account - // - // { - // "amount":0.00051843, - // "balance":0.00100941, - // "currency":"BTC", - // "fee":0, - // "ledger_id":8987285, - // "timestamp":"2018-10-12T11:01:14.000Z", - // "typename":"Get from activity" - // } - // - // spot - // - // { - // "timestamp":"2019-03-18T07:08:25.000Z", - // "ledger_id":"3995334780", - // "created_at":"2019-03-18T07:08:25.000Z", - // "currency":"BTC", - // "amount":"0.0009985", - // "balance":"0.0029955", - // "type":"trade", - // "details":{ - // "instrument_id":"BTC-USDT", - // "order_id":"2500650881647616", - // "product_id":"BTC-USDT" - // } - // } - // - // margin - // - // { - // "created_at":"2019-03-20T03:45:05.000Z", - // "ledger_id":"78918186", - // "timestamp":"2019-03-20T03:45:05.000Z", - // "currency":"EOS", - // "amount":"0", // ? - // "balance":"0.59957711", - // "type":"transfer", - // "details":{ - // "instrument_id":"EOS-USDT", - // "order_id":"787057", - // "product_id":"EOS-USDT" - // } - // } - // - // futures - // - // { - // "ledger_id":"2508090544914461", - // "timestamp":"2019-03-19T14:40:24.000Z", - // "amount":"-0.00529521", - // "balance":"0", - // "currency":"EOS", - // "type":"fee", - // "details":{ - // "order_id":"2506982456445952", - // "instrument_id":"EOS-USD-190628" - // } - // } - // - // swap - // - // { - // "amount":"0.004742", - // "fee":"-0.000551", - // "type":"match", - // "instrument_id":"EOS-USD-SWAP", - // "ledger_id":"197429674941902848", - // "timestamp":"2019-03-25T05:56:31.286Z" - // }, - // - const id = this.safeString (item, 'ledger_id'); - const account = undefined; - const details = this.safeValue (item, 'details', {}); - const referenceId = this.safeString (details, 'order_id'); - const referenceAccount = undefined; - const type = this.parseLedgerEntryType (this.safeString (item, 'type')); - const code = this.safeCurrencyCode (this.safeString (item, 'currency'), currency); - const amount = this.safeFloat (item, 'amount'); - const timestamp = this.parse8601 (this.safeString (item, 'timestamp')); - const fee = { - 'cost': this.safeFloat (item, 'fee'), - 'currency': code, - }; - const before = undefined; - const after = this.safeFloat (item, 'balance'); - const status = 'ok'; - return { - 'info': item, - 'id': id, - 'account': account, - 'referenceId': referenceId, - 'referenceAccount': referenceAccount, - 'type': type, - 'currency': code, - 'amount': amount, - 'before': before, // balance before - 'after': after, // balance after - 'status': status, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'fee': fee, - }; - } - - sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - const isArray = Array.isArray (params); - let request = '/api/' + api + '/' + this.version + '/'; - request += isArray ? path : this.implodeParams (path, params); - const query = isArray ? params : this.omit (params, this.extractParams (path)); - let url = this.urls['api'] + request; - const type = this.getPathAuthenticationType (path); - if (type === 'public') { - if (Object.keys (query).length) { - url += '?' + this.urlencode (query); - } - } else if (type === 'private') { - this.checkRequiredCredentials (); - const timestamp = this.iso8601 (this.milliseconds ()); - headers = { - 'OK-ACCESS-KEY': this.apiKey, - 'OK-ACCESS-PASSPHRASE': this.password, - 'OK-ACCESS-TIMESTAMP': timestamp, - // 'OK-FROM': '', - // 'OK-TO': '', - // 'OK-LIMIT': '', - }; - let auth = timestamp + method + request; - if (method === 'GET') { - if (Object.keys (query).length) { - const urlencodedQuery = '?' + this.urlencode (query); - url += urlencodedQuery; - auth += urlencodedQuery; - } - } else { - if (isArray || Object.keys (query).length) { - body = this.json (query); - auth += body; - } - headers['Content-Type'] = 'application/json'; - } - const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256', 'base64'); - headers['OK-ACCESS-SIGN'] = this.decode (signature); - } - return { 'url': url, 'method': method, 'body': body, 'headers': headers }; - } - - getPathAuthenticationType (path) { - const auth = this.safeValue (this.options, 'auth', {}); - const key = this.findBroadlyMatchedKey (auth, path); - return this.safeString (auth, key, 'private'); - } - - handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { - const feedback = this.id + ' ' + body; - if (code === 503) { - throw new ExchangeError (feedback); - } - if (!response) { - return; // fallback to default error handler - } - const message = this.safeString (response, 'message'); - const errorCode = this.safeString2 (response, 'code', 'error_code'); - if (message !== undefined) { - this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback); - this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback); - } - this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback); - if (message !== undefined) { - throw new ExchangeError (feedback); // unknown message - } - } -}; diff --git a/TaskServer/node_modules/ccxt/js/poloniex.js b/TaskServer/node_modules/ccxt/js/poloniex.js index 2e4588459..fc389cd5e 100644 --- a/TaskServer/node_modules/ccxt/js/poloniex.js +++ b/TaskServer/node_modules/ccxt/js/poloniex.js @@ -15,6 +15,7 @@ module.exports = class poloniex extends Exchange { 'countries': [ 'US' ], 'rateLimit': 1000, // up to 6 calls per second 'certified': true, // 2019-06-07 + 'pro': true, 'has': { 'CORS': false, 'createDepositAddress': true, @@ -228,7 +229,7 @@ module.exports = class poloniex extends Exchange { if (limit === undefined) { request['start'] = request['end'] - this.parseTimeframe ('1w'); // max range = 1 week } else { - request['start'] = request['end'] - this.sum (limit) * this.parseTimeframe (timeframe); + request['start'] = request['end'] - limit * this.parseTimeframe (timeframe); } } else { request['start'] = parseInt (since / 1000); @@ -423,9 +424,6 @@ module.exports = class poloniex extends Exchange { for (let i = 0; i < ids.length; i++) { const id = ids[i]; const currency = response[id]; - // todo: will need to rethink the fees - // to add support for multiple withdrawal/deposit methods and - // differentiated fees for each particular method const precision = 8; // default precision, todo: fix "magic constants" const code = this.safeCurrencyCode (id); const active = (currency['delisted'] === 0) && !currency['disabled']; @@ -751,6 +749,7 @@ module.exports = class poloniex extends Exchange { // }, // ], // 'fee': '0.00000000', + // 'clientOrderId': '12345', // 'currencyPair': 'BTC_MANA', // // --------------------------------------------------------- // // the following fields are injected by createOrder @@ -837,9 +836,11 @@ module.exports = class poloniex extends Exchange { 'currency': feeCurrencyCode, }; } + const clientOrderId = this.safeString (order, 'clientOrderId'); return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, diff --git a/TaskServer/node_modules/ccxt/js/rightbtc.js b/TaskServer/node_modules/ccxt/js/rightbtc.js index 2fb83c274..76a43d325 100644 --- a/TaskServer/node_modules/ccxt/js/rightbtc.js +++ b/TaskServer/node_modules/ccxt/js/rightbtc.js @@ -542,6 +542,7 @@ module.exports = class rightbtc extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -556,6 +557,7 @@ module.exports = class rightbtc extends Exchange { 'status': status, 'fee': fee, 'trades': trades, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/southxchange.js b/TaskServer/node_modules/ccxt/js/southxchange.js index 3ebd4e3dd..0795385fc 100644 --- a/TaskServer/node_modules/ccxt/js/southxchange.js +++ b/TaskServer/node_modules/ccxt/js/southxchange.js @@ -61,6 +61,7 @@ module.exports = class southxchange extends Exchange { 'commonCurrencies': { 'SMT': 'SmartNode', 'MTC': 'Marinecoin', + 'BHD': 'Bithold', }, }); } @@ -85,6 +86,8 @@ module.exports = class southxchange extends Exchange { 'quoteId': quoteId, 'active': undefined, 'info': market, + 'precision': this.precision, + 'limits': this.limits, }); } return result; @@ -245,6 +248,7 @@ module.exports = class southxchange extends Exchange { const result = { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -258,6 +262,8 @@ module.exports = class southxchange extends Exchange { 'remaining': remaining, 'status': status, 'fee': undefined, + 'average': undefined, + 'trades': undefined, }; return result; } diff --git a/TaskServer/node_modules/ccxt/js/stex.js b/TaskServer/node_modules/ccxt/js/stex.js index b70f504fd..29e729957 100644 --- a/TaskServer/node_modules/ccxt/js/stex.js +++ b/TaskServer/node_modules/ccxt/js/stex.js @@ -175,6 +175,9 @@ module.exports = class stex extends Exchange { 'maker': 0.002, }, }, + 'commonCurrencies': { + 'BHD': 'Bithold', + }, 'options': { 'parseOrderToPrecision': false, }, @@ -504,7 +507,7 @@ module.exports = class stex extends Exchange { let change = undefined; let percentage = undefined; if (last !== undefined) { - if (open !== undefined) { + if ((open !== undefined) && (open > 0)) { change = last - open; percentage = ((100 / open) * last) - 100; } @@ -915,6 +918,7 @@ module.exports = class stex extends Exchange { const result = { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, diff --git a/TaskServer/node_modules/ccxt/js/stronghold.js b/TaskServer/node_modules/ccxt/js/stronghold.js index 86e06d6ef..14d0af642 100644 --- a/TaskServer/node_modules/ccxt/js/stronghold.js +++ b/TaskServer/node_modules/ccxt/js/stronghold.js @@ -222,6 +222,7 @@ module.exports = class stronghold extends Exchange { 'precision': precision, 'info': entry, 'limits': limits, + 'active': undefined, }; } return result; @@ -279,6 +280,7 @@ module.exports = class stronghold extends Exchange { 'active': undefined, 'name': undefined, 'limits': limits, + 'fee': undefined, }; } return result; @@ -576,6 +578,7 @@ module.exports = class stronghold extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'info': order, 'symbol': symbol, 'datetime': datetime, @@ -591,6 +594,7 @@ module.exports = class stronghold extends Exchange { 'status': undefined, 'type': undefined, 'average': undefined, + 'fee': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/test/Exchange/test.fetchOHLCV.js b/TaskServer/node_modules/ccxt/js/test/Exchange/test.fetchOHLCV.js index 230e1cf77..a526fd72f 100644 --- a/TaskServer/node_modules/ccxt/js/test/Exchange/test.fetchOHLCV.js +++ b/TaskServer/node_modules/ccxt/js/test/Exchange/test.fetchOHLCV.js @@ -17,8 +17,6 @@ module.exports = async (exchange, symbol) => { 'btcalpha', // issue with 404 on a documented endpoint https://travis-ci.org/ccxt/ccxt/builds/643930431#L2213 'bitmex', // an issue with null values,to be resolved later 'cex', - 'okex', - 'okcoinusd', 'mandala', ] diff --git a/TaskServer/node_modules/ccxt/js/test/Exchange/test.ohlcv.js b/TaskServer/node_modules/ccxt/js/test/Exchange/test.ohlcv.js index 664103259..d71956bcd 100644 --- a/TaskServer/node_modules/ccxt/js/test/Exchange/test.ohlcv.js +++ b/TaskServer/node_modules/ccxt/js/test/Exchange/test.ohlcv.js @@ -21,7 +21,7 @@ module.exports = (exchange, ohlcv, symbol, now) => { assert (ohlcv[0] > 1230940800000) // 03 Jan 2009 - first block assert (ohlcv[0] < 2147483648000) // 19 Jan 2038 - int32 overflows - assert (ohlcv[1] === undefined || ohlcv[2] === undefined || ohlcv[1] <= ohlcv[2], 'open > high!') // open <= high - assert (ohlcv[3] === undefined || ohlcv[2] === undefined || ohlcv[3] <= ohlcv[2], 'low > high!') // low <= high - assert (ohlcv[3] === undefined || ohlcv[4] === undefined || ohlcv[3] <= ohlcv[4], 'low > close!') // low <= close + assert (ohlcv[1] === undefined || ohlcv[2] === undefined || ohlcv[1] <= ohlcv[2], 'open > high! ' + (ohlcv[1].toString () + ' > ' + ohlcv[2].toString ())) // open <= high + assert (ohlcv[3] === undefined || ohlcv[2] === undefined || ohlcv[3] <= ohlcv[2], 'low > high! ' + (ohlcv[3].toString () + ' > ' + ohlcv[2].toString ())) // low <= high + assert (ohlcv[3] === undefined || ohlcv[4] === undefined || ohlcv[3] <= ohlcv[4], 'low > close! ' + (ohlcv[3].toString () + ' > ' + ohlcv[4].toString ())) // low <= close } \ No newline at end of file diff --git a/TaskServer/node_modules/ccxt/js/test/Exchange/test.orderbook.js b/TaskServer/node_modules/ccxt/js/test/Exchange/test.orderbook.js index 7d658434c..11d088796 100644 --- a/TaskServer/node_modules/ccxt/js/test/Exchange/test.orderbook.js +++ b/TaskServer/node_modules/ccxt/js/test/Exchange/test.orderbook.js @@ -60,7 +60,6 @@ module.exports = (exchange, orderbook, method, symbol) => { 'coinmarketcap', 'xbtce', - 'coinsecure', 'upbit', // an orderbook might have a 0-price ask occasionally ].includes (exchange.id)) { diff --git a/TaskServer/node_modules/ccxt/js/test/base/functions/test.crypto.js b/TaskServer/node_modules/ccxt/js/test/base/functions/test.crypto.js index 91f71c13f..f29b0339f 100644 --- a/TaskServer/node_modules/ccxt/js/test/base/functions/test.crypto.js +++ b/TaskServer/node_modules/ccxt/js/test/base/functions/test.crypto.js @@ -108,3 +108,11 @@ const pemKey = pemKeyArray.join ("\n"); assert (jwt ({'chicken': 'salad'}, encode (pemKey), 'RS256') === 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjaGlja2VuIjoic2FsYWQifQ.FSKD5Y6RNzkHTuHdvG3753U7QNZ-u-GUSPfP1FMjEaK0Rr_iyQTSSmHhkdYSFFnmBvrrN_l-UwKwir52WlsgmQm9HYm0kidxbj7fWwrK2E1oe0P7OjupFjv1BZxc5W69WeaHtOPWe28tiHiON1LCnax6HgfI5lcIBsESGIIBZMVeaioQn9gDVwea7JxJvAlrhDIWZowIHTIdCQocXip7g5jREWHeEIuJNug67mwnfAFxCjvTRiTd0Bw6oBwjM3FLya-RyEyWrejQOWSuC8CNWVUHISaSmEyZ7uM6wTi2m_58TaE9mQwlef32OPErPvvBpgL5pZIyQ4ymwrCIFQLBQQ'); assert (jwt ({'lil': 'xan'}, encode ('betrayed'), 'HS256') === 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsaWwiOiJ4YW4ifQ.md-oFvZagA-NXmZoRNyJOQ7zwK-PWUMmMQ_LI9ZOKaM'); + +// --------------------------------------------------------------------------------------------------------------------- + +assert (exchange.soliditySha3 (['0x63581b9abf2b661da0ba247e0dda1b723dcff5e3', 100, 'lulwat']) === '0x1d3e95c10fc64aee6628ea59284503a4eafc6ff13c541f00753fbd2a66cea0f5'); +assert (exchange.soliditySha3 ([234]) === '0x61c831beab28d67d1bb40b5ae1a11e2757fa842f031a2d0bc94a7867bc5d26c2'); +assert (exchange.soliditySha3 (['234']) === '0x61c831beab28d67d1bb40b5ae1a11e2757fa842f031a2d0bc94a7867bc5d26c2'); +assert (exchange.soliditySha3 (['Hello!%']) === '0x661136a4267dba9ccdf6bfddb7c00e714de936674c4bdb065a531cf1cb15c7fc'); +assert (exchange.soliditySha3 (['0x407D73d8a49eeb85D32Cf465507dd71d507100c1']) === '0x4e8ebbefa452077428f93c9520d3edd60594ff452a29ac7d2ccc11d47f3ab95b'); diff --git a/TaskServer/node_modules/ccxt/js/test/base/functions/test.number.js b/TaskServer/node_modules/ccxt/js/test/base/functions/test.number.js index be3e8f49b..e4b9a6b00 100644 --- a/TaskServer/node_modules/ccxt/js/test/base/functions/test.number.js +++ b/TaskServer/node_modules/ccxt/js/test/base/functions/test.number.js @@ -1,8 +1,49 @@ 'use strict' -const { numberToString, decimalToPrecision, ROUND, TRUNCATE, DECIMAL_PLACES, TICK_SIZE, PAD_WITH_ZERO, SIGNIFICANT_DIGITS } = require ('../../../../ccxt'); +const { numberToString, decimalToPrecision, ROUND, TRUNCATE, DECIMAL_PLACES, TICK_SIZE, PAD_WITH_ZERO, SIGNIFICANT_DIGITS, toWei, fromWei } = require ('../../../../ccxt'); const assert = require ('assert'); +// ---------------------------------------------------------------------------- +// toWei / fromWei + +assert (toWei (1, 18) === '1000000000000000000'); +assert (toWei (1, 17) === '100000000000000000'); +assert (toWei (1, 16) === '10000000000000000'); +assert (toWei ('1', 18) === '1000000000000000000'); +assert (toWei ('1', 17) === '100000000000000000'); +assert (toWei ('1', 16) === '10000000000000000'); +assert (toWei (0, 18) === '0'); +assert (toWei (1, 0) === '1'); +assert (toWei (1, 1) === '10'); +assert (toWei (1.3, 18) === '1300000000000000000'); +assert (toWei ('1.3', 18) === '1300000000000000000'); +assert (toWei (1.999, 17) === '199900000000000000'); +assert (toWei ('1.999', 17) === '199900000000000000'); +assert (toWei ('0.1', 18) === '100000000000000000'); +assert (toWei ('0.01', 18) === '10000000000000000'); +assert (toWei ('0.001', 18) === '1000000000000000'); +assert (toWei (0.1, 18) === '100000000000000000'); +assert (toWei (0.01, 18) === '10000000000000000'); +assert (toWei (0.001, 18) === '1000000000000000'); + +// let us test that we get the inverse for all these test +assert (fromWei ('1000000000000000000', 18) === 1.0); +assert (fromWei ('100000000000000000', 17) === 1.0); +assert (fromWei ('10000000000000000', 16) === 1.0); +assert (fromWei (1000000000000000000, 18) === 1.0); +assert (fromWei (100000000000000000, 17) === 1.0); +assert (fromWei (10000000000000000, 16) === 1.0); +assert (fromWei ('1300000000000000000', 18) === 1.3); +assert (fromWei (1300000000000000000, 18) === 1.3); +assert (fromWei ('199900000000000000', 17) === 1.999); +assert (fromWei (199900000000000000, 17) === 1.999); +assert (fromWei ('100000000000000000', 18) === 0.1); +assert (fromWei ('10000000000000000', 18) === 0.01); +assert (fromWei ('1000000000000000', 18) === 0.001); +assert (fromWei (100000000000000000, 18) === 0.1); +assert (fromWei (10000000000000000, 18) === 0.01); +assert (fromWei (1000000000000000, 18) === 0.001); + // ---------------------------------------------------------------------------- // numberToString @@ -17,7 +58,7 @@ assert (numberToString (7.9e27) === '7900000000000000000000000000'); assert (numberToString (-12.345) === '-12.345'); assert (numberToString (12.345) === '12.345'); assert (numberToString (0) === '0'); -// this line breaks the test +// the following line breaks the test // see https://github.com/ccxt/ccxt/issues/5744 // assert (numberToString (0.00000001) === '0.00000001'); @@ -157,6 +198,24 @@ assert (decimalToPrecision ('-0.000123456789', ROUND, 0.00000012, TICK_SIZE) === assert (decimalToPrecision ('-0.000123456789', TRUNCATE, 0.00000012, TICK_SIZE) === '-0.00012336'); assert (decimalToPrecision ('-165', TRUNCATE, 110, TICK_SIZE) === '-110'); assert (decimalToPrecision ('-165', ROUND, 110, TICK_SIZE) === '-220'); +assert (decimalToPrecision ('-1650', TRUNCATE, 1100, TICK_SIZE) === '-1100'); +assert (decimalToPrecision ('-1650', ROUND, 1100, TICK_SIZE) === '-2200'); + +assert (decimalToPrecision ('0.0006', TRUNCATE, 0.0001, TICK_SIZE) === '0.0006'); +assert (decimalToPrecision ('-0.0006', TRUNCATE, 0.0001, TICK_SIZE) === '-0.0006'); +assert (decimalToPrecision ('0.6', TRUNCATE, 0.2, TICK_SIZE) === '0.6'); +assert (decimalToPrecision ('-0.6', TRUNCATE, 0.2, TICK_SIZE) === '-0.6'); +assert (decimalToPrecision ('1.2', ROUND, 0.4, TICK_SIZE) === '1.2'); +assert (decimalToPrecision ('-1.2', ROUND, 0.4, TICK_SIZE) === '-1.2'); +assert (decimalToPrecision ('1.2', ROUND, 0.02, TICK_SIZE) === '1.2'); +assert (decimalToPrecision ('-1.2', ROUND, 0.02, TICK_SIZE) === '-1.2'); +assert (decimalToPrecision ('44', ROUND, 4.4, TICK_SIZE) === '44'); +assert (decimalToPrecision ('-44', ROUND, 4.4, TICK_SIZE) === '-44'); +assert (decimalToPrecision ('44.00000001', ROUND, 4.4, TICK_SIZE) === '44'); +assert (decimalToPrecision ('-44.00000001', ROUND, 4.4, TICK_SIZE) === '-44'); + +// https://github.com/ccxt/ccxt/issues/6731 +assert (decimalToPrecision ('20', TRUNCATE, 0.00000001, TICK_SIZE) === '20'); // ---------------------------------------------------------------------------- // testDecimalToPrecisionNegativeNumbers diff --git a/TaskServer/node_modules/ccxt/js/test/test.js b/TaskServer/node_modules/ccxt/js/test/test.js index e8a879571..665e1a228 100644 --- a/TaskServer/node_modules/ccxt/js/test/test.js +++ b/TaskServer/node_modules/ccxt/js/test/test.js @@ -33,8 +33,7 @@ log.bright ('\nTESTING', { exchange: exchangeId, symbol: exchangeSymbol || 'all' let proxies = [ '', - 'https://cors-anywhere.herokuapp.com/', - // 'https://crossorigin.me/', + 'https://cors-anywhere.herokuapp.com/' ] //----------------------------------------------------------------------------- @@ -120,7 +119,7 @@ let testSymbol = async (exchange, symbol) => { } else if (exchange.id === 'coinbase') { - // do nothing for now + // nothing for now } else { @@ -336,10 +335,12 @@ let tryAllProxies = async function (exchange, proxies) { exchange.proxy = proxies[currentProxy] // add random origin for proxies - if (exchange.proxy.length > 0) + if (exchange.proxy.length > 0) { exchange.origin = exchange.uuid () + } await testExchange (exchange) + break } catch (e) { @@ -369,12 +370,9 @@ let tryAllProxies = async function (exchange, proxies) { ;(async function test () { if (exchangeSymbol) { - await loadExchange (exchange) await testSymbol (exchange, exchangeSymbol) - } else { - await tryAllProxies (exchange, proxies) } diff --git a/TaskServer/node_modules/ccxt/js/theocean.js b/TaskServer/node_modules/ccxt/js/theocean.js index 062ddd4ec..2fd3e1bd6 100644 --- a/TaskServer/node_modules/ccxt/js/theocean.js +++ b/TaskServer/node_modules/ccxt/js/theocean.js @@ -134,16 +134,16 @@ module.exports = class theocean extends Exchange { 'price': -parseInt (quoteToken['precision']), }; const amountLimits = { - 'min': this.fromWei (this.safeString (baseToken, 'minAmount'), 'ether', baseDecimals), - 'max': this.fromWei (this.safeString (baseToken, 'maxAmount'), 'ether', baseDecimals), + 'min': this.fromWei (this.safeString (baseToken, 'minAmount'), baseDecimals), + 'max': this.fromWei (this.safeString (baseToken, 'maxAmount'), baseDecimals), }; const priceLimits = { 'min': undefined, 'max': undefined, }; const costLimits = { - 'min': this.fromWei (this.safeString (quoteToken, 'minAmount'), 'ether', quoteDecimals), - 'max': this.fromWei (this.safeString (quoteToken, 'maxAmount'), 'ether', quoteDecimals), + 'min': this.fromWei (this.safeString (quoteToken, 'minAmount'), quoteDecimals), + 'max': this.fromWei (this.safeString (quoteToken, 'maxAmount'), quoteDecimals), }; const limits = { 'amount': amountLimits, @@ -175,7 +175,7 @@ module.exports = class theocean extends Exchange { this.safeFloat (ohlcv, 'high'), this.safeFloat (ohlcv, 'low'), this.safeFloat (ohlcv, 'close'), - this.fromWei (this.safeString (ohlcv, 'baseVolume'), 'ether', baseDecimals), + this.fromWei (this.safeString (ohlcv, 'baseVolume'), baseDecimals), ]; } @@ -232,9 +232,9 @@ module.exports = class theocean extends Exchange { // {"available":"0","committed":"0","total":"0"} // const decimals = this.safeInteger (this.options['decimals'], code, 18); - const free = this.fromWei (this.safeString (response, 'available'), 'ether', decimals); - const used = this.fromWei (this.safeString (response, 'committed'), 'ether', decimals); - const total = this.fromWei (this.safeString (response, 'total'), 'ether', decimals); + const free = this.fromWei (this.safeString (response, 'available'), decimals); + const used = this.fromWei (this.safeString (response, 'committed'), decimals); + const total = this.fromWei (this.safeString (response, 'total'), decimals); return { 'free': free, 'used': used, @@ -345,7 +345,7 @@ module.exports = class theocean extends Exchange { base = market['base']; } const baseDecimals = this.safeInteger (this.options['decimals'], base, 18); - const baseVolume = this.fromWei (this.safeString (ticker, 'volume'), 'ether', baseDecimals); + const baseVolume = this.fromWei (this.safeString (ticker, 'volume'), baseDecimals); const last = this.safeFloat (ticker, 'last'); return { 'symbol': symbol, @@ -452,7 +452,7 @@ module.exports = class theocean extends Exchange { base = market['base']; } const baseDecimals = this.safeInteger (this.options['decimals'], base, 18); - const amount = this.fromWei (this.safeString (trade, 'amount'), 'ether', baseDecimals); + const amount = this.fromWei (this.safeString (trade, 'amount'), baseDecimals); let cost = undefined; if (amount !== undefined && price !== undefined) { cost = amount * price; @@ -537,7 +537,7 @@ module.exports = class theocean extends Exchange { 'baseTokenAddress': market['baseId'], // Base token address 'quoteTokenAddress': market['quoteId'], // Quote token address 'side': side, // "buy" or "sell" - 'amount': this.toWei (this.amountToPrecision (symbol, amount), 'ether', baseDecimals), // Base token amount in wei + 'amount': this.toWei (this.amountToPrecision (symbol, amount), baseDecimals), // Base token amount in wei }; let method = undefined; if (type === 'limit') { @@ -623,13 +623,13 @@ module.exports = class theocean extends Exchange { } const baseDecimals = this.safeInteger (this.options['decimals'], base, 18); const price = this.safeFloat (order, 'price'); - const filledAmount = this.fromWei (this.safeString (order, 'filledAmount'), 'ether', baseDecimals); - const settledAmount = this.fromWei (this.safeString (order, 'settledAmount'), 'ether', baseDecimals); - const confirmedAmount = this.fromWei (this.safeString (order, 'confirmedAmount'), 'ether', baseDecimals); - const failedAmount = this.fromWei (this.safeString (order, 'failedAmount'), 'ether', baseDecimals); - const deadAmount = this.fromWei (this.safeString (order, 'deadAmount'), 'ether', baseDecimals); - const prunedAmount = this.fromWei (this.safeString (order, 'prunedAmount'), 'ether', baseDecimals); - const amount = this.fromWei (this.safeString (order, 'initialAmount'), 'ether', baseDecimals); + const filledAmount = this.fromWei (this.safeString (order, 'filledAmount'), baseDecimals); + const settledAmount = this.fromWei (this.safeString (order, 'settledAmount'), baseDecimals); + const confirmedAmount = this.fromWei (this.safeString (order, 'confirmedAmount'), baseDecimals); + const failedAmount = this.fromWei (this.safeString (order, 'failedAmount'), baseDecimals); + const deadAmount = this.fromWei (this.safeString (order, 'deadAmount'), baseDecimals); + const prunedAmount = this.fromWei (this.safeString (order, 'prunedAmount'), baseDecimals); + const amount = this.fromWei (this.safeString (order, 'initialAmount'), baseDecimals); const filled = this.sum (filledAmount, settledAmount, confirmedAmount); let remaining = undefined; let lastTradeTimestamp = undefined; @@ -689,7 +689,7 @@ module.exports = class theocean extends Exchange { } const feeDecimals = this.safeInteger (this.options['decimals'], feeCurrency, 18); fee = { - 'cost': this.fromWei (feeCost, 'ether', feeDecimals), + 'cost': this.fromWei (feeCost, feeDecimals), 'currency': feeCurrency, }; } @@ -706,6 +706,7 @@ module.exports = class theocean extends Exchange { const result = { 'info': order, 'id': id, + 'clientOrderId': undefined, 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -720,6 +721,7 @@ module.exports = class theocean extends Exchange { 'status': status, 'fee': fee, 'trades': trades, + 'average': undefined, }; return result; } diff --git a/TaskServer/node_modules/ccxt/js/therock.js b/TaskServer/node_modules/ccxt/js/therock.js index 285471d79..254563067 100644 --- a/TaskServer/node_modules/ccxt/js/therock.js +++ b/TaskServer/node_modules/ccxt/js/therock.js @@ -956,6 +956,7 @@ module.exports = class therock extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), diff --git a/TaskServer/node_modules/ccxt/js/tidebit.js b/TaskServer/node_modules/ccxt/js/tidebit.js index 2cce034e4..5d0f63e6b 100644 --- a/TaskServer/node_modules/ccxt/js/tidebit.js +++ b/TaskServer/node_modules/ccxt/js/tidebit.js @@ -17,7 +17,7 @@ module.exports = class tidebit extends Exchange { 'version': 'v2', 'has': { 'fetchDepositAddress': true, - 'CORS': true, + 'CORS': false, 'fetchTickers': true, 'fetchOHLCV': true, 'withdraw': true, @@ -157,6 +157,9 @@ module.exports = class tidebit extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'info': market, + 'active': undefined, + 'precision': this.precision, + 'limits': this.limits, }); } return result; @@ -342,6 +345,41 @@ module.exports = class tidebit extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "id": 7, // 唯一的 Order ID + // "side": "sell", // Buy/Sell 代表买单/卖单 + // "price": "3100.0", // 出价 + // "avg_price": "3101.2", // 平均成交价 + // "state": "wait", // 订单的当前状态 [wait,done,cancel] + // // wait 表明订单正在市场上挂单 + // // 是一个active order + // // 此时订单可能部分成交或者尚未成交 + // // done 代表订单已经完全成交 + // // cancel 代表订单已经被撤销 + // "market": "btccny", // 订单参与的交易市场 + // "created_at": "2014-04-18T02:02:33Z", // 下单时间 ISO8601格式 + // "volume": "100.0", // 购买/卖出数量 + // "remaining_volume": "89.8", // 还未成交的数量 remaining_volume 总是小于等于 volume + // // 在订单完全成交时变成 0 + // "executed_volume": "10.2", // 已成交的数量 + // // volume = remaining_volume + executed_volume + // "trades_count": 1, // 订单的成交数 整数值 + // // 未成交的订单为 0 有一笔成交的订单为 1 + // // 通过该字段可以判断订单是否处于部分成交状态 + // "trades": [ // 订单的详细成交记录 参见Trade + // // 注意: 只有某些返回详细订单数据的 API 才会包含 Trade 数据 + // { + // "id": 2, + // "price": "3100.0", + // "volume": "10.2", + // "market": "btccny", + // "created_at": "2014-04-18T02:04:49Z", + // "side": "sell" + // } + // ] + // } + // let symbol = undefined; if (market !== undefined) { symbol = market['symbol']; @@ -366,6 +404,7 @@ module.exports = class tidebit extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -381,6 +420,7 @@ module.exports = class tidebit extends Exchange { 'trades': undefined, 'fee': undefined, 'info': order, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/tidex.js b/TaskServer/node_modules/ccxt/js/tidex.js index 4b08cb872..efe071e01 100644 --- a/TaskServer/node_modules/ccxt/js/tidex.js +++ b/TaskServer/node_modules/ccxt/js/tidex.js @@ -164,11 +164,11 @@ module.exports = class tidex extends Exchange { 'max': undefined, }, 'withdraw': { - 'min': currency['withdrawMinAmout'], + 'min': this.safeFloat (currency, 'withdrawMinAmount'), 'max': undefined, }, 'deposit': { - 'min': currency['depositMinAmount'], + 'min': this.safeFloat (currency, 'depositMinAmount'), 'max': undefined, }, }, @@ -528,9 +528,13 @@ module.exports = class tidex extends Exchange { 'filled': filled, 'fee': undefined, // 'trades': this.parseTrades (order['trades'], market), + 'info': response, + 'clientOrderId': undefined, + 'average': undefined, + 'trades': undefined, }; this.orders[id] = order; - return this.extend ({ 'info': response }, order); + return order; } async cancelOrder (id, symbol = undefined, params = {}) { @@ -606,6 +610,9 @@ module.exports = class tidex extends Exchange { 'filled': filled, 'status': status, 'fee': fee, + 'clientOrderId': undefined, + 'average': undefined, + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/timex.js b/TaskServer/node_modules/ccxt/js/timex.js index e20edc6aa..1c381f7cb 100644 --- a/TaskServer/node_modules/ccxt/js/timex.js +++ b/TaskServer/node_modules/ccxt/js/timex.js @@ -1175,9 +1175,11 @@ module.exports = class timex extends Exchange { lastTradeTimestamp = trades[numTrades - 1]['timestamp']; } } + const clientOrderId = this.safeString (order, 'clientOrderId'); return { 'info': order, 'id': id, + 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, diff --git a/TaskServer/node_modules/ccxt/js/topq.js b/TaskServer/node_modules/ccxt/js/topq.js new file mode 100644 index 000000000..2ba3ca937 --- /dev/null +++ b/TaskServer/node_modules/ccxt/js/topq.js @@ -0,0 +1,25 @@ +'use strict'; + +// --------------------------------------------------------------------------- + +const bw = require ('./bw.js'); + +// --------------------------------------------------------------------------- + +module.exports = class topq extends bw { + describe () { + return this.deepExtend (super.describe (), { + 'id': 'topq', + 'countries': [ 'SG' ], + 'name': 'TOP.Q', + 'hostname': 'topliq.com', + 'urls': { + 'logo': 'https://user-images.githubusercontent.com/1294454/74596147-50247000-505c-11ea-9224-4fd347cfbb49.jpg', + 'api': 'https://www.{hostname}', + 'www': 'https://www.topliq.com', + 'doc': 'https://github.com/topq-exchange/api_docs_en/wiki/REST_api_reference', + 'fees': 'https://www.topliq.com/feesRate', + }, + }); + } +}; diff --git a/TaskServer/node_modules/ccxt/js/upbit.js b/TaskServer/node_modules/ccxt/js/upbit.js index 763aa9a78..e34f8e651 100644 --- a/TaskServer/node_modules/ccxt/js/upbit.js +++ b/TaskServer/node_modules/ccxt/js/upbit.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, BadRequest, AuthenticationError, InvalidOrder, InsufficientFunds, OrderNotFound, PermissionDenied } = require ('./base/errors'); +const { ExchangeError, BadRequest, AuthenticationError, InvalidOrder, InsufficientFunds, OrderNotFound, PermissionDenied, AddressPending } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -16,6 +16,7 @@ module.exports = class upbit extends Exchange { 'version': 'v1', 'rateLimit': 1000, 'certified': true, + 'pro': true, // new metainfo interface 'has': { 'CORS': true, @@ -50,7 +51,10 @@ module.exports = class upbit extends Exchange { 'hostname': 'api.upbit.com', 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/49245610-eeaabe00-f423-11e8-9cba-4b0aed794799.jpg', - 'api': 'https://{hostname}', + 'api': { + 'public': 'https://{hostname}', + 'private': 'https://{hostname}', + }, 'www': 'https://upbit.com', 'doc': 'https://docs.upbit.com/docs/%EC%9A%94%EC%B2%AD-%EC%88%98-%EC%A0%9C%ED%95%9C', 'fees': 'https://upbit.com/service_center/guide', @@ -539,7 +543,7 @@ module.exports = class upbit extends Exchange { // timestamp: 1542883543813 } // const timestamp = this.safeInteger (ticker, 'trade_timestamp'); - const symbol = this.getSymbolFromMarketId (this.safeString (ticker, 'market'), market); + const symbol = this.getSymbolFromMarketId (this.safeString2 (ticker, 'market', 'code'), market); const previous = this.safeFloat (ticker, 'prev_closing_price'); const last = this.safeFloat (ticker, 'trade_price'); const change = this.safeFloat (ticker, 'signed_change_price'); @@ -680,8 +684,8 @@ module.exports = class upbit extends Exchange { } } } - const marketId = this.safeString (trade, 'market'); - market = this.safeValue (this.markets_by_id, marketId); + const marketId = this.safeString2 (trade, 'market', 'code'); + market = this.safeValue (this.markets_by_id, marketId, market); let fee = undefined; let feeCurrency = undefined; let symbol = undefined; @@ -1197,6 +1201,7 @@ module.exports = class upbit extends Exchange { const result = { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, @@ -1394,7 +1399,8 @@ module.exports = class upbit extends Exchange { const request = { 'currency': currency['id'], }; - const response = await this.fetchDepositAddress (code, this.extend (request, params)); + // https://github.com/ccxt/ccxt/issues/6452 + const response = await this.privatePostDepositsGenerateCoinAddress (this.extend (request, params)); // // https://docs.upbit.com/v1.0/reference#%EC%9E%85%EA%B8%88-%EC%A3%BC%EC%86%8C-%EC%83%9D%EC%84%B1-%EC%9A%94%EC%B2%AD // can be any of the two responses: @@ -1412,12 +1418,7 @@ module.exports = class upbit extends Exchange { // const message = this.safeString (response, 'message'); if (message !== undefined) { - return { - 'currency': code, - 'address': undefined, - 'tag': undefined, - 'info': response, - }; + throw new AddressPending (this.id + ' is generating ' + code + ' deposit address, call fetchDepositAddress or createDepositAddress one more time later to retrieve the generated address'); } return this.parseDepositAddress (response); } @@ -1463,7 +1464,7 @@ module.exports = class upbit extends Exchange { } sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - let url = this.implodeParams (this.urls['api'], { + let url = this.implodeParams (this.urls['api'][api], { 'hostname': this.hostname, }); url += '/' + this.version + '/' + this.implodeParams (path, params); diff --git a/TaskServer/node_modules/ccxt/js/vaultoro.js b/TaskServer/node_modules/ccxt/js/vaultoro.js index 4d57970dd..abc1ba387 100644 --- a/TaskServer/node_modules/ccxt/js/vaultoro.js +++ b/TaskServer/node_modules/ccxt/js/vaultoro.js @@ -83,6 +83,9 @@ module.exports = class vaultoro extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'info': market, + 'active': undefined, + 'precision': this.precision, + 'limits': this.limits, }); return result; } diff --git a/TaskServer/node_modules/ccxt/js/whitebit.js b/TaskServer/node_modules/ccxt/js/whitebit.js index 8f8c435d6..608f8e52a 100644 --- a/TaskServer/node_modules/ccxt/js/whitebit.js +++ b/TaskServer/node_modules/ccxt/js/whitebit.js @@ -3,7 +3,7 @@ // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); -const { ExchangeError, DDoSProtection, BadSymbol } = require ('./base/errors'); +const { ExchangeNotAvailable, ExchangeError, DDoSProtection, BadSymbol } = require ('./base/errors'); // --------------------------------------------------------------------------- @@ -107,6 +107,7 @@ module.exports = class whitebit extends Exchange { }, 'exceptions': { 'exact': { + '503': ExchangeNotAvailable, // {"response":null,"status":503,"errors":{"message":[""]},"notification":null,"warning":null,"_token":null} }, 'broad': { 'Market is not available': BadSymbol, // {"success":false,"message":{"market":["Market is not available"]},"result":[]} @@ -584,7 +585,7 @@ module.exports = class whitebit extends Exchange { } async fetchStatus (params = {}) { - const response = await this.webGetV1Healthcheck (); + const response = await this.webGetV1Healthcheck (params); const status = this.safeInteger (response, 'status'); let formattedStatus = 'ok'; if (status === 503) { @@ -617,9 +618,9 @@ module.exports = class whitebit extends Exchange { const success = this.safeValue (response, 'success'); if (!success) { const feedback = this.id + ' ' + body; - const message = this.safeValue (response, 'message'); - if (typeof message === 'string') { - this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback); + const status = this.safeString (response, 'status'); + if (typeof status === 'string') { + this.throwExactlyMatchedException (this.exceptions['exact'], status, feedback); } this.throwBroadlyMatchedException (this.exceptions['broad'], body, feedback); throw new ExchangeError (feedback); diff --git a/TaskServer/node_modules/ccxt/js/xbtce.js b/TaskServer/node_modules/ccxt/js/xbtce.js index 250a26592..1529dc94d 100644 --- a/TaskServer/node_modules/ccxt/js/xbtce.js +++ b/TaskServer/node_modules/ccxt/js/xbtce.js @@ -129,6 +129,9 @@ module.exports = class xbtce extends Exchange { 'baseId': baseId, 'quoteId': quoteId, 'info': market, + 'active': undefined, + 'precision': this.precision, + 'limits': this.limits, }); } return result; diff --git a/TaskServer/node_modules/ccxt/js/yobit.js b/TaskServer/node_modules/ccxt/js/yobit.js index 95ed4f6c6..58e452423 100644 --- a/TaskServer/node_modules/ccxt/js/yobit.js +++ b/TaskServer/node_modules/ccxt/js/yobit.js @@ -542,9 +542,13 @@ module.exports = class yobit extends Exchange { 'filled': filled, 'fee': undefined, // 'trades': this.parseTrades (order['trades'], market), + 'info': response, + 'clientOrderId': undefined, + 'average': undefined, + 'trades': undefined, }; this.orders[id] = order; - return this.extend ({ 'info': response }, order); + return order; } async cancelOrder (id, symbol = undefined, params = {}) { @@ -607,6 +611,7 @@ module.exports = class yobit extends Exchange { const result = { 'info': order, 'id': id, + 'clientOrderId': undefined, 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -620,6 +625,8 @@ module.exports = class yobit extends Exchange { 'filled': filled, 'status': status, 'fee': fee, + 'average': undefined, + 'trades': undefined, }; return result; } diff --git a/TaskServer/node_modules/ccxt/js/zaif.js b/TaskServer/node_modules/ccxt/js/zaif.js index 9c43065cf..29495f977 100644 --- a/TaskServer/node_modules/ccxt/js/zaif.js +++ b/TaskServer/node_modules/ccxt/js/zaif.js @@ -324,6 +324,16 @@ module.exports = class zaif extends Exchange { } parseOrder (order, market = undefined) { + // + // { + // "currency_pair": "btc_jpy", + // "action": "ask", + // "amount": 0.03, + // "price": 56000, + // "timestamp": 1402021125, + // "comment" : "demo" + // } + // let side = this.safeString (order, 'action'); side = (side === 'bid') ? 'buy' : 'sell'; const timestamp = this.safeTimestamp (order, 'timestamp'); @@ -348,6 +358,7 @@ module.exports = class zaif extends Exchange { } return { 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -362,6 +373,8 @@ module.exports = class zaif extends Exchange { 'remaining': undefined, 'trades': undefined, 'fee': undefined, + 'info': undefined, + 'average': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/js/zb.js b/TaskServer/node_modules/ccxt/js/zb.js index f267337a8..f4807b607 100644 --- a/TaskServer/node_modules/ccxt/js/zb.js +++ b/TaskServer/node_modules/ccxt/js/zb.js @@ -559,6 +559,7 @@ module.exports = class zb extends Exchange { return { 'info': order, 'id': id, + 'clientOrderId': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, @@ -573,6 +574,7 @@ module.exports = class zb extends Exchange { 'remaining': remaining, 'status': status, 'fee': undefined, + 'trades': undefined, }; } diff --git a/TaskServer/node_modules/ccxt/package.json b/TaskServer/node_modules/ccxt/package.json index fd4d61952..953f8eb8b 100644 --- a/TaskServer/node_modules/ccxt/package.json +++ b/TaskServer/node_modules/ccxt/package.json @@ -1,27 +1,27 @@ { - "_from": "ccxt@1.22.39", - "_id": "ccxt@1.22.39", + "_from": "ccxt@1.25.80", + "_id": "ccxt@1.25.80", "_inBundle": false, - "_integrity": "sha512-Vq4BzYS/FwRudPKQ6BQGU3SVntYv7EAQGT+2guf+e7qm45CJMhdoVwR1z89kl42fbK39XMnl8sUnRCwsKPs38A==", + "_integrity": "sha512-AUWagxMa8PMexRabbktWezlmVacj6L2Ep4844ebIXUOyME2Ommg7O/9/pq0F2Ne1IHcJnNJzHrMYQvkh2gBtlw==", "_location": "/ccxt", "_phantomChildren": {}, "_requested": { "type": "version", "registry": true, - "raw": "ccxt@1.22.39", + "raw": "ccxt@1.25.80", "name": "ccxt", "escapedName": "ccxt", - "rawSpec": "1.22.39", + "rawSpec": "1.25.80", "saveSpec": null, - "fetchSpec": "1.22.39" + "fetchSpec": "1.25.80" }, "_requiredBy": [ "#USER", "/" ], - "_resolved": "https://registry.npmjs.org/ccxt/-/ccxt-1.22.39.tgz", - "_shasum": "ca28a2dafd94089238279c9e5f2f4a041348d065", - "_spec": "ccxt@1.22.39", + "_resolved": "https://registry.npmjs.org/ccxt/-/ccxt-1.25.80.tgz", + "_shasum": "aee14637402aecc53d8a7d78af78bb7d730c84d5", + "_spec": "ccxt@1.25.80", "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer", "author": { "name": "Igor Kroitor", @@ -47,11 +47,11 @@ "browserify": "14.5.0", "chai": "4.1.2", "chai-as-promised": "7.1.1", - "eslint": "^4.19.1", - "eslint-config-airbnb-base": "12.1.0", - "eslint-plugin-import": "2.16.0", + "eslint": "^6.8.0", + "eslint-config-airbnb-base": "14.1.0", + "eslint-plugin-import": "2.20.1", "mocha": "5.2.0", - "ololog": "1.1.121" + "ololog": "1.1.155" }, "engines": { "node": ">=7.6.0" @@ -65,6 +65,8 @@ "altcoins", "api", "arbitrage", + "real-time", + "realtime", "backtest", "backtesting", "bitcoin", @@ -125,6 +127,11 @@ "trading", "usd", "volume", + "websocket", + "websockets", + "web socket", + "web sockets", + "ws", "xbt", "xrp", "zec", @@ -475,7 +482,16 @@ "BW", "timex.io", "TimeX", - "bitz.com" + "bitz.com", + "topliq.com", + "TOP.Q", + "hollaex.com", + "HollaEx", + "bybit.com", + "Bybit", + "aofex.com", + "AOFEX", + "byte-trade.com" ], "license": "MIT", "main": "./ccxt.js", @@ -488,7 +504,7 @@ "browserify": "browserify ./ccxt.browser.js > ./dist/ccxt.browser.js", "build": "npm run build-without-docs && npm run pandoc-all && npm run update-badges", "build-without-docs": "npm run export-exchanges && npm run vss && npm run check-js-syntax && npm run browserify && npm run transpile && npm run qa", - "check-js-syntax": "pwd && eslint --version && eslint 'js/*.js'", + "check-js-syntax": "pwd && eslint --version && eslint \"js/*.js\"", "check-php-syntax": "php -f php/test/syntax.php", "check-python-syntax": "cd python && tox -e qa && cd ..", "check-syntax": "npm run transpile && npm run check-js-syntax && npm run check-python-syntax && npm run check-php-syntax", @@ -499,7 +515,10 @@ "git-ignore-generated-files": "node build/git-ignore-generated-files", "git-unignore-generated-files": "node build/git-ignore-generated-files --unignore", "lint": "eslint", - "pandoc-all": "npm run pandoc-python-readme && npm run pandoc-doc-readme && npm run pandoc-doc-faq && npm run pandoc-doc-manual && npm run pandoc-doc-install && npm run pandoc-doc-exchanges && npm run pandoc-doc-exchanges-by-country", + "pandoc-all": "npm run pandoc-python-readme && npm run pandoc-doc-readme && npm run pandoc-doc-faq && npm run pandoc-doc-manual && npm run pandoc-doc-install && npm run pandoc-doc-exchanges && npm run pandoc-doc-exchanges-by-country && npm run pandoc-doc-ccxtpro-readme && npm run pandoc-doc-ccxtpro-install && npm run pandoc-doc-ccxtpro-manual", + "pandoc-doc-ccxtpro-install": "pandoc --wrap=preserve --columns=10000 --from=markdown --to=rst --output=doc/ccxt.pro.install.rst wiki/ccxt.pro.install.md", + "pandoc-doc-ccxtpro-manual": "pandoc --wrap=preserve --columns=10000 --from=markdown --to=rst --output=doc/ccxt.pro.manual.rst wiki/ccxt.pro.manual.md", + "pandoc-doc-ccxtpro-readme": "pandoc --wrap=preserve --columns=10000 --from=markdown --to=rst --output=doc/ccxt.pro.rst wiki/ccxt.pro.md", "pandoc-doc-exchanges": "pandoc --wrap=preserve --columns=10000 --from=markdown --to=rst --output=doc/exchanges.rst wiki/Exchange-Markets.md", "pandoc-doc-exchanges-by-country": "pandoc --wrap=preserve --columns=10000 --from=markdown --to=rst --output=doc/exchanges-by-country.rst wiki/Exchange-Markets-By-Country.md", "pandoc-doc-faq": "pandoc --wrap=preserve --columns=10000 --from=markdown --to=rst --output=doc/FAQ.rst wiki/FAQ.md", @@ -520,5 +539,5 @@ }, "types": "./ccxt.d.ts", "unpkg": "dist/ccxt.browser.js", - "version": "1.22.39" + "version": "1.25.80" } diff --git a/TaskServer/node_modules/easy-stack/es5.js b/TaskServer/node_modules/easy-stack/es5.js deleted file mode 100644 index a756a7bbf..000000000 --- a/TaskServer/node_modules/easy-stack/es5.js +++ /dev/null @@ -1,74 +0,0 @@ -function Stack(){ - Object.defineProperties( - this, - { - add:{ - enumerable:true, - writable:false, - value:addToStack - }, - next:{ - enumerable:true, - writable:false, - value:run - }, - clear:{ - enumerable:true, - writable:false, - value:clearStack - }, - contents:{ - enumerable:false, - get:getStack, - set:setStack - }, - autoRun:{ - enumerable:true, - writable:true, - value:true - }, - stop:{ - enumerable:true, - writable:true, - value:false - } - } - ); - - var stack=[]; - var running=false; - var stop=false; - - function clearStack(){ - stack=[]; - return stack; - } - - function getStack(){ - return stack; - } - - function setStack(val){ - stack=val; - return stack; - } - - function addToStack(){ - for(var i in arguments){ - stack.unshift(arguments[i]); - } - if(!running && !this.stop && this.autoRun){ - this.next(); - } - } - - function run(){ - running=true; - if(stack.length<1 || this.stop){ - running=false; - return; - } - - stack.shift().bind(this)(); - } -} diff --git a/TaskServer/node_modules/easy-stack/example/basic.js b/TaskServer/node_modules/easy-stack/example/basic.js deleted file mode 100644 index f0d7fbb11..000000000 --- a/TaskServer/node_modules/easy-stack/example/basic.js +++ /dev/null @@ -1,18 +0,0 @@ -var Stack=require('../stack'); -//create a new Stack instance -var stack=new Stack; -stack.autoRun=false; - -for(var i=0; i<50; i++){ - //add a bunch of stuff to the stack - stack.add(makeRequest.bind(stack,i)); -} - -stack.next(); - -function makeRequest(index){ - //do stuff - console.log(`making LIFO request ${index}`); - - this.next(); -} diff --git a/TaskServer/node_modules/easy-stack/package.json b/TaskServer/node_modules/easy-stack/package.json deleted file mode 100644 index 42a030529..000000000 --- a/TaskServer/node_modules/easy-stack/package.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "_args": [ - [ - "easy-stack@1.0.0", - "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer" - ] - ], - "_from": "easy-stack@1.0.0", - "_id": "easy-stack@1.0.0", - "_inBundle": false, - "_integrity": "sha1-EskbMIWjfwuqM26UhurEv5Tj54g=", - "_location": "/easy-stack", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "easy-stack@1.0.0", - "name": "easy-stack", - "escapedName": "easy-stack", - "rawSpec": "1.0.0", - "saveSpec": null, - "fetchSpec": "1.0.0" - }, - "_requiredBy": [ - "/js-queue" - ], - "_resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.0.tgz", - "_spec": "1.0.0", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/easy-stack/issues" - }, - "description": "Simple JS stack with auto run for node and browsers", - "engines": { - "node": ">=6.0.0" - }, - "homepage": "https://github.com/RIAEvangelist/easy-stack#readme", - "keywords": [ - "stack", - "node", - "js", - "auto", - "run", - "execute", - "browser", - "react" - ], - "license": "DBAD", - "main": "stack.js", - "name": "easy-stack", - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/easy-stack.git" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "1.0.0" -} diff --git a/TaskServer/node_modules/easy-stack/stack.js b/TaskServer/node_modules/easy-stack/stack.js deleted file mode 100644 index bfadd1dee..000000000 --- a/TaskServer/node_modules/easy-stack/stack.js +++ /dev/null @@ -1,39 +0,0 @@ -class Stack{ - constructor(){ - this.stack=[]; - this.autoRun=true; - this.running=false; - this.stop=false; - } - - clear(){ - this.stack=[]; - return this.stack; - } - - contents(val){ - if(val){ - this.stack=val; - } - return this.stack; - } - - add(...callbacks){ - this.stack.push(...callbacks); - if(!this.running && !this.stop && this.autoRun){ - this.next(); - } - } - - next(){ - this.running=true; - if(this.stack.length<1 || this.stop){ - this.running=false; - return; - } - - this.stack.pop().bind(this)(); - } -} - -module.exports=Stack; diff --git a/TaskServer/node_modules/event-pubsub/bower.json b/TaskServer/node_modules/event-pubsub/bower.json deleted file mode 100644 index a207b0a5d..000000000 --- a/TaskServer/node_modules/event-pubsub/bower.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "event-pubsub", - "description": "Super light and fast Extensible PubSub events and EventEmitters for Node and the browser with support for ES6 by default, and ES5 versions for older verions of node and older IE/Safari versions. Easy for any developer level. No frills, just high speed pubsub events!", - "main": "event-pubsub.js", - "authors": [ - "Brandon Nozaki Miller" - ], - "license": "DBAD", - "keywords": [ - "event", - "events", - "pubsub", - "node", - "browser" - ], - "homepage": "https://github.com/RIAEvangelist/event-pubsub", - "moduleType": [ - "globals", - "node" - ], - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" - ] -} diff --git a/TaskServer/node_modules/event-pubsub/es5.js b/TaskServer/node_modules/event-pubsub/es5.js deleted file mode 100644 index 7faf8b737..000000000 --- a/TaskServer/node_modules/event-pubsub/es5.js +++ /dev/null @@ -1,143 +0,0 @@ -'use strict'; - -function EventPubSub() { - this._events_={}; - this.publish=this.trigger=this.emit=emit; - this.subscribe=this.on=on; - this.once=once; - this.unSubscribe=this.off=off; - this.emit$=emit$; - - function on(type,handler,once){ - if(!handler){ - throw new ReferenceError('handler not defined.'); - } - - if(!this._events_[type]){ - this._events_[type]=[]; - } - - if(once){ - handler._once_ = once; - } - this._events_[type].push(handler); - return this; - } - - function once(type,handler){ - return this.on(type, handler, true); - } - - function off(type,handler){ - if(!this._events_[type]){ - return this; - } - - if(!handler){ - throw new ReferenceError('handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler'); - } - - if(handler=='*'){ - delete this._events_[type]; - return this; - } - - var handlers=this._events_[type]; - - while(handlers.includes(handler)){ - handlers.splice( - handlers.indexOf(handler), - 1 - ); - } - - if(handlers.length<1){ - delete this._events_[type]; - } - - return this; - } - - function emit(type){ - this.emit$.apply(this, arguments); - if(!this._events_[type]){ - return this; - } - arguments.splice=Array.prototype.splice; - arguments.splice(0,1); - - var handlers=this._events_[type]; - var onceHandled=[]; - - for(var i in handlers){ - var handler=handlers[i]; - handler.apply(this, arguments); - if(handler._once_){ - onceHandled.push(handler); - } - } - - for(var i in onceHandled){ - this.off( - type, - onceHandled[i] - ); - } - - return this; - } - - function emit$(type, args){ - if(!this._events_['*']){ - return this; - } - - var catchAll=this._events_['*']; - - args.shift=Array.prototype.shift; - args.shift(type); - - for(var handler of catchAll){ - handler.apply(this, args); - } - - return this; - } - - return this; -} - -if (!Array.prototype.includes) { - Array.prototype.includes = function(searchElement /*, fromIndex*/) { - 'use strict'; - if (this == null) { - throw new TypeError('Array.prototype.includes called on null or undefined'); - } - - var O = Object(this); - var len = parseInt(O.length, 10) || 0; - if (len === 0) { - return false; - } - var n = parseInt(arguments[1], 10) || 0; - var k; - if (n >= 0) { - k = n; - } else { - k = len + n; - if (k < 0) {k = 0;} - } - var currentElement; - while (k < len) { - currentElement = O[k]; - if (searchElement === currentElement || - (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN - return true; - } - k++; - } - return false; - }; -} - -module.exports=EventPubSub; diff --git a/TaskServer/node_modules/event-pubsub/es6.js b/TaskServer/node_modules/event-pubsub/es6.js deleted file mode 100644 index e9e859f9b..000000000 --- a/TaskServer/node_modules/event-pubsub/es6.js +++ /dev/null @@ -1,99 +0,0 @@ -'use strict'; - -class EventPubSub { - constructor( scope ) { - this._events_ = {}; - this.publish = this.trigger = this.emit; - this.subscribe = this.on; - this.unSubscribe = this.off; - } - - on( type, handler, once ) { - if ( !handler ) { - throw new ReferenceError( 'handler not defined.' ); - } - - if ( !this._events_[ type ] ) { - this._events_[ type ] = []; - } - - if(once){ - handler._once_ = once; - } - - this._events_[ type ].push( handler ); - return this; - } - - once( type, handler ) { - return this.on( type, handler, true ); - } - - off( type, handler ) { - if ( !this._events_[ type ] ) { - return this; - } - - if ( !handler ) { - throw new ReferenceError( 'handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler' ); - } - - if ( handler == '*' ) { - delete this._events_[ type ]; - return this; - } - - const handlers = this._events_[ type ]; - - while ( handlers.includes( handler ) ) { - handlers.splice( - handlers.indexOf( handler ), - 1 - ); - } - - if ( handlers.length < 1 ) { - delete this._events_[ type ]; - } - - return this; - } - - emit( type, ...args ) { - if ( !this._events_[ type ] ) { - return this.emit$( type, ...args ); - } - - const handlers = this._events_[ type ]; - const onceHandled=[]; - - for ( let handler of handlers ) { - handler.apply( this, args ); - if(handler._once_){ - onceHandled.push(handler); - } - } - - for(let handler of onceHandled){ - this.off(type,handler); - } - - return this.emit$( type, ...args ); - } - - emit$( type, ...args ) { - if ( !this._events_[ '*' ] ) { - return this; - } - - const catchAll = this._events_[ '*' ]; - - for ( let handler of catchAll ) { - handler.call( this, type, ...args ); - } - - return this; - } -} - -module.exports = EventPubSub; diff --git a/TaskServer/node_modules/event-pubsub/event-pubsub-browser-es5.js b/TaskServer/node_modules/event-pubsub/event-pubsub-browser-es5.js deleted file mode 100644 index 03f27625e..000000000 --- a/TaskServer/node_modules/event-pubsub/event-pubsub-browser-es5.js +++ /dev/null @@ -1,141 +0,0 @@ -'use strict'; - -window.EventPubSub=function EventPubSub() { - this._events_={}; - this.publish=this.trigger=this.emit=emit; - this.subscribe=this.on=on; - this.once=once; - this.unSubscribe=this.off=off; - this.emit$=emit$; - - function on(type,handler,once){ - if(!handler){ - throw new ReferenceError('handler not defined.'); - } - - if(!this._events_[type]){ - this._events_[type]=[]; - } - - if(once){ - handler._once_ = once; - } - this._events_[type].push(handler); - return this; - } - - function once(type,handler){ - return this.on(type, handler, true); - } - - function off(type,handler){ - if(!this._events_[type]){ - return this; - } - - if(!handler){ - throw new ReferenceError('handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler'); - } - - if(handler=='*'){ - delete this._events_[type]; - return this; - } - - var handlers=this._events_[type]; - - while(handlers.includes(handler)){ - handlers.splice( - handlers.indexOf(handler), - 1 - ); - } - - if(handlers.length<1){ - delete this._events_[type]; - } - - return this; - } - - function emit(type){ - this.emit$.apply(this, arguments); - if(!this._events_[type]){ - return this; - } - arguments.splice=Array.prototype.splice; - arguments.splice(0,1); - - var handlers=this._events_[type]; - var onceHandled=[]; - - for(var i in handlers){ - var handler=handlers[i]; - handler.apply(this, arguments); - if(handler._once_){ - onceHandled.push(handler); - } - } - - for(var i in onceHandled){ - this.off( - type, - onceHandled[i] - ); - } - - return this; - } - - function emit$(type, args){ - if(!this._events_['*']){ - return this; - } - - var catchAll=this._events_['*']; - - args.shift=Array.prototype.shift; - args.shift(type); - - for(var handler of catchAll){ - handler.apply(this, args); - } - - return this; - } - - return this; -} - -if (!Array.prototype.includes) { - Array.prototype.includes = function(searchElement /*, fromIndex*/) { - 'use strict'; - if (this == null) { - throw new TypeError('Array.prototype.includes called on null or undefined'); - } - - var O = Object(this); - var len = parseInt(O.length, 10) || 0; - if (len === 0) { - return false; - } - var n = parseInt(arguments[1], 10) || 0; - var k; - if (n >= 0) { - k = n; - } else { - k = len + n; - if (k < 0) {k = 0;} - } - var currentElement; - while (k < len) { - currentElement = O[k]; - if (searchElement === currentElement || - (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN - return true; - } - k++; - } - return false; - }; -} diff --git a/TaskServer/node_modules/event-pubsub/event-pubsub-browser.js b/TaskServer/node_modules/event-pubsub/event-pubsub-browser.js deleted file mode 100644 index d0bcd7b56..000000000 --- a/TaskServer/node_modules/event-pubsub/event-pubsub-browser.js +++ /dev/null @@ -1,130 +0,0 @@ -'use strict'; - -window.EventPubSub=class EventPubSub { - constructor( scope ) { - this._events_ = {}; - this.publish = this.trigger = this.emit; - this.subscribe = this.on; - this.unSubscribe = this.off; - } - - on( type, handler, once ) { - if ( !handler ) { - throw new ReferenceError( 'handler not defined.' ); - } - - if ( !this._events_[ type ] ) { - this._events_[ type ] = []; - } - - if(once){ - handler._once_ = once; - } - - this._events_[ type ].push( handler ); - return this; - } - - once( type, handler ) { - return this.on( type, handler, true ); - } - - off( type, handler ) { - if ( !this._events_[ type ] ) { - return this; - } - - if ( !handler ) { - throw new ReferenceError( 'handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler' ); - } - - if ( handler == '*' ) { - delete this._events_[ type ]; - return this; - } - - const handlers = this._events_[ type ]; - - while ( handlers.includes( handler ) ) { - handlers.splice( - handlers.indexOf( handler ), - 1 - ); - } - - if ( handlers.length < 1 ) { - delete this._events_[ type ]; - } - - return this; - } - - emit( type, ...args ) { - if ( !this._events_[ type ] ) { - return this.emit$( type, ...args ); - } - - const handlers = this._events_[ type ]; - const onceHandled=[]; - - for ( let handler of handlers ) { - handler.apply( this, args ); - if(handler._once_){ - onceHandled.push(handler); - } - } - - for(let handler of onceHandled){ - this.off(type,handler); - } - - return this.emit$( type, ...args ); - } - - emit$( type, ...args ) { - if ( !this._events_[ '*' ] ) { - return this; - } - - const catchAll = this._events_[ '*' ]; - - for ( let handler of catchAll ) { - handler.call( this, type, ...args ); - } - - return this; - } -} - -if (!Array.prototype.includes) { - Array.prototype.includes = function(searchElement /*, fromIndex*/) { - 'use strict'; - if (this == null) { - throw new TypeError('Array.prototype.includes called on null or undefined'); - } - - var O = Object(this); - var len = parseInt(O.length, 10) || 0; - if (len === 0) { - return false; - } - var n = parseInt(arguments[1], 10) || 0; - var k; - if (n >= 0) { - k = n; - } else { - k = len + n; - if (k < 0) {k = 0;} - } - var currentElement; - while (k < len) { - currentElement = O[k]; - if (searchElement === currentElement || - (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN - return true; - } - k++; - } - return false; - }; -} diff --git a/TaskServer/node_modules/event-pubsub/event-pubsub.js b/TaskServer/node_modules/event-pubsub/event-pubsub.js deleted file mode 100644 index 65bd02419..000000000 --- a/TaskServer/node_modules/event-pubsub/event-pubsub.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -let EventPubSub = require('./es5'); -if(process.version[1]>5){ - EventPubSub = require('./es6'); -} - -module.exports=EventPubSub; diff --git a/TaskServer/node_modules/event-pubsub/package.json b/TaskServer/node_modules/event-pubsub/package.json deleted file mode 100644 index b5d342361..000000000 --- a/TaskServer/node_modules/event-pubsub/package.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "_args": [ - [ - "event-pubsub@4.3.0", - "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer" - ] - ], - "_from": "event-pubsub@4.3.0", - "_id": "event-pubsub@4.3.0", - "_inBundle": false, - "_integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==", - "_location": "/event-pubsub", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "event-pubsub@4.3.0", - "name": "event-pubsub", - "escapedName": "event-pubsub", - "rawSpec": "4.3.0", - "saveSpec": null, - "fetchSpec": "4.3.0" - }, - "_requiredBy": [ - "/node-ipc" - ], - "_resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz", - "_spec": "4.3.0", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/event-pubsub/issues" - }, - "description": "Super light and fast Extensible PubSub events and EventEmitters for Node and the browser with support for ES6 by default, and ES5 versions for older verions of node and older IE/Safari versions. Easy for any developer level. No frills, just high speed pubsub events!", - "directories": { - "example": "examples" - }, - "engines": { - "node": ">=4.0.0" - }, - "homepage": "https://github.com/RIAEvangelist/event-pubsub", - "keywords": [ - "event", - "events", - "pubsub", - "node", - "browser" - ], - "license": "Unlicense", - "main": "event-pubsub.js", - "name": "event-pubsub", - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/event-pubsub.git" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "4.3.0" -} diff --git a/TaskServer/node_modules/js-message/Message.js b/TaskServer/node_modules/js-message/Message.js deleted file mode 100644 index 9a4698232..000000000 --- a/TaskServer/node_modules/js-message/Message.js +++ /dev/null @@ -1,71 +0,0 @@ -function Message() { - Object.defineProperties( - this, { - data: { - enumerable: true, - get: getData, - set: setData - }, - type: { - enumerable: true, - get: getType, - set: setType - }, - load:{ - enumarable:true, - writable:false, - value:parse - }, - JSON: { - enumerable: true, - get: getJSON - } - } - ); - - var type = ''; - var data = {}; - - function getType() { - return type; - } - - function getData() { - return data; - } - - function getJSON() { - return JSON.stringify( - { - type: type, - data: data - } - ); - } - - function setType(value) { - type = value; - } - - function setData(value) { - data = value; - } - - function parse(message){ - try{ - var message=JSON.parse(message); - type=message.type; - data=message.data; - }catch(err){ - var badMessage=message; - type='error', - data={ - message:'Invalid JSON response format', - err:err, - response:badMessage - } - } - } -} - -module.exports=Message; diff --git a/TaskServer/node_modules/js-message/js-message-vanilla.js b/TaskServer/node_modules/js-message/js-message-vanilla.js deleted file mode 100644 index 0c49c2b6c..000000000 --- a/TaskServer/node_modules/js-message/js-message-vanilla.js +++ /dev/null @@ -1,75 +0,0 @@ -( - function(){ - function Message() { - Object.defineProperties( - this, { - data: { - enumerable: true, - get: getData, - set: setData - }, - type: { - enumerable: true, - get: getType, - set: setType - }, - load:{ - enumarable:true, - writable:false, - value:parse - }, - JSON: { - enumerable: true, - get: getJSON - } - } - ); - - var type = ''; - var data = {}; - - function getType() { - return type; - } - - function getData() { - return data; - } - - function getJSON() { - return JSON.stringify( - { - type: type, - data: data - } - ); - } - - function setType(value) { - type = value; - } - - function setData(value) { - data = value; - } - - function parse(message){ - try{ - var message=JSON.parse(message); - type=message.type; - data=message.data; - }catch(err){ - var badMessage=message; - type='error', - data={ - message:'Invalid JSON response format', - err:err, - response:badMessage - } - } - } - } - - window.message=Message; - } -)(); diff --git a/TaskServer/node_modules/js-message/package.json b/TaskServer/node_modules/js-message/package.json deleted file mode 100644 index 329078ca6..000000000 --- a/TaskServer/node_modules/js-message/package.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "_args": [ - [ - "js-message@1.0.5", - "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer" - ] - ], - "_from": "js-message@1.0.5", - "_id": "js-message@1.0.5", - "_inBundle": false, - "_integrity": "sha1-IwDSSxrwjondCVvBpMnJz8uJLRU=", - "_location": "/js-message", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "js-message@1.0.5", - "name": "js-message", - "escapedName": "js-message", - "rawSpec": "1.0.5", - "saveSpec": null, - "fetchSpec": "1.0.5" - }, - "_requiredBy": [ - "/node-ipc" - ], - "_resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.5.tgz", - "_spec": "1.0.5", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/js-message/issues" - }, - "dependencies": {}, - "description": "normalized JS Object and JSON message and event protocol for node.js, vanialla js, react.js, components, actions, stores and dispatchers", - "devDependencies": {}, - "engines": { - "node": ">=0.6.0" - }, - "homepage": "https://github.com/RIAEvangelist/js-message#readme", - "keywords": [ - "message", - "normalize", - "events", - "js", - "json", - "protocol", - "ipc", - "node", - "nodejs", - "node.js", - "react", - "react.js", - "reactjs", - "websocket", - "websockets", - "web", - "socket", - "sockets", - "ws", - "flux", - "reflux", - "component", - "components", - "store", - "stores", - "action", - "actions" - ], - "license": "DBAD", - "main": "Message.js", - "name": "js-message", - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/js-message.git" - }, - "scripts": { - "start": "node devServer.js", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "1.0.5" -} diff --git a/TaskServer/node_modules/js-queue/package.json b/TaskServer/node_modules/js-queue/package.json deleted file mode 100644 index d9f3ab07a..000000000 --- a/TaskServer/node_modules/js-queue/package.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "_args": [ - [ - "js-queue@2.0.0", - "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer" - ] - ], - "_from": "js-queue@2.0.0", - "_id": "js-queue@2.0.0", - "_inBundle": false, - "_integrity": "sha1-NiITz4YPRo8BJfxslqvBdCUx+Ug=", - "_location": "/js-queue", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "js-queue@2.0.0", - "name": "js-queue", - "escapedName": "js-queue", - "rawSpec": "2.0.0", - "saveSpec": null, - "fetchSpec": "2.0.0" - }, - "_requiredBy": [ - "/node-ipc" - ], - "_resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.0.tgz", - "_spec": "2.0.0", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/js-queue/issues" - }, - "dependencies": { - "easy-stack": "^1.0.0" - }, - "description": "Simple JS queue with auto run for node and browsers", - "engines": { - "node": ">=1.0.0" - }, - "homepage": "https://github.com/RIAEvangelist/js-queue#readme", - "keywords": [ - "queue", - "node", - "js", - "auto", - "run", - "execute", - "browser", - "react" - ], - "license": "DBAD", - "main": "queue.js", - "name": "js-queue", - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/js-queue.git" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "2.0.0" -} diff --git a/TaskServer/node_modules/js-queue/queue-vanilla.js b/TaskServer/node_modules/js-queue/queue-vanilla.js deleted file mode 100644 index 6f15495ae..000000000 --- a/TaskServer/node_modules/js-queue/queue-vanilla.js +++ /dev/null @@ -1,74 +0,0 @@ -function Queue(){ - Object.defineProperties( - this, - { - add:{ - enumerable:true, - writable:false, - value:addToQueue - }, - next:{ - enumerable:true, - writable:false, - value:run - }, - clear:{ - enumerable:true, - writable:false, - value:clearQueue - }, - contents:{ - enumerable:false, - get:getQueue, - set:setQueue - }, - autoRun:{ - enumerable:true, - writable:true, - value:true - }, - stop:{ - enumerable:true, - writable:true, - value:false - } - } - ); - - var queue=[]; - var running=false; - var stop=false; - - function clearQueue(){ - queue=[]; - return queue; - } - - function getQueue(){ - return queue; - } - - function setQueue(val){ - queue=val; - return queue; - } - - function addToQueue(){ - for(var i in arguments){ - queue.push(arguments[i]); - } - if(!running && !this.stop && this.autoRun){ - this.next(); - } - } - - function run(){ - running=true; - if(queue.length<1 || this.stop){ - running=false; - return; - } - - queue.shift().bind(this)(); - } -} diff --git a/TaskServer/node_modules/js-queue/queue.js b/TaskServer/node_modules/js-queue/queue.js deleted file mode 100644 index a8698d7e9..000000000 --- a/TaskServer/node_modules/js-queue/queue.js +++ /dev/null @@ -1,76 +0,0 @@ -function Queue(asStack){ - Object.defineProperties( - this, - { - add:{ - enumerable:true, - writable:false, - value:addToQueue - }, - next:{ - enumerable:true, - writable:false, - value:run - }, - clear:{ - enumerable:true, - writable:false, - value:clearQueue - }, - contents:{ - enumerable:false, - get:getQueue, - set:setQueue - }, - autoRun:{ - enumerable:true, - writable:true, - value:true - }, - stop:{ - enumerable:true, - writable:true, - value:false - } - } - ); - - var queue=[]; - var running=false; - var stop=false; - - function clearQueue(){ - queue=[]; - return queue; - } - - function getQueue(){ - return queue; - } - - function setQueue(val){ - queue=val; - return queue; - } - - function addToQueue(){ - for(var i in arguments){ - queue.push(arguments[i]); - } - if(!running && !this.stop && this.autoRun){ - this.next(); - } - } - - function run(){ - running=true; - if(queue.length<1 || this.stop){ - running=false; - return; - } - - queue.shift().bind(this)(); - } -} - -module.exports=Queue; diff --git a/TaskServer/node_modules/js-queue/stack.js b/TaskServer/node_modules/js-queue/stack.js deleted file mode 100644 index a9c25640e..000000000 --- a/TaskServer/node_modules/js-queue/stack.js +++ /dev/null @@ -1,3 +0,0 @@ -const Stack=require('easy-stack'); - -module.exports = Stack; diff --git a/TaskServer/node_modules/minimist/example/parse.js b/TaskServer/node_modules/minimist/example/parse.js index abff3e8ee..f7c8d4980 100644 --- a/TaskServer/node_modules/minimist/example/parse.js +++ b/TaskServer/node_modules/minimist/example/parse.js @@ -1,2 +1,2 @@ var argv = require('../')(process.argv.slice(2)); -console.dir(argv); +console.log(argv); diff --git a/TaskServer/node_modules/minimist/index.js b/TaskServer/node_modules/minimist/index.js index 6a0559d58..d2afe5e4d 100644 --- a/TaskServer/node_modules/minimist/index.js +++ b/TaskServer/node_modules/minimist/index.js @@ -68,12 +68,21 @@ module.exports = function (args, opts) { function setKey (obj, keys, value) { var o = obj; - keys.slice(0,-1).forEach(function (key) { + for (var i = 0; i < keys.length-1; i++) { + var key = keys[i]; + if (key === '__proto__') return; if (o[key] === undefined) o[key] = {}; + if (o[key] === Object.prototype || o[key] === Number.prototype + || o[key] === String.prototype) o[key] = {}; + if (o[key] === Array.prototype) o[key] = []; o = o[key]; - }); + } var key = keys[keys.length - 1]; + if (key === '__proto__') return; + if (o === Object.prototype || o === Number.prototype + || o === String.prototype) o = {}; + if (o === Array.prototype) o = []; if (o[key] === undefined || flags.bools[key] || typeof o[key] === 'boolean') { o[key] = value; } @@ -171,7 +180,7 @@ module.exports = function (args, opts) { setArg(key, args[i+1], arg); i++; } - else if (args[i+1] && /true|false/.test(args[i+1])) { + else if (args[i+1] && /^(true|false)$/.test(args[i+1])) { setArg(key, args[i+1] === 'true', arg); i++; } diff --git a/TaskServer/node_modules/minimist/package.json b/TaskServer/node_modules/minimist/package.json index 7e99e2076..fd7871c8f 100644 --- a/TaskServer/node_modules/minimist/package.json +++ b/TaskServer/node_modules/minimist/package.json @@ -1,8 +1,8 @@ { "_from": "minimist@^1.2.0", - "_id": "minimist@1.2.0", + "_id": "minimist@1.2.5", "_inBundle": false, - "_integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "_integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "_location": "/minimist", "_phantomChildren": {}, "_requested": { @@ -18,8 +18,8 @@ "_requiredBy": [ "/telegraf" ], - "_resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "_shasum": "a35008b20f41383eec1fb914f4cd5df79a264284", + "_resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "_shasum": "67d66014b66a6a8aaa0c083c5fd58df4e4e97602", "_spec": "minimist@^1.2.0", "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer\\node_modules\\telegraf", "author": { @@ -69,5 +69,5 @@ "opera/12" ] }, - "version": "1.2.0" + "version": "1.2.5" } diff --git a/TaskServer/node_modules/minimist/test/bool.js b/TaskServer/node_modules/minimist/test/bool.js index 14b0717ce..5f7dbde16 100644 --- a/TaskServer/node_modules/minimist/test/bool.js +++ b/TaskServer/node_modules/minimist/test/bool.js @@ -164,3 +164,15 @@ test('boolean --boool=false', function (t) { t.same(parsed.boool, false); t.end(); }); + +test('boolean using something similar to true', function (t) { + var opts = { boolean: 'h' }; + var result = parse(['-h', 'true.txt'], opts); + var expected = { + h: true, + '_': ['true.txt'] + }; + + t.same(result, expected); + t.end(); +}); \ No newline at end of file diff --git a/TaskServer/node_modules/minimist/test/proto.js b/TaskServer/node_modules/minimist/test/proto.js new file mode 100644 index 000000000..8649107ec --- /dev/null +++ b/TaskServer/node_modules/minimist/test/proto.js @@ -0,0 +1,44 @@ +var parse = require('../'); +var test = require('tape'); + +test('proto pollution', function (t) { + var argv = parse(['--__proto__.x','123']); + t.equal({}.x, undefined); + t.equal(argv.__proto__.x, undefined); + t.equal(argv.x, undefined); + t.end(); +}); + +test('proto pollution (array)', function (t) { + var argv = parse(['--x','4','--x','5','--x.__proto__.z','789']); + t.equal({}.z, undefined); + t.deepEqual(argv.x, [4,5]); + t.equal(argv.x.z, undefined); + t.equal(argv.x.__proto__.z, undefined); + t.end(); +}); + +test('proto pollution (number)', function (t) { + var argv = parse(['--x','5','--x.__proto__.z','100']); + t.equal({}.z, undefined); + t.equal((4).z, undefined); + t.equal(argv.x, 5); + t.equal(argv.x.z, undefined); + t.end(); +}); + +test('proto pollution (string)', function (t) { + var argv = parse(['--x','abc','--x.__proto__.z','def']); + t.equal({}.z, undefined); + t.equal('...'.z, undefined); + t.equal(argv.x, 'abc'); + t.equal(argv.x.z, undefined); + t.end(); +}); + +test('proto pollution (constructor)', function (t) { + var argv = parse(['--constructor.prototype.y','123']); + t.equal({}.y, undefined); + t.equal(argv.y, undefined); + t.end(); +}); diff --git a/TaskServer/node_modules/node-ipc/dao/client.js b/TaskServer/node_modules/node-ipc/dao/client.js deleted file mode 100644 index 41ce50411..000000000 --- a/TaskServer/node_modules/node-ipc/dao/client.js +++ /dev/null @@ -1,257 +0,0 @@ -'use strict'; - -const net = require('net'), - tls = require('tls'), - EventParser = require('../entities/EventParser.js'), - Message = require('js-message'), - fs = require('fs'), - Queue = require('js-queue'); - -let Events = require('event-pubsub/es5'); -if(process.version[1]>4){ - Events = require('event-pubsub'); -} - -let eventParser = new EventParser(); - -class Client extends Events{ - constructor(config,log){ - super(); - Object.assign( - this, - { - Client : Client, - config : config, - queue : new Queue, - socket : false, - connect : connect, - emit : emit, - log : log, - retriesRemaining:config.maxRetries||0, - explicitlyDisconnected: false - } - ); - - eventParser=new EventParser(this.config); - } -} - -function emit(type,data){ - this.log('dispatching event to ', this.id, this.path, ' : ', type, ',', data); - - let message=new Message; - message.type=type; - message.data=data; - - if(this.config.rawBuffer){ - message=new Buffer(type,this.config.encoding); - }else{ - message=eventParser.format(message); - } - - if(!this.config.sync){ - this.socket.write(message); - return; - } - - this.queue.add( - syncEmit.bind(this,message) - ); -} - -function syncEmit(message){ - this.log('dispatching event to ', this.id, this.path, ' : ', message); - this.socket.write(message); -} - -function connect(){ - //init client object for scope persistance especially inside of socket events. - let client=this; - - client.log('requested connection to ', client.id, client.path); - if(!this.path){ - client.log('\n\n######\nerror: ', client.id ,' client has not specified socket path it wishes to connect to.'); - return; - } - - const options={}; - - if(!client.port){ - client.log('Connecting client on Unix Socket :', client.path); - - options.path=client.path; - - if (process.platform ==='win32' && !client.path.startsWith('\\\\.\\pipe\\')){ - options.path = options.path.replace(/^\//, ''); - options.path = options.path.replace(/\//g, '-'); - options.path= `\\\\.\\pipe\\${options.path}`; - } - - client.socket = net.connect(options); - }else{ - options.host=client.path; - options.port=client.port; - - if(client.config.interface.localAddress){ - options.localAddress=client.config.interface.localAddress; - } - - if(client.config.interface.localPort){ - options.localPort=client.config.interface.localPort; - } - - if(client.config.interface.family){ - options.family=client.config.interface.family; - } - - if(client.config.interface.hints){ - options.hints=client.config.interface.hints; - } - - if(client.config.interface.lookup){ - options.lookup=client.config.interface.lookup; - } - - if(!client.config.tls){ - client.log('Connecting client via TCP to', options); - client.socket = net.connect(options); - }else{ - client.log('Connecting client via TLS to', client.path ,client.port,client.config.tls); - if(client.config.tls.private){ - client.config.tls.key=fs.readFileSync(client.config.tls.private); - } - if(client.config.tls.public){ - client.config.tls.cert=fs.readFileSync(client.config.tls.public); - } - if(client.config.tls.trustedConnections){ - if(typeof client.config.tls.trustedConnections === 'string'){ - client.config.tls.trustedConnections=[client.config.tls.trustedConnections]; - } - client.config.tls.ca=[]; - for(let i=0; i4){ - Events = require('event-pubsub'); -} - -let eventParser = new EventParser(); - -class Server extends Events{ - constructor(path,config,log,port){ - super(); - Object.assign( - this, - { - config : config, - path : path, - port : port, - udp4 : false, - udp6 : false, - log : log, - server : false, - sockets : [], - emit : emit, - broadcast : broadcast - } - ); - - eventParser=new EventParser(this.config); - - this.on( - 'close', - serverClosed.bind(this) - ); - } - - onStart(socket){ - this.trigger( - 'start', - socket - ); - } - - stop(){ - this.server.close(); - } - - start(){ - if(!this.path){ - this.log('Socket Server Path not specified, refusing to start'); - return; - } - - if(this.config.unlink){ - fs.unlink( - this.path, - startServer.bind(this) - ); - }else{ - startServer.bind(this)(); - } - } -} - -function emit(socket, type, data){ - this.log('dispatching event to socket', ' : ', type, data); - - let message=new Message; - message.type=type; - message.data=data; - - if(this.config.rawBuffer){ - this.log(this.config.encoding) - message=new Buffer(type,this.config.encoding); - }else{ - message=eventParser.format(message); - } - - if(this.udp4 || this.udp6){ - - if(!socket.address || !socket.port){ - this.log('Attempting to emit to a single UDP socket without supplying socket address or port. Redispatching event as broadcast to all connected sockets'); - this.broadcast(type,data); - return; - } - - this.server.write( - message, - socket - ); - return; - } - - socket.write(message); -} - -function broadcast(type,data){ - this.log('broadcasting event to all known sockets listening to ', this.path,' : ', ((this.port)?this.port:''), type, data); - let message=new Message; - message.type=type; - message.data=data; - - if(this.config.rawBuffer){ - message=new Buffer(type,this.config.encoding); - }else{ - message=eventParser.format(message); - } - - if(this.udp4 || this.udp6){ - for(let i=1, count=this.sockets.length; i0){ - let message=new Message; - message.load(data.shift()); - - // Only set the sock id if it is specified. - if (message.data && message.data.id){ - sock.id=message.data.id; - } - - this.log('received event of : ',message.type,message.data); - - this.publish( - message.type, - message.data, - sock - ); - } -} - -function socketClosed(socket){ - this.publish( - 'close', - socket - ); -} - -function serverCreated(socket) { - this.sockets.push(socket); - - if(socket.setEncoding){ - socket.setEncoding(this.config.encoding); - } - - this.log('## socket connection to server detected ##'); - socket.on( - 'close', - socketClosed.bind(this) - ); - - socket.on( - 'error', - function(err){ - this.log('server socket error',err); - - this.publish('error',err); - }.bind(this) - ); - - socket.on( - 'data', - gotData.bind(this,socket) - ); - - socket.on( - 'message', - function(msg,rinfo) { - if (!rinfo){ - return; - } - - this.log('Received UDP message from ', rinfo.address, rinfo.port); - let data; - - if(this.config.rawSocket){ - data=new Buffer(msg,this.config.encoding); - }else{ - data=msg.toString(); - } - socket.emit('data',data,rinfo); - }.bind(this) - ); - - this.publish( - 'connect', - socket - ); - - if(this.config.rawBuffer){ - return; - } -} - -function startServer() { - this.log( - 'starting server on ',this.path, - ((this.port)?`:${this.port}`:'') - ); - - if(!this.udp4 && !this.udp6){ - this.log('starting TLS server',this.config.tls); - if(!this.config.tls){ - this.server=net.createServer( - serverCreated.bind(this) - ); - }else{ - startTLSServer.bind(this)(); - } - }else{ - this.server=dgram.createSocket( - ((this.udp4)? 'udp4':'udp6') - ); - this.server.write=UDPWrite.bind(this); - this.server.on( - 'listening', - function UDPServerStarted() { - serverCreated.bind(this)(this.server); - }.bind(this) - ); - } - - this.server.on( - 'error', - function(err){ - this.log('server error',err); - - this.publish( - 'error', - err - ); - }.bind(this) - ); - - this.server.maxConnections=this.config.maxConnections; - - if(!this.port){ - this.log('starting server as', 'Unix || Windows Socket'); - if (process.platform ==='win32'){ - this.path = this.path.replace(/^\//, ''); - this.path = this.path.replace(/\//g, '-'); - this.path= `\\\\.\\pipe\\${this.path}`; - } - - this.server.listen( - this.path, - this.onStart.bind(this) - ); - - return; - } - - if(!this.udp4 && !this.udp6){ - this.log('starting server as', (this.config.tls?'TLS':'TCP')); - this.server.listen( - this.port, - this.path, - this.onStart.bind(this) - ); - return; - } - - this.log('starting server as',((this.udp4)? 'udp4':'udp6')); - - this.server.bind( - this.port, - this.path - ); - - this.onStart( - { - address : this.path, - port : this.port - } - ); -} - -function startTLSServer(){ - this.log('starting TLS server',this.config.tls); - if(this.config.tls.private){ - this.config.tls.key=fs.readFileSync(this.config.tls.private); - }else{ - this.config.tls.key=fs.readFileSync(`${__dirname}/../local-node-ipc-certs/private/server.key`); - } - if(this.config.tls.public){ - this.config.tls.cert=fs.readFileSync(this.config.tls.public); - }else{ - this.config.tls.cert=fs.readFileSync(`${__dirname}/../local-node-ipc-certs/server.pub`); - } - if(this.config.tls.dhparam){ - this.config.tls.dhparam=fs.readFileSync(this.config.tls.dhparam); - } - if(this.config.tls.trustedConnections){ - if(typeof this.config.tls.trustedConnections === 'string'){ - this.config.tls.trustedConnections=[this.config.tls.trustedConnections]; - } - this.config.tls.ca=[]; - for(let i=0; i 0) { - // getting the family of first network interface available - IPType = networkInterfaces [ - Object.keys( networkInterfaces )[0] - ][0].family; - } - return IPType; -} - -module.exports=Defaults; diff --git a/TaskServer/node_modules/node-ipc/entities/EventParser.js b/TaskServer/node_modules/node-ipc/entities/EventParser.js deleted file mode 100644 index 8ac1f2bda..000000000 --- a/TaskServer/node_modules/node-ipc/entities/EventParser.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -const Defaults = require('./Defaults.js'); - -class Parser{ - constructor(config){ - if(!config){ - config=new Defaults; - } - this.delimiter=config.delimiter; - } - - format(message){ - if(!message.data && message.data!==false && message.data!==0){ - message.data={}; - } - if(message.data['_maxListeners']){ - message.data={}; - } - - message=message.JSON+this.delimiter; - return message; - } - - parse(data){ - let events=data.split(this.delimiter); - events.pop(); - return events; - } -} - -module.exports=Parser; diff --git a/TaskServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/goodbye-client.js b/TaskServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/goodbye-client.js deleted file mode 100644 index 9d5ce05d6..000000000 --- a/TaskServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/goodbye-client.js +++ /dev/null @@ -1,44 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'goodbye'; -ipc.config.retry= 1500; -ipc.config.maxRetries= 10; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'goodbye' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/hello-client.js b/TaskServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/hello-client.js deleted file mode 100644 index 74136333d..000000000 --- a/TaskServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/hello-client.js +++ /dev/null @@ -1,50 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.maxRetries=10; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data.message); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/world-server.js b/TaskServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/world-server.js deleted file mode 100644 index 2bef44794..000000000 --- a/TaskServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/world-server.js +++ /dev/null @@ -1,51 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -var messages={ - goodbye:false, - hello:false -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - ipc.log('got a message from', (data.id), (data.message)); - messages[data.id]=true; - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - - if(messages.hello && messages.goodbye){ - ipc.log('got all required events, telling clients to kill connection'); - ipc.server.broadcast( - 'kill.connection', - { - id:ipc.config.id - } - ); - } - } - ); - } -); - - - - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/TCPSocket/basic/hello-client.js b/TaskServer/node_modules/node-ipc/example/TCPSocket/basic/hello-client.js deleted file mode 100644 index 6ae692edf..000000000 --- a/TaskServer/node_modules/node-ipc/example/TCPSocket/basic/hello-client.js +++ /dev/null @@ -1,39 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/TCPSocket/basic/world-server.js b/TaskServer/node_modules/node-ipc/example/TCPSocket/basic/world-server.js deleted file mode 100644 index 6c8790170..000000000 --- a/TaskServer/node_modules/node-ipc/example/TCPSocket/basic/world-server.js +++ /dev/null @@ -1,44 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.maxConnections=1; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log('DISCONNECTED\n\n',arguments); - } - ); - } -); - -ipc.server.on( - 'error', - function(err){ - ipc.log('Got an ERROR!',err); - } -); - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/TCPSocket/basicSync/hello-client.js b/TaskServer/node_modules/node-ipc/example/TCPSocket/basicSync/hello-client.js deleted file mode 100644 index 292415053..000000000 --- a/TaskServer/node_modules/node-ipc/example/TCPSocket/basicSync/hello-client.js +++ /dev/null @@ -1,46 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.sync= true; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - - //queue up a bunch of requests to be sent synchronously - for(var i=0; i<10; i++){ - ipc.of.world.emit( - 'message', - 'hello'+i - ); - } - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data,'\n\n'); - } - ); - } -); - -console.log(ipc); diff --git a/TaskServer/node_modules/node-ipc/example/TCPSocket/basicSync/world-server.js b/TaskServer/node_modules/node-ipc/example/TCPSocket/basicSync/world-server.js deleted file mode 100644 index 3e817da13..000000000 --- a/TaskServer/node_modules/node-ipc/example/TCPSocket/basicSync/world-server.js +++ /dev/null @@ -1,45 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.sync = true; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - //fake some synch procedural code - setTimeout( - function(){ - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - }, - 3000 - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/hello-client.js b/TaskServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/hello-client.js deleted file mode 100644 index b6ac81f6b..000000000 --- a/TaskServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/hello-client.js +++ /dev/null @@ -1,35 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'hello' - ); - } - ); - - ipc.of.world.on( - 'data', - function(data){ - ipc.log('got a message from world : ', data,data.toString()); - } - ); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/world.server.js b/TaskServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/world.server.js deleted file mode 100644 index 5da4de4d5..000000000 --- a/TaskServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/world.server.js +++ /dev/null @@ -1,40 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.serveNet( - function(){ - ipc.server.on( - 'connect', - function(socket){ - ipc.server.emit( - socket, - 'hello' - ); - } - ); - - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data,data.toString()); - ipc.server.emit( - socket, - 'goodbye' - ); - } - ); - } -); - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/goodbye-client.js b/TaskServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/goodbye-client.js deleted file mode 100644 index 508702d01..000000000 --- a/TaskServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/goodbye-client.js +++ /dev/null @@ -1,47 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'goodbye'; -ipc.config.retry= 1500; -ipc.config.maxRetries= 10; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'goodbye' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/hello-client.js b/TaskServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/hello-client.js deleted file mode 100644 index 16fd21fc3..000000000 --- a/TaskServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/hello-client.js +++ /dev/null @@ -1,53 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.maxRetries=10; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data.message); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/world-server.js b/TaskServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/world-server.js deleted file mode 100644 index 0c52c268d..000000000 --- a/TaskServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/world-server.js +++ /dev/null @@ -1,55 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key' -}; - -var messages={ - goodbye:false, - hello:false -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - ipc.log('got a message from', (data.id), (data.message)); - messages[data.id]=true; - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - - if(messages.hello && messages.goodbye){ - ipc.log('got all required events, telling clients to kill connection'); - ipc.server.broadcast( - 'kill.connection', - { - id:ipc.config.id - } - ); - } - } - ); - } -); - - - - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/hello-client.js b/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/hello-client.js deleted file mode 100644 index 15771565b..000000000 --- a/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/hello-client.js +++ /dev/null @@ -1,42 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/world-server.js b/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/world-server.js deleted file mode 100644 index 3cbcd8e38..000000000 --- a/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/world-server.js +++ /dev/null @@ -1,42 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -//node-ipc will default to its local certs -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/hello-client.js b/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/hello-client.js deleted file mode 100644 index bda3eb701..000000000 --- a/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/hello-client.js +++ /dev/null @@ -1,47 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.tls={ - private: __dirname+'/../../../local-node-ipc-certs/private/client.key', - public: __dirname+'/../../../local-node-ipc-certs/client.pub', - rejectUnauthorized:false, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/server.pub' - ] -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/world-server.js b/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/world-server.js deleted file mode 100644 index 56eee122b..000000000 --- a/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/world-server.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key', - dhparam: __dirname+'/../../../local-node-ipc-certs/private/dhparam.pem', - requestCert: true, - rejectUnauthorized:false, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/client.pub' - ] -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/hello-client.js b/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/hello-client.js deleted file mode 100644 index 26d5b1da6..000000000 --- a/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/hello-client.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.networkHost='localhost'; -ipc.config.tls={ - private: __dirname+'/../../../local-node-ipc-certs/private/client.key', - public: __dirname+'/../../../local-node-ipc-certs/client.pub', - rejectUnauthorized:true, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/server.pub' - ] -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/world-server.js b/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/world-server.js deleted file mode 100644 index ee984a4e1..000000000 --- a/TaskServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/world-server.js +++ /dev/null @@ -1,49 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.networkHost='localhost'; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key', - dhparam: __dirname+'/../../../local-node-ipc-certs/private/dhparam.pem', - requestCert: true, - rejectUnauthorized:true, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/client.pub' - ] -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/TLSSocket/basic/hello-client.js b/TaskServer/node_modules/node-ipc/example/TLSSocket/basic/hello-client.js deleted file mode 100644 index 15771565b..000000000 --- a/TaskServer/node_modules/node-ipc/example/TLSSocket/basic/hello-client.js +++ /dev/null @@ -1,42 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/TLSSocket/basic/world-server.js b/TaskServer/node_modules/node-ipc/example/TLSSocket/basic/world-server.js deleted file mode 100644 index a52c3602a..000000000 --- a/TaskServer/node_modules/node-ipc/example/TLSSocket/basic/world-server.js +++ /dev/null @@ -1,42 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key' -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/TLSSocket/basicSync/hello-client.js b/TaskServer/node_modules/node-ipc/example/TLSSocket/basicSync/hello-client.js deleted file mode 100644 index 405db4468..000000000 --- a/TaskServer/node_modules/node-ipc/example/TLSSocket/basicSync/hello-client.js +++ /dev/null @@ -1,47 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.sync= true; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - - //queue up a bunch of requests to be sent synchronously - for(var i=0; i<10; i++){ - ipc.of.world.emit( - 'message', - 'hello'+i - ); - } - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/TLSSocket/basicSync/world-server.js b/TaskServer/node_modules/node-ipc/example/TLSSocket/basicSync/world-server.js deleted file mode 100644 index aec87c100..000000000 --- a/TaskServer/node_modules/node-ipc/example/TLSSocket/basicSync/world-server.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.sync= true; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key' -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - setTimeout( - function(){ - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - }, - 3000 - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/hello-client.js b/TaskServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/hello-client.js deleted file mode 100644 index f0c66ad22..000000000 --- a/TaskServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/hello-client.js +++ /dev/null @@ -1,45 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; -ipc.config.networkHost='localhost'; - -ipc.config.tls={ - private: __dirname+'/../../../local-node-ipc-certs/private/client.key', - public: __dirname+'/../../../local-node-ipc-certs/client.pub', - rejectUnauthorized:true, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/server.pub' - ] -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'hello' - ); - } - ); - - ipc.of.world.on( - 'data', - function(data){ - ipc.log('got a message from world : ', data,data.toString()); - } - ); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/world.server.js b/TaskServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/world.server.js deleted file mode 100644 index f0d0b29af..000000000 --- a/TaskServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/world.server.js +++ /dev/null @@ -1,53 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; -ipc.config.networkHost='localhost'; - -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key', - dhparam: __dirname+'/../../../local-node-ipc-certs/private/dhparam.pem', - requestCert: true, - rejectUnauthorized:true, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/client.pub' - ] -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'connect', - function(socket){ - console.log('connection detected'); - ipc.server.emit( - socket, - 'hello' - ); - } - ); - - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data,data.toString()); - ipc.server.emit( - socket, - 'goodbye' - ); - } - ); - } -); - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/goodbye-client.js b/TaskServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/goodbye-client.js deleted file mode 100644 index d98a7b061..000000000 --- a/TaskServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/goodbye-client.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * Since there is no client relationship - * with UDP sockets sockets are not kept - * open. - * - * This means the order sockets are opened - * is important. - * - * Start World first. Then you can start - * hello or goodbye in any order you - * choose. - * - * *************************************/ - -ipc.config.id = 'goodbye'; -ipc.config.retry= 1500; - -ipc.serveNet( - 8002, //we set the port here because the hello client and world server are already using the default of 8000 and the port 8001. So we can not bind to those while hello and world are connected to them. - 'udp4', - function(){ - ipc.server.on( - 'message', - function(data){ - ipc.log('got Data'); - ipc.log('got a message from ', data.id ,' : ', data.message); - } - ); - ipc.server.emit( - { - address : 'localhost', - port : ipc.config.networkPort - }, - 'message', - { - id : ipc.config.id, - message : 'Goodbye' - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/hello-client.js b/TaskServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/hello-client.js deleted file mode 100644 index ecc0b45a4..000000000 --- a/TaskServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/hello-client.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * Since there is no client relationship - * with UDP sockets sockets are not kept - * open. - * - * This means the order sockets are opened - * is important. - * - * Start World first. Then you can start - * hello or goodbye in any order you - * choose. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; - -ipc.serveNet( - 8001, //we set the port here because the world server is already using the default of 8000. So we can not bind to 8000 while world is using it. - 'udp4', - function(){ - ipc.server.on( - 'message', - function(data){ - ipc.log('got Data'); - ipc.log('got a message from ', data.id ,' : ', data.message); - } - ); - ipc.server.emit( - { - address : 'localhost', - port : ipc.config.networkPort - }, - 'message', - { - id : ipc.config.id, - message : 'Hello' - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/world-server.js b/TaskServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/world-server.js deleted file mode 100644 index 97f927088..000000000 --- a/TaskServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/world-server.js +++ /dev/null @@ -1,63 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * Since there is no client relationship - * with UDP sockets sockets are not kept - * open. - * - * This means the order sockets are opened - * is important. - * - * Start World first. Then you can start - * hello or goodbye in any order you - * choose. - * - ***************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -var messages={ - goodbye:false, - hello:false -}; - -ipc.serveNet( - 'udp4', - function(){ - console.log(123); - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message from ', data.id ,' : ', data.message); - messages[data.id]=true; - ipc.server.emit( - socket, - 'message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - - if(messages.hello && messages.goodbye){ - ipc.log('got all required events, telling evryone how muchg I am loved!'); - ipc.server.broadcast( - 'message', - { - id : ipc.config.id, - message : 'Everybody Loves The World! Got messages from hello and goodbye!' - } - ); - } - } - ); - - console.log(ipc.server); - } -); - - - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/UDPSocket/basic/hello-client.js b/TaskServer/node_modules/node-ipc/example/UDPSocket/basic/hello-client.js deleted file mode 100644 index f731b1ba8..000000000 --- a/TaskServer/node_modules/node-ipc/example/UDPSocket/basic/hello-client.js +++ /dev/null @@ -1,52 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * UDP Client is really a UDP server - * - * Dedicated UDP sockets on the same - * machine can not be bound to in the - * traditional client/server method - * - * Every UDP socket is it's own UDP server - * And so must have a unique port on its - * machine, unlike TCP or Unix Sockts - * which can share on the same machine. - * - * Since there is no open client server - * relationship, you should start world - * first and then hello. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; - -ipc.serveNet( - 8001, //we set the port here because the world server is already using the default of 8000. So we can not bind to 8000 while world is using it. - 'udp4', - function(){ - ipc.server.on( - 'message', - function(data){ - ipc.log('got Data'); - ipc.log('got a message from ', data.id ,' : ', data.message); - } - ); - ipc.server.emit( - { - address : 'localhost', - port : ipc.config.networkPort - }, - 'message', - { - id : ipc.config.id, - message : 'Hello' - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/UDPSocket/basic/world-server.js b/TaskServer/node_modules/node-ipc/example/UDPSocket/basic/world-server.js deleted file mode 100644 index 0f7aa4543..000000000 --- a/TaskServer/node_modules/node-ipc/example/UDPSocket/basic/world-server.js +++ /dev/null @@ -1,47 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * UDP Client is really a UDP server - * - * Dedicated UDP sockets on the same - * machine can not be bound to in the - * traditional client/server method - * - * Every UDP socket is it's own UDP server - * And so must have a unique port on its - * machine, unlike TCP or Unix Sockts - * which can share on the same machine. - * - * Since there is no open client server - * relationship, you should start world - * first and then hello. - * - ***************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -ipc.serveNet( - 'udp4', - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message from ', data.id ,' : ', data.message); - ipc.server.emit( - socket, - 'message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/hello-client.js b/TaskServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/hello-client.js deleted file mode 100644 index 73cd13ac5..000000000 --- a/TaskServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/hello-client.js +++ /dev/null @@ -1,35 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.serveNet( - 8001, //we set the port here because the world server is already using the default of 8000. So we can not bind to 8000 while world is using it. - 'udp4', - function(){ - ipc.server.on( - 'data', - function(data){ - ipc.log('got a message from world ', data, data.toString()); - } - ); - ipc.server.emit( - { - address : 'localhost', - port : ipc.config.networkPort - }, - 'hello' - ); - } -); - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/world.server.js b/TaskServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/world.server.js deleted file mode 100644 index d0c34f7e2..000000000 --- a/TaskServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/world.server.js +++ /dev/null @@ -1,43 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * UDP Client is really a UDP server - * - * Dedicated UDP sockets on the same - * machine can not be bound to in the - * traditional client/server method - * - * Every UDP socket is it's own UDP server - * And so must have a unique port on its - * machine, unlike TCP or Unix Sockts - * which can share on the same machine. - * - * Since there is no open client server - * relationship, you should start world - * first and then hello. - * - ***************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.serveNet( - 'udp4', - function(){ - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data,data.toString()); - ipc.server.emit( - socket, - 'goodbye' - ); - } - ); - } -); - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-client.js b/TaskServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-client.js deleted file mode 100644 index eca2a889c..000000000 --- a/TaskServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-client.js +++ /dev/null @@ -1,31 +0,0 @@ -const fs = require('fs'); -const ipc = require('../../node-ipc'); - -const socketPath = '/tmp/ipc.sock'; - -//loop forever so you can see the pid of the cluster sever change in the logs -setInterval( - function() { - ipc.connectTo( - 'world', - socketPath, - connecting - ); - }, - 2000 -); - -function connecting(socket) { - ipc.of.world.on( - 'connect', - function() { - ipc.of.world.emit( - 'currentDate', - { - message: new Date().toISOString() - } - ); - ipc.disconnect('world'); - } - ); -} diff --git a/TaskServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-server.js b/TaskServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-server.js deleted file mode 100644 index b0942a338..000000000 --- a/TaskServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-server.js +++ /dev/null @@ -1,32 +0,0 @@ -const fs = require('fs'); -const ipc=require('../../../node-ipc'); -const cpuCount = require('os').cpus().length; -const cluster = require('cluster'); -const socketPath = '/tmp/ipc.sock'; - -ipc.config.unlink = false; - -if (cluster.isMaster) { - if (fs.existsSync(socketPath)) { - fs.unlinkSync(socketPath); - } - - for (let i = 0; i < cpuCount; i++) { - cluster.fork(); - } -}else{ - ipc.serve( - socketPath, - function() { - ipc.server.on( - 'currentDate', - function(data,socket) { - console.log(`pid ${process.pid} got: `, data); - } - ); - } - ); - - ipc.server.start(); - console.log(`pid ${process.pid} listening on ${socketPath}`); -} diff --git a/TaskServer/node_modules/node-ipc/example/rawBuffer/hello-client.js b/TaskServer/node_modules/node-ipc/example/rawBuffer/hello-client.js deleted file mode 100644 index f22ab5376..000000000 --- a/TaskServer/node_modules/node-ipc/example/rawBuffer/hello-client.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict'; - -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='hex'; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - //make a 6 byte buffer for example - const myBuffer=new Buffer(6).fill(0); - - myBuffer.writeUInt16BE(0x02,0); - myBuffer.writeUInt32BE(0xffeecc,2); - - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - myBuffer - ); - } - ); - - ipc.of.world.on( - 'data', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/rawBuffer/world.server.js b/TaskServer/node_modules/node-ipc/example/rawBuffer/world.server.js deleted file mode 100644 index f27a02cd5..000000000 --- a/TaskServer/node_modules/node-ipc/example/rawBuffer/world.server.js +++ /dev/null @@ -1,40 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='hex'; - -ipc.serve( - function(){ - ipc.server.on( - 'connect', - function(socket){ - ipc.server.emit( - socket, - [0xaa] - ); - } - ); - - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data); - ipc.server.emit( - socket, - [0x0d,0xee] - ); - } - ); - } -); - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/goodbye-client.js b/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/goodbye-client.js deleted file mode 100644 index 57d455eec..000000000 --- a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/goodbye-client.js +++ /dev/null @@ -1,43 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'goodbye'; -ipc.config.retry= 1500; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'goodbye' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/hello-client.js b/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/hello-client.js deleted file mode 100644 index d556c4694..000000000 --- a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/hello-client.js +++ /dev/null @@ -1,49 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/world-server.js b/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/world-server.js deleted file mode 100644 index 69cfb31c0..000000000 --- a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/world-server.js +++ /dev/null @@ -1,51 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -var messages={ - goodbye:false, - hello:false -}; - -ipc.serve( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - ipc.log('got a message from', (data.id), (data.message)); - messages[data.id]=true; - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - - if(messages.hello && messages.goodbye){ - ipc.log('got all required events, telling clients to kill connection'); - ipc.server.broadcast( - 'kill.connection', - { - id:ipc.config.id - } - ); - } - } - ); - } -); - - - - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/basic/hello-client.js b/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/basic/hello-client.js deleted file mode 100644 index c6d87cb27..000000000 --- a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/basic/hello-client.js +++ /dev/null @@ -1,44 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry = 1000; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - - console.log(ipc.of.world.destroy); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/basic/world-server.js b/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/basic/world-server.js deleted file mode 100644 index 6b3052242..000000000 --- a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/basic/world-server.js +++ /dev/null @@ -1,33 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -ipc.serve( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/hello-client.js b/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/hello-client.js deleted file mode 100644 index 3142677a2..000000000 --- a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/hello-client.js +++ /dev/null @@ -1,49 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry = 1000; -ipc.config.sync= true; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - - //queue up a bunch of requests to be sent synchronously - for(var i=0; i<10; i++){ - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello'+i - } - ); - } - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - - console.log(ipc.of.world.destroy); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/world-server.js b/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/world-server.js deleted file mode 100644 index c76e1bb6f..000000000 --- a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/world-server.js +++ /dev/null @@ -1,39 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.sync= true; - -ipc.serve( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - setTimeout( - function(){ - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - }, - 2000 - ); - } - ); - } -); - - - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/hello-client.js b/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/hello-client.js deleted file mode 100644 index 9c7042a90..000000000 --- a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/hello-client.js +++ /dev/null @@ -1,35 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'hello' - ); - } - ); - - ipc.of.world.on( - 'data', - function(data){ - ipc.log('got a message from world : ', data,data.toString()); - } - ); - } -); diff --git a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/world.server.js b/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/world.server.js deleted file mode 100644 index c3ed83c9a..000000000 --- a/TaskServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/world.server.js +++ /dev/null @@ -1,40 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.serve( - function(){ - ipc.server.on( - 'connect', - function(socket){ - ipc.server.emit( - socket, - 'hello' - ); - } - ); - - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data,data.toString()); - ipc.server.emit( - socket, - 'goodbye' - ); - } - ); - } -); - -ipc.server.start(); diff --git a/TaskServer/node_modules/node-ipc/node-ipc.js b/TaskServer/node_modules/node-ipc/node-ipc.js deleted file mode 100644 index 1c6336061..000000000 --- a/TaskServer/node_modules/node-ipc/node-ipc.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -const IPC = require('./services/IPC.js'); - -class IPCModule extends IPC{ - constructor(){ - super(); - //include IPC to make extensible - Object.defineProperty( - this, - 'IPC', - { - enumerable:true, - writable:false, - value:IPC - } - ) - } -} - -module.exports=new IPCModule; diff --git a/TaskServer/node_modules/node-ipc/package.json b/TaskServer/node_modules/node-ipc/package.json deleted file mode 100644 index 696d18b97..000000000 --- a/TaskServer/node_modules/node-ipc/package.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "_args": [ - [ - "node-ipc@9.1.1", - "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer" - ] - ], - "_from": "node-ipc@9.1.1", - "_id": "node-ipc@9.1.1", - "_inBundle": false, - "_integrity": "sha512-FAyICv0sIRJxVp3GW5fzgaf9jwwRQxAKDJlmNFUL5hOy+W4X/I5AypyHoq0DXXbo9o/gt79gj++4cMr4jVWE/w==", - "_location": "/node-ipc", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "node-ipc@9.1.1", - "name": "node-ipc", - "escapedName": "node-ipc", - "rawSpec": "9.1.1", - "saveSpec": null, - "fetchSpec": "9.1.1" - }, - "_requiredBy": [ - "/" - ], - "_resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.1.1.tgz", - "_spec": "9.1.1", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/node-ipc/issues" - }, - "dependencies": { - "event-pubsub": "4.3.0", - "js-message": "1.0.5", - "js-queue": "2.0.0" - }, - "description": "A nodejs module for local and remote Inter Process Communication (IPC), Neural Networking, and able to facilitate machine learning.", - "devDependencies": { - "codacy-coverage": "2.0.0", - "istanbul": "0.4.1", - "jasmine": "2.4.1", - "node-cmd": "2.0.0" - }, - "directories": { - "example": "example" - }, - "engines": { - "node": ">=4.0.0" - }, - "homepage": "http://riaevangelist.github.io/node-ipc/", - "keywords": [ - "IPC", - "Neural Networking", - "Machine Learning", - "inter", - "process", - "communication", - "unix", - "windows", - "win", - "socket", - "TCP", - "UDP", - "domain", - "sockets", - "threaded", - "communication", - "multi", - "process", - "shared", - "memory" - ], - "license": "DBAD", - "main": "node-ipc.js", - "name": "node-ipc", - "pre-commit": [ - "cover" - ], - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/node-ipc.git" - }, - "scripts": { - "cover": "istanbul cover -x **/spec/** -dir ./spec/coverage jasmine", - "coverup": "cat ./spec/coverage/lcov.info | codacy-coverage", - "test": "istanbul cover -x **/spec/** -dir ./spec/coverage jasmine", - "test-windows": "istanbul cover -x **/spec/** -dir ./spec/coverage ./node_modules/jasmine/bin/jasmine.js" - }, - "version": "9.1.1" -} diff --git a/TaskServer/node_modules/node-ipc/services/IPC.js b/TaskServer/node_modules/node-ipc/services/IPC.js deleted file mode 100644 index 3a6edc7f5..000000000 --- a/TaskServer/node_modules/node-ipc/services/IPC.js +++ /dev/null @@ -1,337 +0,0 @@ -'use strict'; - -const Defaults = require('../entities/Defaults.js'), - Client = require('../dao/client.js'), - Server = require('../dao/socketServer.js'), - util = require('util'); - -class IPC{ - constructor(){ - Object.defineProperties( - this, - { - config : { - enumerable:true, - writable:true, - value:new Defaults - }, - connectTo : { - enumerable:true, - writable:false, - value:connect - }, - connectToNet: { - enumerable:true, - writable:false, - value:connectNet - }, - disconnect : { - enumerable:true, - writable:false, - value:disconnect - }, - serve : { - enumerable:true, - writable:false, - value:serve - }, - serveNet : { - enumerable:true, - writable:false, - value:serveNet - }, - of : { - enumerable:true, - writable:true, - value:{} - }, - server : { - enumerable:true, - writable:true, - configurable:true, - value:false - }, - log : { - enumerable:true, - writable:false, - value:log - } - } - ); - } -} - -function log(...args){ - if(this.config.silent){ - return; - } - - for(let i=0, count=args.length; i entity.offset === offset) - if (index === -1) { - break - } - const entity = available[index] - switch (entity.type) { - case 'bold': - result.push('') - break - case 'italic': - result.push('') - break - case 'code': - result.push('') - break - case 'pre': - result.push('
')
-            break
-          case 'strikethrough':
-            result.push('')
-            break
-          case 'underline':
-            result.push('')
-            break
-          case 'text_link':
-            result.push(``)
-            break
-        }
-        opened.unshift(entity)
-        available.splice(index, 1)
-      }
-
-      result.push(chars[offset])
-
-      while (true) {
-        const index = opened.findIndex((entity) => entity.offset + entity.length - 1 === offset)
-        if (index === -1) {
-          break
-        }
-        const entity = opened[index]
-        switch (entity.type) {
-          case 'bold':
-            result.push('')
-            break
-          case 'italic':
-            result.push('')
-            break
-          case 'code':
-            result.push('')
-            break
-          case 'pre':
-            result.push('
') - break - case 'strikethrough': - result.push('') - break - case 'underline': - result.push('') - break - case 'text_link': - result.push('') - break - } - opened.splice(index, 1) - } - } - return result.join('') + static formatHTML (text = '', entities = []) { + const chars = ['', ...text.split(''), ''].map(escapeHTMLChar) + entities.forEach(entity => { + const tag = getHTMLTag(entity) + const openPos = entity.offset + const closePos = entity.offset + entity.length + 1 + chars[openPos] += tag.open + chars[closePos] = tag.close + chars[closePos] + }) + return chars.join('') } } @@ -267,4 +203,40 @@ function buildKeyboard (buttons, options) { return result } +function escapeHTMLChar (c) { + switch (c) { + case '&': return '&' + case '"': return '"' + case '\'': return ''' + case '<': return '<' + default : return c + } +} + +function tag (name, params) { + return { + open: params + ? `<${name} ${Object.entries(params).map(([key, value]) => `${key}="${value.replace(/[<&"]/g, escapeHTMLChar)}"`).join(' ')}>` + : `<${name}>`, + close: `` + } +} + +const HTMLTags = new Map([ + ['bold', tag('b')], + ['italic', tag('i')], + ['code', tag('code')], + ['pre', tag('pre')], + ['strikethrough', tag('s')], + ['underline', tag('u')], + ['text_link', ({ url }) => tag('a', { href: url })], + ['text_mention', ({ user }) => tag('a', { href: `tg://user?id=${user.id}` })] +]) + +function getHTMLTag (entity) { + const tag = HTMLTags.get(entity.type || 'unknown') + if (!tag) return { open: '', close: '' } + return typeof tag === 'function' ? tag(entity) : tag +} + module.exports = Markup diff --git a/TaskServer/node_modules/telegraf/package.json b/TaskServer/node_modules/telegraf/package.json index 3a67e53db..040c02569 100644 --- a/TaskServer/node_modules/telegraf/package.json +++ b/TaskServer/node_modules/telegraf/package.json @@ -1,41 +1,40 @@ { - "_from": "telegraf@3.36.0", - "_id": "telegraf@3.36.0", + "_from": "telegraf@3.37.0", + "_id": "telegraf@3.37.0", "_inBundle": false, - "_integrity": "sha512-9o6AJKRiTm5vMWYI6WpTfBHzu4FMpWBNKxvnMxRds/cbMY9RnsVVjdi8i4bFFlfd+xbi73EbrnI3dybayryICA==", + "_integrity": "sha512-V3448qwfOolBqkIc87yxjW4zMvR2P6AIF24pPTlX9WhZPwA1TF/x3nQhnWPRLtGh2SJuvDcr83iTkXPXT7Opnw==", "_location": "/telegraf", "_phantomChildren": {}, "_requested": { "type": "version", "registry": true, - "raw": "telegraf@3.36.0", + "raw": "telegraf@3.37.0", "name": "telegraf", "escapedName": "telegraf", - "rawSpec": "3.36.0", + "rawSpec": "3.37.0", "saveSpec": null, - "fetchSpec": "3.36.0" + "fetchSpec": "3.37.0" }, "_requiredBy": [ "#USER", "/" ], - "_resolved": "https://registry.npmjs.org/telegraf/-/telegraf-3.36.0.tgz", - "_shasum": "eab1160159df6033d3cb92ac990902523277822a", - "_spec": "telegraf@3.36.0", + "_resolved": "https://registry.npmjs.org/telegraf/-/telegraf-3.37.0.tgz", + "_shasum": "f88ae3d4bddac6f479137d4c867489acf3f57b66", + "_spec": "telegraf@3.37.0", "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer", "author": { "name": "Vitaly Domnikov", "email": "oss@vitaly.codes" }, "bin": { - "telegraf": "./bin/telegraf" + "telegraf": "bin/telegraf" }, "bugs": { "url": "https://github.com/telegraf/telegraf/issues" }, "bundleDependencies": false, "dependencies": { - "@types/node": "^13.1.0", "debug": "^4.0.1", "minimist": "^1.2.0", "module-alias": "^2.2.2", @@ -46,6 +45,7 @@ "deprecated": false, "description": "Modern Telegram Bot Framework", "devDependencies": { + "@types/node": "^13.1.0", "ava": "^3.0.0", "eslint": "^6.2.2", "eslint-config-standard": "^14.1.0", @@ -91,5 +91,5 @@ }, "type": "commonjs", "types": "./typings/index.d.ts", - "version": "3.36.0" + "version": "3.37.0" } diff --git a/TaskServer/node_modules/telegraf/scenes/context.js b/TaskServer/node_modules/telegraf/scenes/context.js index c47e06e98..9dd24d7ac 100644 --- a/TaskServer/node_modules/telegraf/scenes/context.js +++ b/TaskServer/node_modules/telegraf/scenes/context.js @@ -2,7 +2,7 @@ const debug = require('debug')('telegraf:scenes:context') const { safePassThru } = require('../composer') const noop = () => Promise.resolve() -const now = () => Math.floor(new Date().getTime() / 1000) +const now = () => Math.floor(Date.now() / 1000) class SceneContext { constructor (ctx, scenes, options) { diff --git a/TaskServer/node_modules/telegraf/session.js b/TaskServer/node_modules/telegraf/session.js index 1f58ed269..05f69ad9d 100644 --- a/TaskServer/node_modules/telegraf/session.js +++ b/TaskServer/node_modules/telegraf/session.js @@ -13,7 +13,7 @@ module.exports = function (opts) { if (!key) { return next(ctx) } - const now = new Date().getTime() + const now = Date.now() return Promise.resolve(options.store.get(key)) .then((state) => state || { session: {} }) .then(({ session, expires }) => { diff --git a/TaskServer/node_modules/telegraf/telegraf.js b/TaskServer/node_modules/telegraf/telegraf.js index 2d6e73373..15c3b0fb6 100644 --- a/TaskServer/node_modules/telegraf/telegraf.js +++ b/TaskServer/node_modules/telegraf/telegraf.js @@ -209,16 +209,7 @@ class Telegraf extends Composer { module.exports = Object.assign(Telegraf, { Context, Composer, - Extra, - Markup, - Router, - Telegram, - session -}) - -module.exports.default = Object.assign(Telegraf, { - Context, - Composer, + default: Telegraf, Extra, Markup, Router, diff --git a/TaskServer/node_modules/telegraf/telegram.js b/TaskServer/node_modules/telegraf/telegram.js index d217fde43..1224b766e 100644 --- a/TaskServer/node_modules/telegraf/telegram.js +++ b/TaskServer/node_modules/telegraf/telegram.js @@ -115,6 +115,10 @@ class Telegram extends ApiClient { return this.callApi('sendPhoto', { chat_id: chatId, photo, ...extra }) } + sendDice (chatId, extra) { + return this.callApi('sendDice', { chat_id: chatId, ...extra }) + } + sendDocument (chatId, document, extra) { return this.callApi('sendDocument', { chat_id: chatId, document, ...extra }) } @@ -386,10 +390,22 @@ class Telegram extends ApiClient { }) } + setStickerSetThumb (name, userId, thumb) { + return this.callApi('setStickerSetThumb', { name, user_id: userId, thumb }) + } + deleteStickerFromSet (sticker) { return this.callApi('deleteStickerFromSet', { sticker }) } + getMyCommands () { + return this.callApi('getMyCommands') + } + + setMyCommands (commands) { + return this.callApi('setMyCommands', { commands }) + } + setPassportDataErrors (userId, errors) { return this.callApi('setPassportDataErrors', { user_id: userId, diff --git a/TaskServer/node_modules/ws/browser.js b/TaskServer/node_modules/ws/browser.js new file mode 100644 index 000000000..782077969 --- /dev/null +++ b/TaskServer/node_modules/ws/browser.js @@ -0,0 +1,8 @@ +'use strict'; + +module.exports = function() { + throw new Error( + 'ws does not work in the browser. Browser clients must use the native ' + + 'WebSocket object' + ); +}; diff --git a/TaskServer/node_modules/ws/index.js b/TaskServer/node_modules/ws/index.js new file mode 100644 index 000000000..722c78676 --- /dev/null +++ b/TaskServer/node_modules/ws/index.js @@ -0,0 +1,10 @@ +'use strict'; + +const WebSocket = require('./lib/websocket'); + +WebSocket.createWebSocketStream = require('./lib/stream'); +WebSocket.Server = require('./lib/websocket-server'); +WebSocket.Receiver = require('./lib/receiver'); +WebSocket.Sender = require('./lib/sender'); + +module.exports = WebSocket; diff --git a/TaskServer/node_modules/ws/lib/buffer-util.js b/TaskServer/node_modules/ws/lib/buffer-util.js new file mode 100644 index 000000000..3648638b0 --- /dev/null +++ b/TaskServer/node_modules/ws/lib/buffer-util.js @@ -0,0 +1,146 @@ +'use strict'; + +const { EMPTY_BUFFER } = require('./constants'); + +/** + * Merges an array of buffers into a new buffer. + * + * @param {Buffer[]} list The array of buffers to concat + * @param {Number} totalLength The total length of buffers in the list + * @return {Buffer} The resulting buffer + * @public + */ +function concat(list, totalLength) { + if (list.length === 0) return EMPTY_BUFFER; + if (list.length === 1) return list[0]; + + const target = Buffer.allocUnsafe(totalLength); + let offset = 0; + + for (let i = 0; i < list.length; i++) { + const buf = list[i]; + target.set(buf, offset); + offset += buf.length; + } + + if (offset < totalLength) return target.slice(0, offset); + + return target; +} + +/** + * Masks a buffer using the given mask. + * + * @param {Buffer} source The buffer to mask + * @param {Buffer} mask The mask to use + * @param {Buffer} output The buffer where to store the result + * @param {Number} offset The offset at which to start writing + * @param {Number} length The number of bytes to mask. + * @public + */ +function _mask(source, mask, output, offset, length) { + for (let i = 0; i < length; i++) { + output[offset + i] = source[i] ^ mask[i & 3]; + } +} + +/** + * Unmasks a buffer using the given mask. + * + * @param {Buffer} buffer The buffer to unmask + * @param {Buffer} mask The mask to use + * @public + */ +function _unmask(buffer, mask) { + // Required until https://github.com/nodejs/node/issues/9006 is resolved. + const length = buffer.length; + for (let i = 0; i < length; i++) { + buffer[i] ^= mask[i & 3]; + } +} + +/** + * Converts a buffer to an `ArrayBuffer`. + * + * @param {Buffer} buf The buffer to convert + * @return {ArrayBuffer} Converted buffer + * @public + */ +function toArrayBuffer(buf) { + if (buf.byteLength === buf.buffer.byteLength) { + return buf.buffer; + } + + return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); +} + +/** + * Converts `data` to a `Buffer`. + * + * @param {*} data The data to convert + * @return {Buffer} The buffer + * @throws {TypeError} + * @public + */ +function toBuffer(data) { + toBuffer.readOnly = true; + + if (Buffer.isBuffer(data)) return data; + + let buf; + + if (data instanceof ArrayBuffer) { + buf = Buffer.from(data); + } else if (ArrayBuffer.isView(data)) { + buf = viewToBuffer(data); + } else { + buf = Buffer.from(data); + toBuffer.readOnly = false; + } + + return buf; +} + +/** + * Converts an `ArrayBuffer` view into a buffer. + * + * @param {(DataView|TypedArray)} view The view to convert + * @return {Buffer} Converted view + * @private + */ +function viewToBuffer(view) { + const buf = Buffer.from(view.buffer); + + if (view.byteLength !== view.buffer.byteLength) { + return buf.slice(view.byteOffset, view.byteOffset + view.byteLength); + } + + return buf; +} + +try { + const bufferUtil = require('bufferutil'); + const bu = bufferUtil.BufferUtil || bufferUtil; + + module.exports = { + concat, + mask(source, mask, output, offset, length) { + if (length < 48) _mask(source, mask, output, offset, length); + else bu.mask(source, mask, output, offset, length); + }, + toArrayBuffer, + toBuffer, + unmask(buffer, mask) { + if (buffer.length < 32) _unmask(buffer, mask); + else bu.unmask(buffer, mask); + } + }; +} catch (e) /* istanbul ignore next */ { + module.exports = { + concat, + mask: _mask, + toArrayBuffer, + toBuffer, + unmask: _unmask + }; +} diff --git a/TaskServer/node_modules/ws/lib/constants.js b/TaskServer/node_modules/ws/lib/constants.js new file mode 100644 index 000000000..4082981f8 --- /dev/null +++ b/TaskServer/node_modules/ws/lib/constants.js @@ -0,0 +1,10 @@ +'use strict'; + +module.exports = { + BINARY_TYPES: ['nodebuffer', 'arraybuffer', 'fragments'], + GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', + kStatusCode: Symbol('status-code'), + kWebSocket: Symbol('websocket'), + EMPTY_BUFFER: Buffer.alloc(0), + NOOP: () => {} +}; diff --git a/TaskServer/node_modules/ws/lib/event-target.js b/TaskServer/node_modules/ws/lib/event-target.js new file mode 100644 index 000000000..c060d63a8 --- /dev/null +++ b/TaskServer/node_modules/ws/lib/event-target.js @@ -0,0 +1,170 @@ +'use strict'; + +/** + * Class representing an event. + * + * @private + */ +class Event { + /** + * Create a new `Event`. + * + * @param {String} type The name of the event + * @param {Object} target A reference to the target to which the event was dispatched + */ + constructor(type, target) { + this.target = target; + this.type = type; + } +} + +/** + * Class representing a message event. + * + * @extends Event + * @private + */ +class MessageEvent extends Event { + /** + * Create a new `MessageEvent`. + * + * @param {(String|Buffer|ArrayBuffer|Buffer[])} data The received data + * @param {WebSocket} target A reference to the target to which the event was dispatched + */ + constructor(data, target) { + super('message', target); + + this.data = data; + } +} + +/** + * Class representing a close event. + * + * @extends Event + * @private + */ +class CloseEvent extends Event { + /** + * Create a new `CloseEvent`. + * + * @param {Number} code The status code explaining why the connection is being closed + * @param {String} reason A human-readable string explaining why the connection is closing + * @param {WebSocket} target A reference to the target to which the event was dispatched + */ + constructor(code, reason, target) { + super('close', target); + + this.wasClean = target._closeFrameReceived && target._closeFrameSent; + this.reason = reason; + this.code = code; + } +} + +/** + * Class representing an open event. + * + * @extends Event + * @private + */ +class OpenEvent extends Event { + /** + * Create a new `OpenEvent`. + * + * @param {WebSocket} target A reference to the target to which the event was dispatched + */ + constructor(target) { + super('open', target); + } +} + +/** + * Class representing an error event. + * + * @extends Event + * @private + */ +class ErrorEvent extends Event { + /** + * Create a new `ErrorEvent`. + * + * @param {Object} error The error that generated this event + * @param {WebSocket} target A reference to the target to which the event was dispatched + */ + constructor(error, target) { + super('error', target); + + this.message = error.message; + this.error = error; + } +} + +/** + * This provides methods for emulating the `EventTarget` interface. It's not + * meant to be used directly. + * + * @mixin + */ +const EventTarget = { + /** + * Register an event listener. + * + * @param {String} method A string representing the event type to listen for + * @param {Function} listener The listener to add + * @public + */ + addEventListener(method, listener) { + if (typeof listener !== 'function') return; + + function onMessage(data) { + listener.call(this, new MessageEvent(data, this)); + } + + function onClose(code, message) { + listener.call(this, new CloseEvent(code, message, this)); + } + + function onError(error) { + listener.call(this, new ErrorEvent(error, this)); + } + + function onOpen() { + listener.call(this, new OpenEvent(this)); + } + + if (method === 'message') { + onMessage._listener = listener; + this.on(method, onMessage); + } else if (method === 'close') { + onClose._listener = listener; + this.on(method, onClose); + } else if (method === 'error') { + onError._listener = listener; + this.on(method, onError); + } else if (method === 'open') { + onOpen._listener = listener; + this.on(method, onOpen); + } else { + this.on(method, listener); + } + }, + + /** + * Remove an event listener. + * + * @param {String} method A string representing the event type to remove + * @param {Function} listener The listener to remove + * @public + */ + removeEventListener(method, listener) { + const listeners = this.listeners(method); + + for (let i = 0; i < listeners.length; i++) { + if (listeners[i] === listener || listeners[i]._listener === listener) { + this.removeListener(method, listeners[i]); + } + } + } +}; + +module.exports = EventTarget; diff --git a/TaskServer/node_modules/ws/lib/extension.js b/TaskServer/node_modules/ws/lib/extension.js new file mode 100644 index 000000000..87a421329 --- /dev/null +++ b/TaskServer/node_modules/ws/lib/extension.js @@ -0,0 +1,223 @@ +'use strict'; + +// +// Allowed token characters: +// +// '!', '#', '$', '%', '&', ''', '*', '+', '-', +// '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~' +// +// tokenChars[32] === 0 // ' ' +// tokenChars[33] === 1 // '!' +// tokenChars[34] === 0 // '"' +// ... +// +// prettier-ignore +const tokenChars = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31 + 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127 +]; + +/** + * Adds an offer to the map of extension offers or a parameter to the map of + * parameters. + * + * @param {Object} dest The map of extension offers or parameters + * @param {String} name The extension or parameter name + * @param {(Object|Boolean|String)} elem The extension parameters or the + * parameter value + * @private + */ +function push(dest, name, elem) { + if (dest[name] === undefined) dest[name] = [elem]; + else dest[name].push(elem); +} + +/** + * Parses the `Sec-WebSocket-Extensions` header into an object. + * + * @param {String} header The field value of the header + * @return {Object} The parsed object + * @public + */ +function parse(header) { + const offers = Object.create(null); + + if (header === undefined || header === '') return offers; + + let params = Object.create(null); + let mustUnescape = false; + let isEscaping = false; + let inQuotes = false; + let extensionName; + let paramName; + let start = -1; + let end = -1; + let i = 0; + + for (; i < header.length; i++) { + const code = header.charCodeAt(i); + + if (extensionName === undefined) { + if (end === -1 && tokenChars[code] === 1) { + if (start === -1) start = i; + } else if (code === 0x20 /* ' ' */ || code === 0x09 /* '\t' */) { + if (end === -1 && start !== -1) end = i; + } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + + if (end === -1) end = i; + const name = header.slice(start, end); + if (code === 0x2c) { + push(offers, name, params); + params = Object.create(null); + } else { + extensionName = name; + } + + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } else if (paramName === undefined) { + if (end === -1 && tokenChars[code] === 1) { + if (start === -1) start = i; + } else if (code === 0x20 || code === 0x09) { + if (end === -1 && start !== -1) end = i; + } else if (code === 0x3b || code === 0x2c) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + + if (end === -1) end = i; + push(params, header.slice(start, end), true); + if (code === 0x2c) { + push(offers, extensionName, params); + params = Object.create(null); + extensionName = undefined; + } + + start = end = -1; + } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) { + paramName = header.slice(start, i); + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } else { + // + // The value of a quoted-string after unescaping must conform to the + // token ABNF, so only token characters are valid. + // Ref: https://tools.ietf.org/html/rfc6455#section-9.1 + // + if (isEscaping) { + if (tokenChars[code] !== 1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + if (start === -1) start = i; + else if (!mustUnescape) mustUnescape = true; + isEscaping = false; + } else if (inQuotes) { + if (tokenChars[code] === 1) { + if (start === -1) start = i; + } else if (code === 0x22 /* '"' */ && start !== -1) { + inQuotes = false; + end = i; + } else if (code === 0x5c /* '\' */) { + isEscaping = true; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) { + inQuotes = true; + } else if (end === -1 && tokenChars[code] === 1) { + if (start === -1) start = i; + } else if (start !== -1 && (code === 0x20 || code === 0x09)) { + if (end === -1) end = i; + } else if (code === 0x3b || code === 0x2c) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + + if (end === -1) end = i; + let value = header.slice(start, end); + if (mustUnescape) { + value = value.replace(/\\/g, ''); + mustUnescape = false; + } + push(params, paramName, value); + if (code === 0x2c) { + push(offers, extensionName, params); + params = Object.create(null); + extensionName = undefined; + } + + paramName = undefined; + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } + } + + if (start === -1 || inQuotes) { + throw new SyntaxError('Unexpected end of input'); + } + + if (end === -1) end = i; + const token = header.slice(start, end); + if (extensionName === undefined) { + push(offers, token, params); + } else { + if (paramName === undefined) { + push(params, token, true); + } else if (mustUnescape) { + push(params, paramName, token.replace(/\\/g, '')); + } else { + push(params, paramName, token); + } + push(offers, extensionName, params); + } + + return offers; +} + +/** + * Builds the `Sec-WebSocket-Extensions` header field value. + * + * @param {Object} extensions The map of extensions and parameters to format + * @return {String} A string representing the given object + * @public + */ +function format(extensions) { + return Object.keys(extensions) + .map((extension) => { + let configurations = extensions[extension]; + if (!Array.isArray(configurations)) configurations = [configurations]; + return configurations + .map((params) => { + return [extension] + .concat( + Object.keys(params).map((k) => { + let values = params[k]; + if (!Array.isArray(values)) values = [values]; + return values + .map((v) => (v === true ? k : `${k}=${v}`)) + .join('; '); + }) + ) + .join('; '); + }) + .join(', '); + }) + .join(', '); +} + +module.exports = { format, parse }; diff --git a/TaskServer/node_modules/ws/lib/limiter.js b/TaskServer/node_modules/ws/lib/limiter.js new file mode 100644 index 000000000..8e990865d --- /dev/null +++ b/TaskServer/node_modules/ws/lib/limiter.js @@ -0,0 +1,54 @@ +'use strict'; + +const kDone = Symbol('kDone'); +const kRun = Symbol('kRun'); + +/** + * A very simple job queue with adjustable concurrency. Adapted from + * https://github.com/STRML/async-limiter + */ +class Limiter { + /** + * Creates a new `Limiter`. + * + * @param {Number} concurrency The maximum number of jobs allowed to run + * concurrently + */ + constructor(concurrency) { + this[kDone] = () => { + this.pending--; + this[kRun](); + }; + this.concurrency = concurrency || Infinity; + this.jobs = []; + this.pending = 0; + } + + /** + * Adds a job to the queue. + * + * @public + */ + add(job) { + this.jobs.push(job); + this[kRun](); + } + + /** + * Removes a job from the queue and runs it if possible. + * + * @private + */ + [kRun]() { + if (this.pending === this.concurrency) return; + + if (this.jobs.length) { + const job = this.jobs.shift(); + + this.pending++; + job(this[kDone]); + } + } +} + +module.exports = Limiter; diff --git a/TaskServer/node_modules/ws/lib/permessage-deflate.js b/TaskServer/node_modules/ws/lib/permessage-deflate.js new file mode 100644 index 000000000..7bb7c98d7 --- /dev/null +++ b/TaskServer/node_modules/ws/lib/permessage-deflate.js @@ -0,0 +1,512 @@ +'use strict'; + +const zlib = require('zlib'); + +const bufferUtil = require('./buffer-util'); +const Limiter = require('./limiter'); +const { kStatusCode, NOOP } = require('./constants'); + +const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]); +const kPerMessageDeflate = Symbol('permessage-deflate'); +const kTotalLength = Symbol('total-length'); +const kCallback = Symbol('callback'); +const kBuffers = Symbol('buffers'); +const kError = Symbol('error'); + +// +// We limit zlib concurrency, which prevents severe memory fragmentation +// as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913 +// and https://github.com/websockets/ws/issues/1202 +// +// Intentionally global; it's the global thread pool that's an issue. +// +let zlibLimiter; + +/** + * permessage-deflate implementation. + */ +class PerMessageDeflate { + /** + * Creates a PerMessageDeflate instance. + * + * @param {Object} options Configuration options + * @param {Boolean} options.serverNoContextTakeover Request/accept disabling + * of server context takeover + * @param {Boolean} options.clientNoContextTakeover Advertise/acknowledge + * disabling of client context takeover + * @param {(Boolean|Number)} options.serverMaxWindowBits Request/confirm the + * use of a custom server window size + * @param {(Boolean|Number)} options.clientMaxWindowBits Advertise support + * for, or request, a custom client window size + * @param {Object} options.zlibDeflateOptions Options to pass to zlib on deflate + * @param {Object} options.zlibInflateOptions Options to pass to zlib on inflate + * @param {Number} options.threshold Size (in bytes) below which messages + * should not be compressed + * @param {Number} options.concurrencyLimit The number of concurrent calls to + * zlib + * @param {Boolean} isServer Create the instance in either server or client + * mode + * @param {Number} maxPayload The maximum allowed message length + */ + constructor(options, isServer, maxPayload) { + this._maxPayload = maxPayload | 0; + this._options = options || {}; + this._threshold = + this._options.threshold !== undefined ? this._options.threshold : 1024; + this._isServer = !!isServer; + this._deflate = null; + this._inflate = null; + + this.params = null; + + if (!zlibLimiter) { + const concurrency = + this._options.concurrencyLimit !== undefined + ? this._options.concurrencyLimit + : 10; + zlibLimiter = new Limiter(concurrency); + } + } + + /** + * @type {String} + */ + static get extensionName() { + return 'permessage-deflate'; + } + + /** + * Create an extension negotiation offer. + * + * @return {Object} Extension parameters + * @public + */ + offer() { + const params = {}; + + if (this._options.serverNoContextTakeover) { + params.server_no_context_takeover = true; + } + if (this._options.clientNoContextTakeover) { + params.client_no_context_takeover = true; + } + if (this._options.serverMaxWindowBits) { + params.server_max_window_bits = this._options.serverMaxWindowBits; + } + if (this._options.clientMaxWindowBits) { + params.client_max_window_bits = this._options.clientMaxWindowBits; + } else if (this._options.clientMaxWindowBits == null) { + params.client_max_window_bits = true; + } + + return params; + } + + /** + * Accept an extension negotiation offer/response. + * + * @param {Array} configurations The extension negotiation offers/reponse + * @return {Object} Accepted configuration + * @public + */ + accept(configurations) { + configurations = this.normalizeParams(configurations); + + this.params = this._isServer + ? this.acceptAsServer(configurations) + : this.acceptAsClient(configurations); + + return this.params; + } + + /** + * Releases all resources used by the extension. + * + * @public + */ + cleanup() { + if (this._inflate) { + this._inflate.close(); + this._inflate = null; + } + + if (this._deflate) { + const callback = this._deflate[kCallback]; + + this._deflate.close(); + this._deflate = null; + + if (callback) { + callback( + new Error( + 'The deflate stream was closed while data was being processed' + ) + ); + } + } + } + + /** + * Accept an extension negotiation offer. + * + * @param {Array} offers The extension negotiation offers + * @return {Object} Accepted configuration + * @private + */ + acceptAsServer(offers) { + const opts = this._options; + const accepted = offers.find((params) => { + if ( + (opts.serverNoContextTakeover === false && + params.server_no_context_takeover) || + (params.server_max_window_bits && + (opts.serverMaxWindowBits === false || + (typeof opts.serverMaxWindowBits === 'number' && + opts.serverMaxWindowBits > params.server_max_window_bits))) || + (typeof opts.clientMaxWindowBits === 'number' && + !params.client_max_window_bits) + ) { + return false; + } + + return true; + }); + + if (!accepted) { + throw new Error('None of the extension offers can be accepted'); + } + + if (opts.serverNoContextTakeover) { + accepted.server_no_context_takeover = true; + } + if (opts.clientNoContextTakeover) { + accepted.client_no_context_takeover = true; + } + if (typeof opts.serverMaxWindowBits === 'number') { + accepted.server_max_window_bits = opts.serverMaxWindowBits; + } + if (typeof opts.clientMaxWindowBits === 'number') { + accepted.client_max_window_bits = opts.clientMaxWindowBits; + } else if ( + accepted.client_max_window_bits === true || + opts.clientMaxWindowBits === false + ) { + delete accepted.client_max_window_bits; + } + + return accepted; + } + + /** + * Accept the extension negotiation response. + * + * @param {Array} response The extension negotiation response + * @return {Object} Accepted configuration + * @private + */ + acceptAsClient(response) { + const params = response[0]; + + if ( + this._options.clientNoContextTakeover === false && + params.client_no_context_takeover + ) { + throw new Error('Unexpected parameter "client_no_context_takeover"'); + } + + if (!params.client_max_window_bits) { + if (typeof this._options.clientMaxWindowBits === 'number') { + params.client_max_window_bits = this._options.clientMaxWindowBits; + } + } else if ( + this._options.clientMaxWindowBits === false || + (typeof this._options.clientMaxWindowBits === 'number' && + params.client_max_window_bits > this._options.clientMaxWindowBits) + ) { + throw new Error( + 'Unexpected or invalid parameter "client_max_window_bits"' + ); + } + + return params; + } + + /** + * Normalize parameters. + * + * @param {Array} configurations The extension negotiation offers/reponse + * @return {Array} The offers/response with normalized parameters + * @private + */ + normalizeParams(configurations) { + configurations.forEach((params) => { + Object.keys(params).forEach((key) => { + let value = params[key]; + + if (value.length > 1) { + throw new Error(`Parameter "${key}" must have only a single value`); + } + + value = value[0]; + + if (key === 'client_max_window_bits') { + if (value !== true) { + const num = +value; + if (!Number.isInteger(num) || num < 8 || num > 15) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + value = num; + } else if (!this._isServer) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + } else if (key === 'server_max_window_bits') { + const num = +value; + if (!Number.isInteger(num) || num < 8 || num > 15) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + value = num; + } else if ( + key === 'client_no_context_takeover' || + key === 'server_no_context_takeover' + ) { + if (value !== true) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + } else { + throw new Error(`Unknown parameter "${key}"`); + } + + params[key] = value; + }); + }); + + return configurations; + } + + /** + * Decompress data. Concurrency limited. + * + * @param {Buffer} data Compressed data + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @public + */ + decompress(data, fin, callback) { + zlibLimiter.add((done) => { + this._decompress(data, fin, (err, result) => { + done(); + callback(err, result); + }); + }); + } + + /** + * Compress data. Concurrency limited. + * + * @param {Buffer} data Data to compress + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @public + */ + compress(data, fin, callback) { + zlibLimiter.add((done) => { + this._compress(data, fin, (err, result) => { + done(); + callback(err, result); + }); + }); + } + + /** + * Decompress data. + * + * @param {Buffer} data Compressed data + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @private + */ + _decompress(data, fin, callback) { + const endpoint = this._isServer ? 'client' : 'server'; + + if (!this._inflate) { + const key = `${endpoint}_max_window_bits`; + const windowBits = + typeof this.params[key] !== 'number' + ? zlib.Z_DEFAULT_WINDOWBITS + : this.params[key]; + + this._inflate = zlib.createInflateRaw({ + ...this._options.zlibInflateOptions, + windowBits + }); + this._inflate[kPerMessageDeflate] = this; + this._inflate[kTotalLength] = 0; + this._inflate[kBuffers] = []; + this._inflate.on('error', inflateOnError); + this._inflate.on('data', inflateOnData); + } + + this._inflate[kCallback] = callback; + + this._inflate.write(data); + if (fin) this._inflate.write(TRAILER); + + this._inflate.flush(() => { + const err = this._inflate[kError]; + + if (err) { + this._inflate.close(); + this._inflate = null; + callback(err); + return; + } + + const data = bufferUtil.concat( + this._inflate[kBuffers], + this._inflate[kTotalLength] + ); + + if (fin && this.params[`${endpoint}_no_context_takeover`]) { + this._inflate.close(); + this._inflate = null; + } else { + this._inflate[kTotalLength] = 0; + this._inflate[kBuffers] = []; + } + + callback(null, data); + }); + } + + /** + * Compress data. + * + * @param {Buffer} data Data to compress + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @private + */ + _compress(data, fin, callback) { + const endpoint = this._isServer ? 'server' : 'client'; + + if (!this._deflate) { + const key = `${endpoint}_max_window_bits`; + const windowBits = + typeof this.params[key] !== 'number' + ? zlib.Z_DEFAULT_WINDOWBITS + : this.params[key]; + + this._deflate = zlib.createDeflateRaw({ + ...this._options.zlibDeflateOptions, + windowBits + }); + + this._deflate[kTotalLength] = 0; + this._deflate[kBuffers] = []; + + // + // An `'error'` event is emitted, only on Node.js < 10.0.0, if the + // `zlib.DeflateRaw` instance is closed while data is being processed. + // This can happen if `PerMessageDeflate#cleanup()` is called at the wrong + // time due to an abnormal WebSocket closure. + // + this._deflate.on('error', NOOP); + this._deflate.on('data', deflateOnData); + } + + this._deflate[kCallback] = callback; + + this._deflate.write(data); + this._deflate.flush(zlib.Z_SYNC_FLUSH, () => { + if (!this._deflate) { + // + // The deflate stream was closed while data was being processed. + // + return; + } + + let data = bufferUtil.concat( + this._deflate[kBuffers], + this._deflate[kTotalLength] + ); + + if (fin) data = data.slice(0, data.length - 4); + + // + // Ensure that the callback will not be called again in + // `PerMessageDeflate#cleanup()`. + // + this._deflate[kCallback] = null; + + if (fin && this.params[`${endpoint}_no_context_takeover`]) { + this._deflate.close(); + this._deflate = null; + } else { + this._deflate[kTotalLength] = 0; + this._deflate[kBuffers] = []; + } + + callback(null, data); + }); + } +} + +module.exports = PerMessageDeflate; + +/** + * The listener of the `zlib.DeflateRaw` stream `'data'` event. + * + * @param {Buffer} chunk A chunk of data + * @private + */ +function deflateOnData(chunk) { + this[kBuffers].push(chunk); + this[kTotalLength] += chunk.length; +} + +/** + * The listener of the `zlib.InflateRaw` stream `'data'` event. + * + * @param {Buffer} chunk A chunk of data + * @private + */ +function inflateOnData(chunk) { + this[kTotalLength] += chunk.length; + + if ( + this[kPerMessageDeflate]._maxPayload < 1 || + this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload + ) { + this[kBuffers].push(chunk); + return; + } + + this[kError] = new RangeError('Max payload size exceeded'); + this[kError][kStatusCode] = 1009; + this.removeListener('data', inflateOnData); + this.reset(); +} + +/** + * The listener of the `zlib.InflateRaw` stream `'error'` event. + * + * @param {Error} err The emitted error + * @private + */ +function inflateOnError(err) { + // + // There is no need to call `Zlib#close()` as the handle is automatically + // closed when an error is emitted. + // + this[kPerMessageDeflate]._inflate = null; + err[kStatusCode] = 1007; + this[kCallback](err); +} diff --git a/TaskServer/node_modules/ws/lib/receiver.js b/TaskServer/node_modules/ws/lib/receiver.js new file mode 100644 index 000000000..57daa725d --- /dev/null +++ b/TaskServer/node_modules/ws/lib/receiver.js @@ -0,0 +1,506 @@ +'use strict'; + +const { Writable } = require('stream'); + +const PerMessageDeflate = require('./permessage-deflate'); +const { + BINARY_TYPES, + EMPTY_BUFFER, + kStatusCode, + kWebSocket +} = require('./constants'); +const { concat, toArrayBuffer, unmask } = require('./buffer-util'); +const { isValidStatusCode, isValidUTF8 } = require('./validation'); + +const GET_INFO = 0; +const GET_PAYLOAD_LENGTH_16 = 1; +const GET_PAYLOAD_LENGTH_64 = 2; +const GET_MASK = 3; +const GET_DATA = 4; +const INFLATING = 5; + +/** + * HyBi Receiver implementation. + * + * @extends stream.Writable + */ +class Receiver extends Writable { + /** + * Creates a Receiver instance. + * + * @param {String} binaryType The type for binary data + * @param {Object} extensions An object containing the negotiated extensions + * @param {Boolean} isServer Specifies whether to operate in client or server + * mode + * @param {Number} maxPayload The maximum allowed message length + */ + constructor(binaryType, extensions, isServer, maxPayload) { + super(); + + this._binaryType = binaryType || BINARY_TYPES[0]; + this[kWebSocket] = undefined; + this._extensions = extensions || {}; + this._isServer = !!isServer; + this._maxPayload = maxPayload | 0; + + this._bufferedBytes = 0; + this._buffers = []; + + this._compressed = false; + this._payloadLength = 0; + this._mask = undefined; + this._fragmented = 0; + this._masked = false; + this._fin = false; + this._opcode = 0; + + this._totalPayloadLength = 0; + this._messageLength = 0; + this._fragments = []; + + this._state = GET_INFO; + this._loop = false; + } + + /** + * Implements `Writable.prototype._write()`. + * + * @param {Buffer} chunk The chunk of data to write + * @param {String} encoding The character encoding of `chunk` + * @param {Function} cb Callback + */ + _write(chunk, encoding, cb) { + if (this._opcode === 0x08 && this._state == GET_INFO) return cb(); + + this._bufferedBytes += chunk.length; + this._buffers.push(chunk); + this.startLoop(cb); + } + + /** + * Consumes `n` bytes from the buffered data. + * + * @param {Number} n The number of bytes to consume + * @return {Buffer} The consumed bytes + * @private + */ + consume(n) { + this._bufferedBytes -= n; + + if (n === this._buffers[0].length) return this._buffers.shift(); + + if (n < this._buffers[0].length) { + const buf = this._buffers[0]; + this._buffers[0] = buf.slice(n); + return buf.slice(0, n); + } + + const dst = Buffer.allocUnsafe(n); + + do { + const buf = this._buffers[0]; + const offset = dst.length - n; + + if (n >= buf.length) { + dst.set(this._buffers.shift(), offset); + } else { + dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset); + this._buffers[0] = buf.slice(n); + } + + n -= buf.length; + } while (n > 0); + + return dst; + } + + /** + * Starts the parsing loop. + * + * @param {Function} cb Callback + * @private + */ + startLoop(cb) { + let err; + this._loop = true; + + do { + switch (this._state) { + case GET_INFO: + err = this.getInfo(); + break; + case GET_PAYLOAD_LENGTH_16: + err = this.getPayloadLength16(); + break; + case GET_PAYLOAD_LENGTH_64: + err = this.getPayloadLength64(); + break; + case GET_MASK: + this.getMask(); + break; + case GET_DATA: + err = this.getData(cb); + break; + default: + // `INFLATING` + this._loop = false; + return; + } + } while (this._loop); + + cb(err); + } + + /** + * Reads the first two bytes of a frame. + * + * @return {(RangeError|undefined)} A possible error + * @private + */ + getInfo() { + if (this._bufferedBytes < 2) { + this._loop = false; + return; + } + + const buf = this.consume(2); + + if ((buf[0] & 0x30) !== 0x00) { + this._loop = false; + return error(RangeError, 'RSV2 and RSV3 must be clear', true, 1002); + } + + const compressed = (buf[0] & 0x40) === 0x40; + + if (compressed && !this._extensions[PerMessageDeflate.extensionName]) { + this._loop = false; + return error(RangeError, 'RSV1 must be clear', true, 1002); + } + + this._fin = (buf[0] & 0x80) === 0x80; + this._opcode = buf[0] & 0x0f; + this._payloadLength = buf[1] & 0x7f; + + if (this._opcode === 0x00) { + if (compressed) { + this._loop = false; + return error(RangeError, 'RSV1 must be clear', true, 1002); + } + + if (!this._fragmented) { + this._loop = false; + return error(RangeError, 'invalid opcode 0', true, 1002); + } + + this._opcode = this._fragmented; + } else if (this._opcode === 0x01 || this._opcode === 0x02) { + if (this._fragmented) { + this._loop = false; + return error(RangeError, `invalid opcode ${this._opcode}`, true, 1002); + } + + this._compressed = compressed; + } else if (this._opcode > 0x07 && this._opcode < 0x0b) { + if (!this._fin) { + this._loop = false; + return error(RangeError, 'FIN must be set', true, 1002); + } + + if (compressed) { + this._loop = false; + return error(RangeError, 'RSV1 must be clear', true, 1002); + } + + if (this._payloadLength > 0x7d) { + this._loop = false; + return error( + RangeError, + `invalid payload length ${this._payloadLength}`, + true, + 1002 + ); + } + } else { + this._loop = false; + return error(RangeError, `invalid opcode ${this._opcode}`, true, 1002); + } + + if (!this._fin && !this._fragmented) this._fragmented = this._opcode; + this._masked = (buf[1] & 0x80) === 0x80; + + if (this._isServer) { + if (!this._masked) { + this._loop = false; + return error(RangeError, 'MASK must be set', true, 1002); + } + } else if (this._masked) { + this._loop = false; + return error(RangeError, 'MASK must be clear', true, 1002); + } + + if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16; + else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64; + else return this.haveLength(); + } + + /** + * Gets extended payload length (7+16). + * + * @return {(RangeError|undefined)} A possible error + * @private + */ + getPayloadLength16() { + if (this._bufferedBytes < 2) { + this._loop = false; + return; + } + + this._payloadLength = this.consume(2).readUInt16BE(0); + return this.haveLength(); + } + + /** + * Gets extended payload length (7+64). + * + * @return {(RangeError|undefined)} A possible error + * @private + */ + getPayloadLength64() { + if (this._bufferedBytes < 8) { + this._loop = false; + return; + } + + const buf = this.consume(8); + const num = buf.readUInt32BE(0); + + // + // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned + // if payload length is greater than this number. + // + if (num > Math.pow(2, 53 - 32) - 1) { + this._loop = false; + return error( + RangeError, + 'Unsupported WebSocket frame: payload length > 2^53 - 1', + false, + 1009 + ); + } + + this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4); + return this.haveLength(); + } + + /** + * Payload length has been read. + * + * @return {(RangeError|undefined)} A possible error + * @private + */ + haveLength() { + if (this._payloadLength && this._opcode < 0x08) { + this._totalPayloadLength += this._payloadLength; + if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) { + this._loop = false; + return error(RangeError, 'Max payload size exceeded', false, 1009); + } + } + + if (this._masked) this._state = GET_MASK; + else this._state = GET_DATA; + } + + /** + * Reads mask bytes. + * + * @private + */ + getMask() { + if (this._bufferedBytes < 4) { + this._loop = false; + return; + } + + this._mask = this.consume(4); + this._state = GET_DATA; + } + + /** + * Reads data bytes. + * + * @param {Function} cb Callback + * @return {(Error|RangeError|undefined)} A possible error + * @private + */ + getData(cb) { + let data = EMPTY_BUFFER; + + if (this._payloadLength) { + if (this._bufferedBytes < this._payloadLength) { + this._loop = false; + return; + } + + data = this.consume(this._payloadLength); + if (this._masked) unmask(data, this._mask); + } + + if (this._opcode > 0x07) return this.controlMessage(data); + + if (this._compressed) { + this._state = INFLATING; + this.decompress(data, cb); + return; + } + + if (data.length) { + // + // This message is not compressed so its lenght is the sum of the payload + // length of all fragments. + // + this._messageLength = this._totalPayloadLength; + this._fragments.push(data); + } + + return this.dataMessage(); + } + + /** + * Decompresses data. + * + * @param {Buffer} data Compressed data + * @param {Function} cb Callback + * @private + */ + decompress(data, cb) { + const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; + + perMessageDeflate.decompress(data, this._fin, (err, buf) => { + if (err) return cb(err); + + if (buf.length) { + this._messageLength += buf.length; + if (this._messageLength > this._maxPayload && this._maxPayload > 0) { + return cb( + error(RangeError, 'Max payload size exceeded', false, 1009) + ); + } + + this._fragments.push(buf); + } + + const er = this.dataMessage(); + if (er) return cb(er); + + this.startLoop(cb); + }); + } + + /** + * Handles a data message. + * + * @return {(Error|undefined)} A possible error + * @private + */ + dataMessage() { + if (this._fin) { + const messageLength = this._messageLength; + const fragments = this._fragments; + + this._totalPayloadLength = 0; + this._messageLength = 0; + this._fragmented = 0; + this._fragments = []; + + if (this._opcode === 2) { + let data; + + if (this._binaryType === 'nodebuffer') { + data = concat(fragments, messageLength); + } else if (this._binaryType === 'arraybuffer') { + data = toArrayBuffer(concat(fragments, messageLength)); + } else { + data = fragments; + } + + this.emit('message', data); + } else { + const buf = concat(fragments, messageLength); + + if (!isValidUTF8(buf)) { + this._loop = false; + return error(Error, 'invalid UTF-8 sequence', true, 1007); + } + + this.emit('message', buf.toString()); + } + } + + this._state = GET_INFO; + } + + /** + * Handles a control message. + * + * @param {Buffer} data Data to handle + * @return {(Error|RangeError|undefined)} A possible error + * @private + */ + controlMessage(data) { + if (this._opcode === 0x08) { + this._loop = false; + + if (data.length === 0) { + this.emit('conclude', 1005, ''); + this.end(); + } else if (data.length === 1) { + return error(RangeError, 'invalid payload length 1', true, 1002); + } else { + const code = data.readUInt16BE(0); + + if (!isValidStatusCode(code)) { + return error(RangeError, `invalid status code ${code}`, true, 1002); + } + + const buf = data.slice(2); + + if (!isValidUTF8(buf)) { + return error(Error, 'invalid UTF-8 sequence', true, 1007); + } + + this.emit('conclude', code, buf.toString()); + this.end(); + } + } else if (this._opcode === 0x09) { + this.emit('ping', data); + } else { + this.emit('pong', data); + } + + this._state = GET_INFO; + } +} + +module.exports = Receiver; + +/** + * Builds an error object. + * + * @param {(Error|RangeError)} ErrorCtor The error constructor + * @param {String} message The error message + * @param {Boolean} prefix Specifies whether or not to add a default prefix to + * `message` + * @param {Number} statusCode The status code + * @return {(Error|RangeError)} The error + * @private + */ +function error(ErrorCtor, message, prefix, statusCode) { + const err = new ErrorCtor( + prefix ? `Invalid WebSocket frame: ${message}` : message + ); + + Error.captureStackTrace(err, error); + err[kStatusCode] = statusCode; + return err; +} diff --git a/TaskServer/node_modules/ws/lib/sender.js b/TaskServer/node_modules/ws/lib/sender.js new file mode 100644 index 000000000..75c78fb35 --- /dev/null +++ b/TaskServer/node_modules/ws/lib/sender.js @@ -0,0 +1,390 @@ +'use strict'; + +const { randomFillSync } = require('crypto'); + +const PerMessageDeflate = require('./permessage-deflate'); +const { EMPTY_BUFFER } = require('./constants'); +const { isValidStatusCode } = require('./validation'); +const { mask: applyMask, toBuffer } = require('./buffer-util'); + +const mask = Buffer.alloc(4); + +/** + * HyBi Sender implementation. + */ +class Sender { + /** + * Creates a Sender instance. + * + * @param {net.Socket} socket The connection socket + * @param {Object} extensions An object containing the negotiated extensions + */ + constructor(socket, extensions) { + this._extensions = extensions || {}; + this._socket = socket; + + this._firstFragment = true; + this._compress = false; + + this._bufferedBytes = 0; + this._deflating = false; + this._queue = []; + } + + /** + * Frames a piece of data according to the HyBi WebSocket protocol. + * + * @param {Buffer} data The data to frame + * @param {Object} options Options object + * @param {Number} options.opcode The opcode + * @param {Boolean} options.readOnly Specifies whether `data` can be modified + * @param {Boolean} options.fin Specifies whether or not to set the FIN bit + * @param {Boolean} options.mask Specifies whether or not to mask `data` + * @param {Boolean} options.rsv1 Specifies whether or not to set the RSV1 bit + * @return {Buffer[]} The framed data as a list of `Buffer` instances + * @public + */ + static frame(data, options) { + const merge = options.mask && options.readOnly; + let offset = options.mask ? 6 : 2; + let payloadLength = data.length; + + if (data.length >= 65536) { + offset += 8; + payloadLength = 127; + } else if (data.length > 125) { + offset += 2; + payloadLength = 126; + } + + const target = Buffer.allocUnsafe(merge ? data.length + offset : offset); + + target[0] = options.fin ? options.opcode | 0x80 : options.opcode; + if (options.rsv1) target[0] |= 0x40; + + target[1] = payloadLength; + + if (payloadLength === 126) { + target.writeUInt16BE(data.length, 2); + } else if (payloadLength === 127) { + target.writeUInt32BE(0, 2); + target.writeUInt32BE(data.length, 6); + } + + if (!options.mask) return [target, data]; + + randomFillSync(mask, 0, 4); + + target[1] |= 0x80; + target[offset - 4] = mask[0]; + target[offset - 3] = mask[1]; + target[offset - 2] = mask[2]; + target[offset - 1] = mask[3]; + + if (merge) { + applyMask(data, mask, target, offset, data.length); + return [target]; + } + + applyMask(data, mask, data, 0, data.length); + return [target, data]; + } + + /** + * Sends a close message to the other peer. + * + * @param {(Number|undefined)} code The status code component of the body + * @param {String} data The message component of the body + * @param {Boolean} mask Specifies whether or not to mask the message + * @param {Function} cb Callback + * @public + */ + close(code, data, mask, cb) { + let buf; + + if (code === undefined) { + buf = EMPTY_BUFFER; + } else if (typeof code !== 'number' || !isValidStatusCode(code)) { + throw new TypeError('First argument must be a valid error code number'); + } else if (data === undefined || data === '') { + buf = Buffer.allocUnsafe(2); + buf.writeUInt16BE(code, 0); + } else { + const length = Buffer.byteLength(data); + + if (length > 123) { + throw new RangeError('The message must not be greater than 123 bytes'); + } + + buf = Buffer.allocUnsafe(2 + length); + buf.writeUInt16BE(code, 0); + buf.write(data, 2); + } + + if (this._deflating) { + this.enqueue([this.doClose, buf, mask, cb]); + } else { + this.doClose(buf, mask, cb); + } + } + + /** + * Frames and sends a close message. + * + * @param {Buffer} data The message to send + * @param {Boolean} mask Specifies whether or not to mask `data` + * @param {Function} cb Callback + * @private + */ + doClose(data, mask, cb) { + this.sendFrame( + Sender.frame(data, { + fin: true, + rsv1: false, + opcode: 0x08, + mask, + readOnly: false + }), + cb + ); + } + + /** + * Sends a ping message to the other peer. + * + * @param {*} data The message to send + * @param {Boolean} mask Specifies whether or not to mask `data` + * @param {Function} cb Callback + * @public + */ + ping(data, mask, cb) { + const buf = toBuffer(data); + + if (buf.length > 125) { + throw new RangeError('The data size must not be greater than 125 bytes'); + } + + if (this._deflating) { + this.enqueue([this.doPing, buf, mask, toBuffer.readOnly, cb]); + } else { + this.doPing(buf, mask, toBuffer.readOnly, cb); + } + } + + /** + * Frames and sends a ping message. + * + * @param {*} data The message to send + * @param {Boolean} mask Specifies whether or not to mask `data` + * @param {Boolean} readOnly Specifies whether `data` can be modified + * @param {Function} cb Callback + * @private + */ + doPing(data, mask, readOnly, cb) { + this.sendFrame( + Sender.frame(data, { + fin: true, + rsv1: false, + opcode: 0x09, + mask, + readOnly + }), + cb + ); + } + + /** + * Sends a pong message to the other peer. + * + * @param {*} data The message to send + * @param {Boolean} mask Specifies whether or not to mask `data` + * @param {Function} cb Callback + * @public + */ + pong(data, mask, cb) { + const buf = toBuffer(data); + + if (buf.length > 125) { + throw new RangeError('The data size must not be greater than 125 bytes'); + } + + if (this._deflating) { + this.enqueue([this.doPong, buf, mask, toBuffer.readOnly, cb]); + } else { + this.doPong(buf, mask, toBuffer.readOnly, cb); + } + } + + /** + * Frames and sends a pong message. + * + * @param {*} data The message to send + * @param {Boolean} mask Specifies whether or not to mask `data` + * @param {Boolean} readOnly Specifies whether `data` can be modified + * @param {Function} cb Callback + * @private + */ + doPong(data, mask, readOnly, cb) { + this.sendFrame( + Sender.frame(data, { + fin: true, + rsv1: false, + opcode: 0x0a, + mask, + readOnly + }), + cb + ); + } + + /** + * Sends a data message to the other peer. + * + * @param {*} data The message to send + * @param {Object} options Options object + * @param {Boolean} options.compress Specifies whether or not to compress `data` + * @param {Boolean} options.binary Specifies whether `data` is binary or text + * @param {Boolean} options.fin Specifies whether the fragment is the last one + * @param {Boolean} options.mask Specifies whether or not to mask `data` + * @param {Function} cb Callback + * @public + */ + send(data, options, cb) { + const buf = toBuffer(data); + const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; + let opcode = options.binary ? 2 : 1; + let rsv1 = options.compress; + + if (this._firstFragment) { + this._firstFragment = false; + if (rsv1 && perMessageDeflate) { + rsv1 = buf.length >= perMessageDeflate._threshold; + } + this._compress = rsv1; + } else { + rsv1 = false; + opcode = 0; + } + + if (options.fin) this._firstFragment = true; + + if (perMessageDeflate) { + const opts = { + fin: options.fin, + rsv1, + opcode, + mask: options.mask, + readOnly: toBuffer.readOnly + }; + + if (this._deflating) { + this.enqueue([this.dispatch, buf, this._compress, opts, cb]); + } else { + this.dispatch(buf, this._compress, opts, cb); + } + } else { + this.sendFrame( + Sender.frame(buf, { + fin: options.fin, + rsv1: false, + opcode, + mask: options.mask, + readOnly: toBuffer.readOnly + }), + cb + ); + } + } + + /** + * Dispatches a data message. + * + * @param {Buffer} data The message to send + * @param {Boolean} compress Specifies whether or not to compress `data` + * @param {Object} options Options object + * @param {Number} options.opcode The opcode + * @param {Boolean} options.readOnly Specifies whether `data` can be modified + * @param {Boolean} options.fin Specifies whether or not to set the FIN bit + * @param {Boolean} options.mask Specifies whether or not to mask `data` + * @param {Boolean} options.rsv1 Specifies whether or not to set the RSV1 bit + * @param {Function} cb Callback + * @private + */ + dispatch(data, compress, options, cb) { + if (!compress) { + this.sendFrame(Sender.frame(data, options), cb); + return; + } + + const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; + + this._deflating = true; + perMessageDeflate.compress(data, options.fin, (_, buf) => { + if (this._socket.destroyed) { + const err = new Error( + 'The socket was closed while data was being compressed' + ); + + if (typeof cb === 'function') cb(err); + + for (let i = 0; i < this._queue.length; i++) { + const callback = this._queue[i][4]; + + if (typeof callback === 'function') callback(err); + } + + return; + } + + this._deflating = false; + options.readOnly = false; + this.sendFrame(Sender.frame(buf, options), cb); + this.dequeue(); + }); + } + + /** + * Executes queued send operations. + * + * @private + */ + dequeue() { + while (!this._deflating && this._queue.length) { + const params = this._queue.shift(); + + this._bufferedBytes -= params[1].length; + Reflect.apply(params[0], this, params.slice(1)); + } + } + + /** + * Enqueues a send operation. + * + * @param {Array} params Send operation parameters. + * @private + */ + enqueue(params) { + this._bufferedBytes += params[1].length; + this._queue.push(params); + } + + /** + * Sends a frame. + * + * @param {Buffer[]} list The frame to send + * @param {Function} cb Callback + * @private + */ + sendFrame(list, cb) { + if (list.length === 2) { + this._socket.cork(); + this._socket.write(list[0]); + this._socket.write(list[1], cb); + this._socket.uncork(); + } else { + this._socket.write(list[0], cb); + } + } +} + +module.exports = Sender; diff --git a/TaskServer/node_modules/ws/lib/stream.js b/TaskServer/node_modules/ws/lib/stream.js new file mode 100644 index 000000000..c6811afb1 --- /dev/null +++ b/TaskServer/node_modules/ws/lib/stream.js @@ -0,0 +1,164 @@ +'use strict'; + +const { Duplex } = require('stream'); + +/** + * Emits the `'close'` event on a stream. + * + * @param {stream.Duplex} The stream. + * @private + */ +function emitClose(stream) { + stream.emit('close'); +} + +/** + * The listener of the `'end'` event. + * + * @private + */ +function duplexOnEnd() { + if (!this.destroyed && this._writableState.finished) { + this.destroy(); + } +} + +/** + * The listener of the `'error'` event. + * + * @private + */ +function duplexOnError(err) { + this.removeListener('error', duplexOnError); + this.destroy(); + if (this.listenerCount('error') === 0) { + // Do not suppress the throwing behavior. + this.emit('error', err); + } +} + +/** + * Wraps a `WebSocket` in a duplex stream. + * + * @param {WebSocket} ws The `WebSocket` to wrap + * @param {Object} options The options for the `Duplex` constructor + * @return {stream.Duplex} The duplex stream + * @public + */ +function createWebSocketStream(ws, options) { + let resumeOnReceiverDrain = true; + + function receiverOnDrain() { + if (resumeOnReceiverDrain) ws._socket.resume(); + } + + if (ws.readyState === ws.CONNECTING) { + ws.once('open', function open() { + ws._receiver.removeAllListeners('drain'); + ws._receiver.on('drain', receiverOnDrain); + }); + } else { + ws._receiver.removeAllListeners('drain'); + ws._receiver.on('drain', receiverOnDrain); + } + + const duplex = new Duplex({ + ...options, + autoDestroy: false, + emitClose: false, + objectMode: false, + writableObjectMode: false + }); + + ws.on('message', function message(msg) { + if (!duplex.push(msg)) { + resumeOnReceiverDrain = false; + ws._socket.pause(); + } + }); + + ws.once('error', function error(err) { + if (duplex.destroyed) return; + + duplex.destroy(err); + }); + + ws.once('close', function close() { + if (duplex.destroyed) return; + + duplex.push(null); + }); + + duplex._destroy = function(err, callback) { + if (ws.readyState === ws.CLOSED) { + callback(err); + process.nextTick(emitClose, duplex); + return; + } + + let called = false; + + ws.once('error', function error(err) { + called = true; + callback(err); + }); + + ws.once('close', function close() { + if (!called) callback(err); + process.nextTick(emitClose, duplex); + }); + ws.terminate(); + }; + + duplex._final = function(callback) { + if (ws.readyState === ws.CONNECTING) { + ws.once('open', function open() { + duplex._final(callback); + }); + return; + } + + // If the value of the `_socket` property is `null` it means that `ws` is a + // client websocket and the handshake failed. In fact, when this happens, a + // socket is never assigned to the websocket. Wait for the `'error'` event + // that will be emitted by the websocket. + if (ws._socket === null) return; + + if (ws._socket._writableState.finished) { + if (duplex._readableState.endEmitted) duplex.destroy(); + callback(); + } else { + ws._socket.once('finish', function finish() { + // `duplex` is not destroyed here because the `'end'` event will be + // emitted on `duplex` after this `'finish'` event. The EOF signaling + // `null` chunk is, in fact, pushed when the websocket emits `'close'`. + callback(); + }); + ws.close(); + } + }; + + duplex._read = function() { + if (ws.readyState === ws.OPEN && !resumeOnReceiverDrain) { + resumeOnReceiverDrain = true; + if (!ws._receiver._writableState.needDrain) ws._socket.resume(); + } + }; + + duplex._write = function(chunk, encoding, callback) { + if (ws.readyState === ws.CONNECTING) { + ws.once('open', function open() { + duplex._write(chunk, encoding, callback); + }); + return; + } + + ws.send(chunk, callback); + }; + + duplex.on('end', duplexOnEnd); + duplex.on('error', duplexOnError); + return duplex; +} + +module.exports = createWebSocketStream; diff --git a/TaskServer/node_modules/ws/lib/validation.js b/TaskServer/node_modules/ws/lib/validation.js new file mode 100644 index 000000000..32db5a570 --- /dev/null +++ b/TaskServer/node_modules/ws/lib/validation.js @@ -0,0 +1,30 @@ +'use strict'; + +try { + const isValidUTF8 = require('utf-8-validate'); + + exports.isValidUTF8 = + typeof isValidUTF8 === 'object' + ? isValidUTF8.Validation.isValidUTF8 // utf-8-validate@<3.0.0 + : isValidUTF8; +} catch (e) /* istanbul ignore next */ { + exports.isValidUTF8 = () => true; +} + +/** + * Checks if a status code is allowed in a close frame. + * + * @param {Number} code The status code + * @return {Boolean} `true` if the status code is valid, else `false` + * @public + */ +exports.isValidStatusCode = (code) => { + return ( + (code >= 1000 && + code <= 1014 && + code !== 1004 && + code !== 1005 && + code !== 1006) || + (code >= 3000 && code <= 4999) + ); +}; diff --git a/TaskServer/node_modules/ws/lib/websocket-server.js b/TaskServer/node_modules/ws/lib/websocket-server.js new file mode 100644 index 000000000..057a12be5 --- /dev/null +++ b/TaskServer/node_modules/ws/lib/websocket-server.js @@ -0,0 +1,406 @@ +'use strict'; + +const EventEmitter = require('events'); +const { createHash } = require('crypto'); +const { createServer, STATUS_CODES } = require('http'); + +const PerMessageDeflate = require('./permessage-deflate'); +const WebSocket = require('./websocket'); +const { format, parse } = require('./extension'); +const { GUID } = require('./constants'); + +const keyRegex = /^[+/0-9A-Za-z]{22}==$/; +const kUsedByWebSocketServer = Symbol('kUsedByWebSocketServer'); + +/** + * Class representing a WebSocket server. + * + * @extends EventEmitter + */ +class WebSocketServer extends EventEmitter { + /** + * Create a `WebSocketServer` instance. + * + * @param {Object} options Configuration options + * @param {Number} options.backlog The maximum length of the queue of pending + * connections + * @param {Boolean} options.clientTracking Specifies whether or not to track + * clients + * @param {Function} options.handleProtocols A hook to handle protocols + * @param {String} options.host The hostname where to bind the server + * @param {Number} options.maxPayload The maximum allowed message size + * @param {Boolean} options.noServer Enable no server mode + * @param {String} options.path Accept only connections matching this path + * @param {(Boolean|Object)} options.perMessageDeflate Enable/disable + * permessage-deflate + * @param {Number} options.port The port where to bind the server + * @param {http.Server} options.server A pre-created HTTP/S server to use + * @param {Function} options.verifyClient A hook to reject connections + * @param {Function} callback A listener for the `listening` event + */ + constructor(options, callback) { + super(); + + options = { + maxPayload: 100 * 1024 * 1024, + perMessageDeflate: false, + handleProtocols: null, + clientTracking: true, + verifyClient: null, + noServer: false, + backlog: null, // use default (511 as implemented in net.js) + server: null, + host: null, + path: null, + port: null, + ...options + }; + + if (options.port == null && !options.server && !options.noServer) { + throw new TypeError( + 'One of the "port", "server", or "noServer" options must be specified' + ); + } + + if (options.port != null) { + this._server = createServer((req, res) => { + const body = STATUS_CODES[426]; + + res.writeHead(426, { + 'Content-Length': body.length, + 'Content-Type': 'text/plain' + }); + res.end(body); + }); + this._server.listen( + options.port, + options.host, + options.backlog, + callback + ); + } else if (options.server) { + if (options.server[kUsedByWebSocketServer]) { + throw new Error( + 'The HTTP/S server is already being used by another WebSocket server' + ); + } + + options.server[kUsedByWebSocketServer] = true; + this._server = options.server; + } + + if (this._server) { + this._removeListeners = addListeners(this._server, { + listening: this.emit.bind(this, 'listening'), + error: this.emit.bind(this, 'error'), + upgrade: (req, socket, head) => { + this.handleUpgrade(req, socket, head, (ws) => { + this.emit('connection', ws, req); + }); + } + }); + } + + if (options.perMessageDeflate === true) options.perMessageDeflate = {}; + if (options.clientTracking) this.clients = new Set(); + this.options = options; + } + + /** + * Returns the bound address, the address family name, and port of the server + * as reported by the operating system if listening on an IP socket. + * If the server is listening on a pipe or UNIX domain socket, the name is + * returned as a string. + * + * @return {(Object|String|null)} The address of the server + * @public + */ + address() { + if (this.options.noServer) { + throw new Error('The server is operating in "noServer" mode'); + } + + if (!this._server) return null; + return this._server.address(); + } + + /** + * Close the server. + * + * @param {Function} cb Callback + * @public + */ + close(cb) { + if (cb) this.once('close', cb); + + // + // Terminate all associated clients. + // + if (this.clients) { + for (const client of this.clients) client.terminate(); + } + + const server = this._server; + + if (server) { + this._removeListeners(); + this._removeListeners = this._server = null; + + // + // Close the http server if it was internally created. + // + if (this.options.port != null) { + server.close(() => this.emit('close')); + return; + } + + delete server[kUsedByWebSocketServer]; + } + + process.nextTick(emitClose, this); + } + + /** + * See if a given request should be handled by this server instance. + * + * @param {http.IncomingMessage} req Request object to inspect + * @return {Boolean} `true` if the request is valid, else `false` + * @public + */ + shouldHandle(req) { + if (this.options.path) { + const index = req.url.indexOf('?'); + const pathname = index !== -1 ? req.url.slice(0, index) : req.url; + + if (pathname !== this.options.path) return false; + } + + return true; + } + + /** + * Handle a HTTP Upgrade request. + * + * @param {http.IncomingMessage} req The request object + * @param {net.Socket} socket The network socket between the server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Function} cb Callback + * @public + */ + handleUpgrade(req, socket, head, cb) { + socket.on('error', socketOnError); + + const key = + req.headers['sec-websocket-key'] !== undefined + ? req.headers['sec-websocket-key'].trim() + : false; + const version = +req.headers['sec-websocket-version']; + const extensions = {}; + + if ( + req.method !== 'GET' || + req.headers.upgrade.toLowerCase() !== 'websocket' || + !key || + !keyRegex.test(key) || + (version !== 8 && version !== 13) || + !this.shouldHandle(req) + ) { + return abortHandshake(socket, 400); + } + + if (this.options.perMessageDeflate) { + const perMessageDeflate = new PerMessageDeflate( + this.options.perMessageDeflate, + true, + this.options.maxPayload + ); + + try { + const offers = parse(req.headers['sec-websocket-extensions']); + + if (offers[PerMessageDeflate.extensionName]) { + perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]); + extensions[PerMessageDeflate.extensionName] = perMessageDeflate; + } + } catch (err) { + return abortHandshake(socket, 400); + } + } + + // + // Optionally call external client verification handler. + // + if (this.options.verifyClient) { + const info = { + origin: + req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`], + secure: !!(req.connection.authorized || req.connection.encrypted), + req + }; + + if (this.options.verifyClient.length === 2) { + this.options.verifyClient(info, (verified, code, message, headers) => { + if (!verified) { + return abortHandshake(socket, code || 401, message, headers); + } + + this.completeUpgrade(key, extensions, req, socket, head, cb); + }); + return; + } + + if (!this.options.verifyClient(info)) return abortHandshake(socket, 401); + } + + this.completeUpgrade(key, extensions, req, socket, head, cb); + } + + /** + * Upgrade the connection to WebSocket. + * + * @param {String} key The value of the `Sec-WebSocket-Key` header + * @param {Object} extensions The accepted extensions + * @param {http.IncomingMessage} req The request object + * @param {net.Socket} socket The network socket between the server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Function} cb Callback + * @private + */ + completeUpgrade(key, extensions, req, socket, head, cb) { + // + // Destroy the socket if the client has already sent a FIN packet. + // + if (!socket.readable || !socket.writable) return socket.destroy(); + + const digest = createHash('sha1') + .update(key + GUID) + .digest('base64'); + + const headers = [ + 'HTTP/1.1 101 Switching Protocols', + 'Upgrade: websocket', + 'Connection: Upgrade', + `Sec-WebSocket-Accept: ${digest}` + ]; + + const ws = new WebSocket(null); + let protocol = req.headers['sec-websocket-protocol']; + + if (protocol) { + protocol = protocol.trim().split(/ *, */); + + // + // Optionally call external protocol selection handler. + // + if (this.options.handleProtocols) { + protocol = this.options.handleProtocols(protocol, req); + } else { + protocol = protocol[0]; + } + + if (protocol) { + headers.push(`Sec-WebSocket-Protocol: ${protocol}`); + ws.protocol = protocol; + } + } + + if (extensions[PerMessageDeflate.extensionName]) { + const params = extensions[PerMessageDeflate.extensionName].params; + const value = format({ + [PerMessageDeflate.extensionName]: [params] + }); + headers.push(`Sec-WebSocket-Extensions: ${value}`); + ws._extensions = extensions; + } + + // + // Allow external modification/inspection of handshake headers. + // + this.emit('headers', headers, req); + + socket.write(headers.concat('\r\n').join('\r\n')); + socket.removeListener('error', socketOnError); + + ws.setSocket(socket, head, this.options.maxPayload); + + if (this.clients) { + this.clients.add(ws); + ws.on('close', () => this.clients.delete(ws)); + } + + cb(ws); + } +} + +module.exports = WebSocketServer; + +/** + * Add event listeners on an `EventEmitter` using a map of + * pairs. + * + * @param {EventEmitter} server The event emitter + * @param {Object.} map The listeners to add + * @return {Function} A function that will remove the added listeners when called + * @private + */ +function addListeners(server, map) { + for (const event of Object.keys(map)) server.on(event, map[event]); + + return function removeListeners() { + for (const event of Object.keys(map)) { + server.removeListener(event, map[event]); + } + }; +} + +/** + * Emit a `'close'` event on an `EventEmitter`. + * + * @param {EventEmitter} server The event emitter + * @private + */ +function emitClose(server) { + server.emit('close'); +} + +/** + * Handle premature socket errors. + * + * @private + */ +function socketOnError() { + this.destroy(); +} + +/** + * Close the connection when preconditions are not fulfilled. + * + * @param {net.Socket} socket The socket of the upgrade request + * @param {Number} code The HTTP response status code + * @param {String} [message] The HTTP response body + * @param {Object} [headers] Additional HTTP response headers + * @private + */ +function abortHandshake(socket, code, message, headers) { + if (socket.writable) { + message = message || STATUS_CODES[code]; + headers = { + Connection: 'close', + 'Content-type': 'text/html', + 'Content-Length': Buffer.byteLength(message), + ...headers + }; + + socket.write( + `HTTP/1.1 ${code} ${STATUS_CODES[code]}\r\n` + + Object.keys(headers) + .map((h) => `${h}: ${headers[h]}`) + .join('\r\n') + + '\r\n\r\n' + + message + ); + } + + socket.removeListener('error', socketOnError); + socket.destroy(); +} diff --git a/TaskServer/node_modules/ws/lib/websocket.js b/TaskServer/node_modules/ws/lib/websocket.js new file mode 100644 index 000000000..ca72ad76d --- /dev/null +++ b/TaskServer/node_modules/ws/lib/websocket.js @@ -0,0 +1,909 @@ +'use strict'; + +const EventEmitter = require('events'); +const https = require('https'); +const http = require('http'); +const net = require('net'); +const tls = require('tls'); +const { randomBytes, createHash } = require('crypto'); +const { URL } = require('url'); + +const PerMessageDeflate = require('./permessage-deflate'); +const Receiver = require('./receiver'); +const Sender = require('./sender'); +const { + BINARY_TYPES, + EMPTY_BUFFER, + GUID, + kStatusCode, + kWebSocket, + NOOP +} = require('./constants'); +const { addEventListener, removeEventListener } = require('./event-target'); +const { format, parse } = require('./extension'); +const { toBuffer } = require('./buffer-util'); + +const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; +const protocolVersions = [8, 13]; +const closeTimeout = 30 * 1000; + +/** + * Class representing a WebSocket. + * + * @extends EventEmitter + */ +class WebSocket extends EventEmitter { + /** + * Create a new `WebSocket`. + * + * @param {(String|url.URL)} address The URL to which to connect + * @param {(String|String[])} protocols The subprotocols + * @param {Object} options Connection options + */ + constructor(address, protocols, options) { + super(); + + this.readyState = WebSocket.CONNECTING; + this.protocol = ''; + + this._binaryType = BINARY_TYPES[0]; + this._closeFrameReceived = false; + this._closeFrameSent = false; + this._closeMessage = ''; + this._closeTimer = null; + this._closeCode = 1006; + this._extensions = {}; + this._receiver = null; + this._sender = null; + this._socket = null; + + if (address !== null) { + this._bufferedAmount = 0; + this._isServer = false; + this._redirects = 0; + + if (Array.isArray(protocols)) { + protocols = protocols.join(', '); + } else if (typeof protocols === 'object' && protocols !== null) { + options = protocols; + protocols = undefined; + } + + initAsClient(this, address, protocols, options); + } else { + this._isServer = true; + } + } + + get CONNECTING() { + return WebSocket.CONNECTING; + } + get CLOSING() { + return WebSocket.CLOSING; + } + get CLOSED() { + return WebSocket.CLOSED; + } + get OPEN() { + return WebSocket.OPEN; + } + + /** + * This deviates from the WHATWG interface since ws doesn't support the + * required default "blob" type (instead we define a custom "nodebuffer" + * type). + * + * @type {String} + */ + get binaryType() { + return this._binaryType; + } + + set binaryType(type) { + if (!BINARY_TYPES.includes(type)) return; + + this._binaryType = type; + + // + // Allow to change `binaryType` on the fly. + // + if (this._receiver) this._receiver._binaryType = type; + } + + /** + * @type {Number} + */ + get bufferedAmount() { + if (!this._socket) return this._bufferedAmount; + + // + // `socket.bufferSize` is `undefined` if the socket is closed. + // + return (this._socket.bufferSize || 0) + this._sender._bufferedBytes; + } + + /** + * @type {String} + */ + get extensions() { + return Object.keys(this._extensions).join(); + } + + /** + * Set up the socket and the internal resources. + * + * @param {net.Socket} socket The network socket between the server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Number} maxPayload The maximum allowed message size + * @private + */ + setSocket(socket, head, maxPayload) { + const receiver = new Receiver( + this._binaryType, + this._extensions, + this._isServer, + maxPayload + ); + + this._sender = new Sender(socket, this._extensions); + this._receiver = receiver; + this._socket = socket; + + receiver[kWebSocket] = this; + socket[kWebSocket] = this; + + receiver.on('conclude', receiverOnConclude); + receiver.on('drain', receiverOnDrain); + receiver.on('error', receiverOnError); + receiver.on('message', receiverOnMessage); + receiver.on('ping', receiverOnPing); + receiver.on('pong', receiverOnPong); + + socket.setTimeout(0); + socket.setNoDelay(); + + if (head.length > 0) socket.unshift(head); + + socket.on('close', socketOnClose); + socket.on('data', socketOnData); + socket.on('end', socketOnEnd); + socket.on('error', socketOnError); + + this.readyState = WebSocket.OPEN; + this.emit('open'); + } + + /** + * Emit the `'close'` event. + * + * @private + */ + emitClose() { + if (!this._socket) { + this.readyState = WebSocket.CLOSED; + this.emit('close', this._closeCode, this._closeMessage); + return; + } + + if (this._extensions[PerMessageDeflate.extensionName]) { + this._extensions[PerMessageDeflate.extensionName].cleanup(); + } + + this._receiver.removeAllListeners(); + this.readyState = WebSocket.CLOSED; + this.emit('close', this._closeCode, this._closeMessage); + } + + /** + * Start a closing handshake. + * + * +----------+ +-----------+ +----------+ + * - - -|ws.close()|-->|close frame|-->|ws.close()|- - - + * | +----------+ +-----------+ +----------+ | + * +----------+ +-----------+ | + * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING + * +----------+ +-----------+ | + * | | | +---+ | + * +------------------------+-->|fin| - - - - + * | +---+ | +---+ + * - - - - -|fin|<---------------------+ + * +---+ + * + * @param {Number} code Status code explaining why the connection is closing + * @param {String} data A string explaining why the connection is closing + * @public + */ + close(code, data) { + if (this.readyState === WebSocket.CLOSED) return; + if (this.readyState === WebSocket.CONNECTING) { + const msg = 'WebSocket was closed before the connection was established'; + return abortHandshake(this, this._req, msg); + } + + if (this.readyState === WebSocket.CLOSING) { + if (this._closeFrameSent && this._closeFrameReceived) this._socket.end(); + return; + } + + this.readyState = WebSocket.CLOSING; + this._sender.close(code, data, !this._isServer, (err) => { + // + // This error is handled by the `'error'` listener on the socket. We only + // want to know if the close frame has been sent here. + // + if (err) return; + + this._closeFrameSent = true; + if (this._closeFrameReceived) this._socket.end(); + }); + + // + // Specify a timeout for the closing handshake to complete. + // + this._closeTimer = setTimeout( + this._socket.destroy.bind(this._socket), + closeTimeout + ); + } + + /** + * Send a ping. + * + * @param {*} data The data to send + * @param {Boolean} mask Indicates whether or not to mask `data` + * @param {Function} cb Callback which is executed when the ping is sent + * @public + */ + ping(data, mask, cb) { + if (this.readyState === WebSocket.CONNECTING) { + throw new Error('WebSocket is not open: readyState 0 (CONNECTING)'); + } + + if (typeof data === 'function') { + cb = data; + data = mask = undefined; + } else if (typeof mask === 'function') { + cb = mask; + mask = undefined; + } + + if (typeof data === 'number') data = data.toString(); + + if (this.readyState !== WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; + } + + if (mask === undefined) mask = !this._isServer; + this._sender.ping(data || EMPTY_BUFFER, mask, cb); + } + + /** + * Send a pong. + * + * @param {*} data The data to send + * @param {Boolean} mask Indicates whether or not to mask `data` + * @param {Function} cb Callback which is executed when the pong is sent + * @public + */ + pong(data, mask, cb) { + if (this.readyState === WebSocket.CONNECTING) { + throw new Error('WebSocket is not open: readyState 0 (CONNECTING)'); + } + + if (typeof data === 'function') { + cb = data; + data = mask = undefined; + } else if (typeof mask === 'function') { + cb = mask; + mask = undefined; + } + + if (typeof data === 'number') data = data.toString(); + + if (this.readyState !== WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; + } + + if (mask === undefined) mask = !this._isServer; + this._sender.pong(data || EMPTY_BUFFER, mask, cb); + } + + /** + * Send a data message. + * + * @param {*} data The message to send + * @param {Object} options Options object + * @param {Boolean} options.compress Specifies whether or not to compress + * `data` + * @param {Boolean} options.binary Specifies whether `data` is binary or text + * @param {Boolean} options.fin Specifies whether the fragment is the last one + * @param {Boolean} options.mask Specifies whether or not to mask `data` + * @param {Function} cb Callback which is executed when data is written out + * @public + */ + send(data, options, cb) { + if (this.readyState === WebSocket.CONNECTING) { + throw new Error('WebSocket is not open: readyState 0 (CONNECTING)'); + } + + if (typeof options === 'function') { + cb = options; + options = {}; + } + + if (typeof data === 'number') data = data.toString(); + + if (this.readyState !== WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; + } + + const opts = { + binary: typeof data !== 'string', + mask: !this._isServer, + compress: true, + fin: true, + ...options + }; + + if (!this._extensions[PerMessageDeflate.extensionName]) { + opts.compress = false; + } + + this._sender.send(data || EMPTY_BUFFER, opts, cb); + } + + /** + * Forcibly close the connection. + * + * @public + */ + terminate() { + if (this.readyState === WebSocket.CLOSED) return; + if (this.readyState === WebSocket.CONNECTING) { + const msg = 'WebSocket was closed before the connection was established'; + return abortHandshake(this, this._req, msg); + } + + if (this._socket) { + this.readyState = WebSocket.CLOSING; + this._socket.destroy(); + } + } +} + +readyStates.forEach((readyState, i) => { + WebSocket[readyState] = i; +}); + +// +// Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes. +// See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface +// +['open', 'error', 'close', 'message'].forEach((method) => { + Object.defineProperty(WebSocket.prototype, `on${method}`, { + /** + * Return the listener of the event. + * + * @return {(Function|undefined)} The event listener or `undefined` + * @public + */ + get() { + const listeners = this.listeners(method); + for (let i = 0; i < listeners.length; i++) { + if (listeners[i]._listener) return listeners[i]._listener; + } + + return undefined; + }, + /** + * Add a listener for the event. + * + * @param {Function} listener The listener to add + * @public + */ + set(listener) { + const listeners = this.listeners(method); + for (let i = 0; i < listeners.length; i++) { + // + // Remove only the listeners added via `addEventListener`. + // + if (listeners[i]._listener) this.removeListener(method, listeners[i]); + } + this.addEventListener(method, listener); + } + }); +}); + +WebSocket.prototype.addEventListener = addEventListener; +WebSocket.prototype.removeEventListener = removeEventListener; + +module.exports = WebSocket; + +/** + * Initialize a WebSocket client. + * + * @param {WebSocket} websocket The client to initialize + * @param {(String|url.URL)} address The URL to which to connect + * @param {String} protocols The subprotocols + * @param {Object} options Connection options + * @param {(Boolean|Object)} options.perMessageDeflate Enable/disable + * permessage-deflate + * @param {Number} options.handshakeTimeout Timeout in milliseconds for the + * handshake request + * @param {Number} options.protocolVersion Value of the `Sec-WebSocket-Version` + * header + * @param {String} options.origin Value of the `Origin` or + * `Sec-WebSocket-Origin` header + * @param {Number} options.maxPayload The maximum allowed message size + * @param {Boolean} options.followRedirects Whether or not to follow redirects + * @param {Number} options.maxRedirects The maximum number of redirects allowed + * @private + */ +function initAsClient(websocket, address, protocols, options) { + const opts = { + protocolVersion: protocolVersions[1], + maxPayload: 100 * 1024 * 1024, + perMessageDeflate: true, + followRedirects: false, + maxRedirects: 10, + ...options, + createConnection: undefined, + socketPath: undefined, + hostname: undefined, + protocol: undefined, + timeout: undefined, + method: undefined, + auth: undefined, + host: undefined, + path: undefined, + port: undefined + }; + + if (!protocolVersions.includes(opts.protocolVersion)) { + throw new RangeError( + `Unsupported protocol version: ${opts.protocolVersion} ` + + `(supported versions: ${protocolVersions.join(', ')})` + ); + } + + let parsedUrl; + + if (address instanceof URL) { + parsedUrl = address; + websocket.url = address.href; + } else { + parsedUrl = new URL(address); + websocket.url = address; + } + + const isUnixSocket = parsedUrl.protocol === 'ws+unix:'; + + if (!parsedUrl.host && (!isUnixSocket || !parsedUrl.pathname)) { + throw new Error(`Invalid URL: ${websocket.url}`); + } + + const isSecure = + parsedUrl.protocol === 'wss:' || parsedUrl.protocol === 'https:'; + const defaultPort = isSecure ? 443 : 80; + const key = randomBytes(16).toString('base64'); + const get = isSecure ? https.get : http.get; + let perMessageDeflate; + + opts.createConnection = isSecure ? tlsConnect : netConnect; + opts.defaultPort = opts.defaultPort || defaultPort; + opts.port = parsedUrl.port || defaultPort; + opts.host = parsedUrl.hostname.startsWith('[') + ? parsedUrl.hostname.slice(1, -1) + : parsedUrl.hostname; + opts.headers = { + 'Sec-WebSocket-Version': opts.protocolVersion, + 'Sec-WebSocket-Key': key, + Connection: 'Upgrade', + Upgrade: 'websocket', + ...opts.headers + }; + opts.path = parsedUrl.pathname + parsedUrl.search; + opts.timeout = opts.handshakeTimeout; + + if (opts.perMessageDeflate) { + perMessageDeflate = new PerMessageDeflate( + opts.perMessageDeflate !== true ? opts.perMessageDeflate : {}, + false, + opts.maxPayload + ); + opts.headers['Sec-WebSocket-Extensions'] = format({ + [PerMessageDeflate.extensionName]: perMessageDeflate.offer() + }); + } + if (protocols) { + opts.headers['Sec-WebSocket-Protocol'] = protocols; + } + if (opts.origin) { + if (opts.protocolVersion < 13) { + opts.headers['Sec-WebSocket-Origin'] = opts.origin; + } else { + opts.headers.Origin = opts.origin; + } + } + if (parsedUrl.username || parsedUrl.password) { + opts.auth = `${parsedUrl.username}:${parsedUrl.password}`; + } + + if (isUnixSocket) { + const parts = opts.path.split(':'); + + opts.socketPath = parts[0]; + opts.path = parts[1]; + } + + let req = (websocket._req = get(opts)); + + if (opts.timeout) { + req.on('timeout', () => { + abortHandshake(websocket, req, 'Opening handshake has timed out'); + }); + } + + req.on('error', (err) => { + if (websocket._req.aborted) return; + + req = websocket._req = null; + websocket.readyState = WebSocket.CLOSING; + websocket.emit('error', err); + websocket.emitClose(); + }); + + req.on('response', (res) => { + const location = res.headers.location; + const statusCode = res.statusCode; + + if ( + location && + opts.followRedirects && + statusCode >= 300 && + statusCode < 400 + ) { + if (++websocket._redirects > opts.maxRedirects) { + abortHandshake(websocket, req, 'Maximum redirects exceeded'); + return; + } + + req.abort(); + + const addr = new URL(location, address); + + initAsClient(websocket, addr, protocols, options); + } else if (!websocket.emit('unexpected-response', req, res)) { + abortHandshake( + websocket, + req, + `Unexpected server response: ${res.statusCode}` + ); + } + }); + + req.on('upgrade', (res, socket, head) => { + websocket.emit('upgrade', res); + + // + // The user may have closed the connection from a listener of the `upgrade` + // event. + // + if (websocket.readyState !== WebSocket.CONNECTING) return; + + req = websocket._req = null; + + const digest = createHash('sha1') + .update(key + GUID) + .digest('base64'); + + if (res.headers['sec-websocket-accept'] !== digest) { + abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header'); + return; + } + + const serverProt = res.headers['sec-websocket-protocol']; + const protList = (protocols || '').split(/, */); + let protError; + + if (!protocols && serverProt) { + protError = 'Server sent a subprotocol but none was requested'; + } else if (protocols && !serverProt) { + protError = 'Server sent no subprotocol'; + } else if (serverProt && !protList.includes(serverProt)) { + protError = 'Server sent an invalid subprotocol'; + } + + if (protError) { + abortHandshake(websocket, socket, protError); + return; + } + + if (serverProt) websocket.protocol = serverProt; + + if (perMessageDeflate) { + try { + const extensions = parse(res.headers['sec-websocket-extensions']); + + if (extensions[PerMessageDeflate.extensionName]) { + perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]); + websocket._extensions[ + PerMessageDeflate.extensionName + ] = perMessageDeflate; + } + } catch (err) { + abortHandshake( + websocket, + socket, + 'Invalid Sec-WebSocket-Extensions header' + ); + return; + } + } + + websocket.setSocket(socket, head, opts.maxPayload); + }); +} + +/** + * Create a `net.Socket` and initiate a connection. + * + * @param {Object} options Connection options + * @return {net.Socket} The newly created socket used to start the connection + * @private + */ +function netConnect(options) { + options.path = options.socketPath; + return net.connect(options); +} + +/** + * Create a `tls.TLSSocket` and initiate a connection. + * + * @param {Object} options Connection options + * @return {tls.TLSSocket} The newly created socket used to start the connection + * @private + */ +function tlsConnect(options) { + options.path = undefined; + + if (!options.servername && options.servername !== '') { + options.servername = options.host; + } + + return tls.connect(options); +} + +/** + * Abort the handshake and emit an error. + * + * @param {WebSocket} websocket The WebSocket instance + * @param {(http.ClientRequest|net.Socket)} stream The request to abort or the + * socket to destroy + * @param {String} message The error message + * @private + */ +function abortHandshake(websocket, stream, message) { + websocket.readyState = WebSocket.CLOSING; + + const err = new Error(message); + Error.captureStackTrace(err, abortHandshake); + + if (stream.setHeader) { + stream.abort(); + stream.once('abort', websocket.emitClose.bind(websocket)); + websocket.emit('error', err); + } else { + stream.destroy(err); + stream.once('error', websocket.emit.bind(websocket, 'error')); + stream.once('close', websocket.emitClose.bind(websocket)); + } +} + +/** + * Handle cases where the `ping()`, `pong()`, or `send()` methods are called + * when the `readyState` attribute is `CLOSING` or `CLOSED`. + * + * @param {WebSocket} websocket The WebSocket instance + * @param {*} data The data to send + * @param {Function} cb Callback + * @private + */ +function sendAfterClose(websocket, data, cb) { + if (data) { + const length = toBuffer(data).length; + + // + // The `_bufferedAmount` property is used only when the peer is a client and + // the opening handshake fails. Under these circumstances, in fact, the + // `setSocket()` method is not called, so the `_socket` and `_sender` + // properties are set to `null`. + // + if (websocket._socket) websocket._sender._bufferedBytes += length; + else websocket._bufferedAmount += length; + } + + if (cb) { + const err = new Error( + `WebSocket is not open: readyState ${websocket.readyState} ` + + `(${readyStates[websocket.readyState]})` + ); + cb(err); + } +} + +/** + * The listener of the `Receiver` `'conclude'` event. + * + * @param {Number} code The status code + * @param {String} reason The reason for closing + * @private + */ +function receiverOnConclude(code, reason) { + const websocket = this[kWebSocket]; + + websocket._socket.removeListener('data', socketOnData); + websocket._socket.resume(); + + websocket._closeFrameReceived = true; + websocket._closeMessage = reason; + websocket._closeCode = code; + + if (code === 1005) websocket.close(); + else websocket.close(code, reason); +} + +/** + * The listener of the `Receiver` `'drain'` event. + * + * @private + */ +function receiverOnDrain() { + this[kWebSocket]._socket.resume(); +} + +/** + * The listener of the `Receiver` `'error'` event. + * + * @param {(RangeError|Error)} err The emitted error + * @private + */ +function receiverOnError(err) { + const websocket = this[kWebSocket]; + + websocket._socket.removeListener('data', socketOnData); + + websocket.readyState = WebSocket.CLOSING; + websocket._closeCode = err[kStatusCode]; + websocket.emit('error', err); + websocket._socket.destroy(); +} + +/** + * The listener of the `Receiver` `'finish'` event. + * + * @private + */ +function receiverOnFinish() { + this[kWebSocket].emitClose(); +} + +/** + * The listener of the `Receiver` `'message'` event. + * + * @param {(String|Buffer|ArrayBuffer|Buffer[])} data The message + * @private + */ +function receiverOnMessage(data) { + this[kWebSocket].emit('message', data); +} + +/** + * The listener of the `Receiver` `'ping'` event. + * + * @param {Buffer} data The data included in the ping frame + * @private + */ +function receiverOnPing(data) { + const websocket = this[kWebSocket]; + + websocket.pong(data, !websocket._isServer, NOOP); + websocket.emit('ping', data); +} + +/** + * The listener of the `Receiver` `'pong'` event. + * + * @param {Buffer} data The data included in the pong frame + * @private + */ +function receiverOnPong(data) { + this[kWebSocket].emit('pong', data); +} + +/** + * The listener of the `net.Socket` `'close'` event. + * + * @private + */ +function socketOnClose() { + const websocket = this[kWebSocket]; + + this.removeListener('close', socketOnClose); + this.removeListener('end', socketOnEnd); + + websocket.readyState = WebSocket.CLOSING; + + // + // The close frame might not have been received or the `'end'` event emitted, + // for example, if the socket was destroyed due to an error. Ensure that the + // `receiver` stream is closed after writing any remaining buffered data to + // it. If the readable side of the socket is in flowing mode then there is no + // buffered data as everything has been already written and `readable.read()` + // will return `null`. If instead, the socket is paused, any possible buffered + // data will be read as a single chunk and emitted synchronously in a single + // `'data'` event. + // + websocket._socket.read(); + websocket._receiver.end(); + + this.removeListener('data', socketOnData); + this[kWebSocket] = undefined; + + clearTimeout(websocket._closeTimer); + + if ( + websocket._receiver._writableState.finished || + websocket._receiver._writableState.errorEmitted + ) { + websocket.emitClose(); + } else { + websocket._receiver.on('error', receiverOnFinish); + websocket._receiver.on('finish', receiverOnFinish); + } +} + +/** + * The listener of the `net.Socket` `'data'` event. + * + * @param {Buffer} chunk A chunk of data + * @private + */ +function socketOnData(chunk) { + if (!this[kWebSocket]._receiver.write(chunk)) { + this.pause(); + } +} + +/** + * The listener of the `net.Socket` `'end'` event. + * + * @private + */ +function socketOnEnd() { + const websocket = this[kWebSocket]; + + websocket.readyState = WebSocket.CLOSING; + websocket._receiver.end(); + this.end(); +} + +/** + * The listener of the `net.Socket` `'error'` event. + * + * @private + */ +function socketOnError() { + const websocket = this[kWebSocket]; + + this.removeListener('error', socketOnError); + this.on('error', NOOP); + + if (websocket) { + websocket.readyState = WebSocket.CLOSING; + this.destroy(); + } +} diff --git a/TaskServer/node_modules/ws/package.json b/TaskServer/node_modules/ws/package.json new file mode 100644 index 000000000..a6a75bdf9 --- /dev/null +++ b/TaskServer/node_modules/ws/package.json @@ -0,0 +1,136 @@ +{ + "_args": [ + [ + "ws@^7.1.2", + "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer" + ] + ], + "_from": "ws@>=7.1.2-0 <8.0.0-0", + "_hasShrinkwrap": false, + "_id": "ws@7.2.3", + "_inCache": true, + "_location": "/ws", + "_nodeVersion": "13.10.1", + "_npmOperationalInternal": { + "host": "s3://npm-registry-packages", + "tmp": "tmp/ws_7.2.3_1583774852485_0.5683086237203219" + }, + "_npmUser": { + "email": "luigipinca@gmail.com", + "name": "lpinca" + }, + "_npmVersion": "6.13.7", + "_phantomChildren": {}, + "_requested": { + "name": "ws", + "raw": "ws@^7.1.2", + "rawSpec": "^7.1.2", + "scope": null, + "spec": ">=7.1.2-0 <8.0.0-0", + "type": "range" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", + "_shasum": "a5411e1fb04d5ed0efee76d26d5c46d830c39b46", + "_shrinkwrap": null, + "_spec": "ws@^7.1.2", + "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer", + "author": { + "email": "einaros@gmail.com", + "name": "Einar Otto Stangvik", + "url": "http://2x.io" + }, + "browser": "browser.js", + "bugs": { + "url": "https://github.com/websockets/ws/issues" + }, + "dependencies": {}, + "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js", + "devDependencies": { + "benchmark": "^2.1.4", + "bufferutil": "^4.0.1", + "coveralls": "^3.0.3", + "eslint": "^6.0.0", + "eslint-config-prettier": "^6.0.0", + "eslint-plugin-prettier": "^3.0.1", + "mocha": "^7.0.0", + "nyc": "^15.0.0", + "prettier": "^1.17.0", + "utf-8-validate": "^5.0.2" + }, + "directories": {}, + "dist": { + "fileCount": 17, + "integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==", + "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeZnyFCRA9TVsSAnZWagAAUvwP/jAz5ASUvvHJjDMOS+r/\npDkuV2MoMwz6ccV+qfbVRWUKq9DqnK7bZBApyNlzV2I+APDqLOVU+2BazNKh\nqoTcVHYcBYe5oBIYUvEeSK2qyBCNJUcz2f79lVxWagdcax5nl5tOcW3B8v4X\n9T2hSvSuDNz8vg0uhCnLboZ+F4SPXd3lHwwfcZFkNSjTcRog4W4QNQTEaPbi\noqPawUw/NXDJMFILS2m/rerFnEyrDl4VpoAS9GyitCE31g22N03bCbsmaUMo\nHmFmefATEhmtIExXMDW9JGLL9FtTwVEIAJEfAWqjLt3JeAuWHvYKKd7rU/y1\nwPUQJxwGM1HDYaxbDLXRBVYkOja3YHB5txB8d2lHLt98c5DQ/lZCz1XQIRao\nPv48dpOX2Qg69IpMzSHktoRUJpt+0KkLWUhb7XGVY79kCgqt6ZqYxBs7coae\nOeReUBaKc+yuM3k45sHxyqiKCsw/qejgzScPnmU/BaC32vEdjqpysRNDtfZj\nNmizo+cLoiO8stLVCHGBwpIxegM8aGj3/C8emNEsSFi4rXT6LGHaWvNfv3FR\nVY2/4QZFL/ddUQ3yAOKF4znsHBY2qfbpPJVnW7IyxZ2h39HX3PpITCcYDPzu\nj4LV/wXFESBSre9RANqfPfkJC+A3k0V8eAB0bYQJKImeUAiqkOkYMyrX+2Ea\nHUeL\r\n=aUaH\r\n-----END PGP SIGNATURE-----\r\n", + "shasum": "a5411e1fb04d5ed0efee76d26d5c46d830c39b46", + "tarball": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", + "unpackedSize": 109814 + }, + "engines": { + "node": ">=8.3.0" + }, + "gitHead": "5fcdc42ef76d2d0ab920aa37631468e6f1066bcd", + "greenkeeper": { + "commitMessages": { + "dependencyUpdate": "[pkg] Update ${dependency} to version ${version}", + "devDependencyUpdate": "[pkg] Update ${dependency} to version ${version}" + } + }, + "homepage": "https://github.com/websockets/ws", + "installable": true, + "keywords": [ + "HyBi", + "Push", + "RFC-6455", + "WebSocket", + "WebSockets", + "real-time" + ], + "license": "MIT", + "main": "index.js", + "maintainers": [ + { + "email": "npm@3rd-Eden.com", + "name": "3rdeden" + }, + { + "email": "einaros@gmail.com", + "name": "einaros" + }, + { + "email": "luigipinca@gmail.com", + "name": "lpinca" + }, + { + "email": "npm@3rd-Eden.com", + "name": "v1" + } + ], + "name": "ws", + "optionalDependencies": {}, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + }, + "repository": { + "type": "git", + "url": "git+https://github.com/websockets/ws.git" + }, + "scripts": { + "integration": "npm run lint && mocha --throw-deprecation test/*.integration.js", + "lint": "eslint --ignore-path .gitignore . && prettier --check --ignore-path .gitignore \"**/*.{json,md,yaml,yml}\"", + "test": "npm run lint && nyc --reporter=html --reporter=text mocha --throw-deprecation test/*.test.js" + }, + "version": "7.2.3" +} diff --git a/TaskServer/package-lock.json b/TaskServer/package-lock.json index bdb728c2e..9da031d46 100644 --- a/TaskServer/package-lock.json +++ b/TaskServer/package-lock.json @@ -4,15 +4,10 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@types/node": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.0.tgz", - "integrity": "sha512-GnZbirvmqZUzMgkFn70c74OQpTTUcCzlhQliTzYjQMqg+hVKcDnxdL19Ne3UdYzdMA/+W3eb646FWn/ZaT1NfQ==" - }, "ccxt": { - "version": "1.22.39", - "resolved": "https://registry.npmjs.org/ccxt/-/ccxt-1.22.39.tgz", - "integrity": "sha512-Vq4BzYS/FwRudPKQ6BQGU3SVntYv7EAQGT+2guf+e7qm45CJMhdoVwR1z89kl42fbK39XMnl8sUnRCwsKPs38A==" + "version": "1.25.80", + "resolved": "https://registry.npmjs.org/ccxt/-/ccxt-1.25.80.tgz", + "integrity": "sha512-AUWagxMa8PMexRabbktWezlmVacj6L2Ep4844ebIXUOyME2Ommg7O/9/pq0F2Ne1IHcJnNJzHrMYQvkh2gBtlw==" }, "debug": { "version": "4.1.1", @@ -27,33 +22,10 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" }, - "easy-stack": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.0.tgz", - "integrity": "sha1-EskbMIWjfwuqM26UhurEv5Tj54g=" - }, - "event-pubsub": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz", - "integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==" - }, - "js-message": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.5.tgz", - "integrity": "sha1-IwDSSxrwjondCVvBpMnJz8uJLRU=" - }, - "js-queue": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.0.tgz", - "integrity": "sha1-NiITz4YPRo8BJfxslqvBdCUx+Ug=", - "requires": { - "easy-stack": "1.0.0" - } - }, "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "module-alias": { "version": "2.2.2", @@ -70,29 +42,18 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" }, - "node-ipc": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.1.1.tgz", - "integrity": "sha512-FAyICv0sIRJxVp3GW5fzgaf9jwwRQxAKDJlmNFUL5hOy+W4X/I5AypyHoq0DXXbo9o/gt79gj++4cMr4jVWE/w==", - "requires": { - "event-pubsub": "4.3.0", - "js-message": "1.0.5", - "js-queue": "2.0.0" - } - }, "sandwich-stream": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/sandwich-stream/-/sandwich-stream-2.0.2.tgz", "integrity": "sha512-jLYV0DORrzY3xaz/S9ydJL6Iz7essZeAfnAavsJ+zsJGZ1MOnsS52yRjU3uF3pJa/lla7+wisp//fxOwOH8SKQ==" }, "telegraf": { - "version": "3.36.0", - "resolved": "https://registry.npmjs.org/telegraf/-/telegraf-3.36.0.tgz", - "integrity": "sha512-9o6AJKRiTm5vMWYI6WpTfBHzu4FMpWBNKxvnMxRds/cbMY9RnsVVjdi8i4bFFlfd+xbi73EbrnI3dybayryICA==", + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/telegraf/-/telegraf-3.37.0.tgz", + "integrity": "sha512-V3448qwfOolBqkIc87yxjW4zMvR2P6AIF24pPTlX9WhZPwA1TF/x3nQhnWPRLtGh2SJuvDcr83iTkXPXT7Opnw==", "requires": { - "@types/node": "13.7.0", "debug": "4.1.1", - "minimist": "1.2.0", + "minimist": "1.2.5", "module-alias": "2.2.2", "node-fetch": "2.6.0", "sandwich-stream": "2.0.2", @@ -103,6 +64,11 @@ "version": "3.6.1", "resolved": "https://registry.npmjs.org/telegram-typings/-/telegram-typings-3.6.1.tgz", "integrity": "sha512-njVv1EAhIZnmQVLocZEADYUyqA1WIXuVcDYlsp+mXua/XB0pxx+PKtMSPeZ/EE4wPWTw9h/hA9ASTT6yQelkiw==" + }, + "ws": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", + "integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==" } } } diff --git a/TaskServer/package.json b/TaskServer/package.json index a81037332..33f6c67e8 100644 --- a/TaskServer/package.json +++ b/TaskServer/package.json @@ -13,9 +13,9 @@ "test": "echo \"Error: no test specified\" && exit 1" }, "dependencies": { - "ccxt": "^1.22.39", + "ccxt": "^1.25.80", "dotenv": "^8.2.0", - "node-ipc": "^9.1.1", - "telegraf": "^3.36.0" + "telegraf": "^3.37.0", + "ws": "^7.1.2" } } diff --git a/TaskServer/server.js b/TaskServer/server.js index 566a26f89..4b813c954 100644 --- a/TaskServer/server.js +++ b/TaskServer/server.js @@ -40,13 +40,15 @@ process.on('unhandledRejection', (reason, p) => { }) process.on('exit', function (code) { - - /* We send an event signaling that the Task is being terminated. */ - let key = global.TASK_NODE.name + '-' + global.TASK_NODE.type + '-' + global.TASK_NODE.id - global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Stopped') // Meaning Task Stopped - global.SYSTEM_EVENT_HANDLER.finalize() - global.SYSTEM_EVENT_HANDLER = undefined + if (global.TASK_NODE !== undefined) { + /* We send an event signaling that the Task is being terminated. */ + let key = global.TASK_NODE.name + '-' + global.TASK_NODE.type + '-' + global.TASK_NODE.id + + global.EVENT_SERVER_CLIENT.raiseEvent(key, 'Stopped') // Meaning Task Stopped + global.EVENT_SERVER_CLIENT.finalize() + global.EVENT_SERVER_CLIENT = undefined + } //console.log('[INFO] Task Server -> server -> process.on.exit -> About to exit -> code = ' + code) }) @@ -77,7 +79,7 @@ global.EXIT_NODE_PROCESS = function exitProcess() { let process = global.TASK_NODE.bot.processes[i] key = process.name + '-' + process.type + '-' + process.id - global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Stopped') // Meaning Process Stopped + global.EVENT_SERVER_CLIENT.raiseEvent(key, 'Stopped') // Meaning Process Stopped } //console.log("[INFO] Task Server -> " + global.TASK_NODE.name + " -> EXIT_NODE_PROCESS -> Task Server will stop in 10 seconds."); @@ -108,10 +110,10 @@ let taskId = process.argv[2] // reading what comes as an argument of the nodejs /* Setting up the global Event Handler */ -const EVENT_HANDLER_MODULE = require('./SystemEventHandler.js'); -const IPC = require('node-ipc'); -global.SYSTEM_EVENT_HANDLER = EVENT_HANDLER_MODULE.newSystemEventHandler(IPC) -global.SYSTEM_EVENT_HANDLER.initialize('Task Server', preLoader) +let EVENT_SERVER_CLIENT = require('./EventServerClient.js'); + +global.EVENT_SERVER_CLIENT = EVENT_SERVER_CLIENT.newEventsServerClient() +global.EVENT_SERVER_CLIENT.initialize(preLoader) global.STOP_TASK_GRACEFULLY = false; function preLoader() { @@ -119,8 +121,8 @@ function preLoader() { /* The Task Manager sent the info via a process argument. In this case we listen to an event with the Task Info that should be emitted at the UI */ try { //console.log('[INFO] Task Server -> server -> preLoader -> Listening to starting event -> key = ' + 'Task Server - ' + taskId) - global.SYSTEM_EVENT_HANDLER.listenToEvent('Task Server - ' + taskId, 'Run Task', undefined, undefined, undefined, eventReceived) - global.SYSTEM_EVENT_HANDLER.raiseEvent('Task Manager - ' + taskId, 'Nodejs Process Ready for Task') + global.EVENT_SERVER_CLIENT.listenToEvent('Task Server - ' + taskId, 'Run Task', undefined, undefined, undefined, eventReceived) + global.EVENT_SERVER_CLIENT.raiseEvent('Task Manager - ' + taskId, 'Nodejs Process Ready for Task') function eventReceived(message) { global.TASK_NODE = message global.TASK_NODE = JSON.parse(message.event.definition) @@ -134,7 +136,7 @@ function preLoader() { else { /* This process was started not by the Task Manager, but independently (most likely for debugging purposes). In this case we listen to an event with the Task Info that should be emitted at the UI */ try { //console.log('[INFO] Task Server -> server -> preLoader -> Waiting for event to start debugging...') - global.SYSTEM_EVENT_HANDLER.listenToEvent('Task Server', 'Debug Task Started', undefined, undefined, undefined, startDebugging) + global.EVENT_SERVER_CLIENT.listenToEvent('Task Server', 'Debug Task Started', undefined, undefined, undefined, startDebugging) function startDebugging(message) { global.TASK_NODE = message global.TASK_NODE = JSON.parse(message.event.definition) @@ -153,8 +155,8 @@ function bootLoader() { let key = global.TASK_NODE.name + '-' + global.TASK_NODE.type + '-' + global.TASK_NODE.id - global.SYSTEM_EVENT_HANDLER.createEventHandler(key) - global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Running') // Meaning Task Running + global.EVENT_SERVER_CLIENT.createEventHandler(key) + global.EVENT_SERVER_CLIENT.raiseEvent(key, 'Running') // Meaning Task Running global.HEARTBEAT_INTERVAL_HANDLER = setInterval(taskHearBeat, 1000) function taskHearBeat() { @@ -163,7 +165,7 @@ function bootLoader() { let event = { seconds: (new Date()).getSeconds() } - global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Heartbeat', event) + global.EVENT_SERVER_CLIENT.raiseEvent(key, 'Heartbeat', event) } for (let processIndex = 0; processIndex < global.TASK_NODE.bot.processes.length; processIndex++) { diff --git a/WebSocketsServer/node_modules/async-limiter/index.js b/WebSocketsServer/node_modules/async-limiter/index.js deleted file mode 100644 index c9bd2f977..000000000 --- a/WebSocketsServer/node_modules/async-limiter/index.js +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; - -function Queue(options) { - if (!(this instanceof Queue)) { - return new Queue(options); - } - - options = options || {}; - this.concurrency = options.concurrency || Infinity; - this.pending = 0; - this.jobs = []; - this.cbs = []; - this._done = done.bind(this); -} - -var arrayAddMethods = [ - 'push', - 'unshift', - 'splice' -]; - -arrayAddMethods.forEach(function(method) { - Queue.prototype[method] = function() { - var methodResult = Array.prototype[method].apply(this.jobs, arguments); - this._run(); - return methodResult; - }; -}); - -Object.defineProperty(Queue.prototype, 'length', { - get: function() { - return this.pending + this.jobs.length; - } -}); - -Queue.prototype._run = function() { - if (this.pending === this.concurrency) { - return; - } - if (this.jobs.length) { - var job = this.jobs.shift(); - this.pending++; - job(this._done); - this._run(); - } - - if (this.pending === 0) { - while (this.cbs.length !== 0) { - var cb = this.cbs.pop(); - process.nextTick(cb); - } - } -}; - -Queue.prototype.onDone = function(cb) { - if (typeof cb === 'function') { - this.cbs.push(cb); - this._run(); - } -}; - -function done() { - this.pending--; - this._run(); -} - -module.exports = Queue; diff --git a/WebSocketsServer/node_modules/async-limiter/package.json b/WebSocketsServer/node_modules/async-limiter/package.json deleted file mode 100644 index 6228c970f..000000000 --- a/WebSocketsServer/node_modules/async-limiter/package.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "_from": "async-limiter@^1.0.0", - "_id": "async-limiter@1.0.1", - "_inBundle": false, - "_integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "_location": "/async-limiter", - "_phantomChildren": {}, - "_requested": { - "type": "range", - "registry": true, - "raw": "async-limiter@^1.0.0", - "name": "async-limiter", - "escapedName": "async-limiter", - "rawSpec": "^1.0.0", - "saveSpec": null, - "fetchSpec": "^1.0.0" - }, - "_requiredBy": [ - "/ws" - ], - "_resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "_shasum": "dd379e94f0db8310b08291f9d64c3209766617fd", - "_spec": "async-limiter@^1.0.0", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\WebSockets-Server\\node_modules\\ws", - "author": { - "name": "Samuel Reed" - }, - "bugs": { - "url": "https://github.com/strml/async-limiter/issues" - }, - "bundleDependencies": false, - "dependencies": {}, - "deprecated": false, - "description": "asynchronous function queue with adjustable concurrency", - "devDependencies": { - "coveralls": "^3.0.3", - "eslint": "^5.16.0", - "eslint-plugin-mocha": "^5.3.0", - "intelli-espower-loader": "^1.0.1", - "mocha": "^6.1.4", - "nyc": "^14.1.1", - "power-assert": "^1.6.1" - }, - "homepage": "https://github.com/strml/async-limiter#readme", - "keywords": [ - "throttle", - "async", - "limiter", - "asynchronous", - "job", - "task", - "concurrency", - "concurrent" - ], - "license": "MIT", - "name": "async-limiter", - "repository": { - "type": "git", - "url": "git+https://github.com/strml/async-limiter.git" - }, - "scripts": { - "coverage": "nyc npm test && nyc report --reporter=text-lcov | coveralls", - "example": "node example", - "lint": "eslint .", - "test": "mocha --require intelli-espower-loader test/", - "travis": "npm run lint && npm run test" - }, - "version": "1.0.1" -} diff --git a/WebSocketsServer/node_modules/dotenv/config.js b/WebSocketsServer/node_modules/dotenv/config.js deleted file mode 100644 index c7e6447fc..000000000 --- a/WebSocketsServer/node_modules/dotenv/config.js +++ /dev/null @@ -1,11 +0,0 @@ -/* @flow */ - -(function () { - require('./lib/main').config( - Object.assign( - {}, - require('./lib/env-options'), - require('./lib/cli-options')(process.argv) - ) - ) -})() diff --git a/WebSocketsServer/node_modules/dotenv/lib/cli-options.js b/WebSocketsServer/node_modules/dotenv/lib/cli-options.js deleted file mode 100644 index ad69fabd9..000000000 --- a/WebSocketsServer/node_modules/dotenv/lib/cli-options.js +++ /dev/null @@ -1,13 +0,0 @@ -/* @flow */ - -const re = /^dotenv_config_(encoding|path|debug)=(.+)$/ - -module.exports = function optionMatcher (args /*: Array */) { - return args.reduce(function (acc, cur) { - const matches = cur.match(re) - if (matches) { - acc[matches[1]] = matches[2] - } - return acc - }, {}) -} diff --git a/WebSocketsServer/node_modules/dotenv/lib/env-options.js b/WebSocketsServer/node_modules/dotenv/lib/env-options.js deleted file mode 100644 index b4c4a6068..000000000 --- a/WebSocketsServer/node_modules/dotenv/lib/env-options.js +++ /dev/null @@ -1,18 +0,0 @@ -/* @flow */ - -// ../config.js accepts options via environment variables -const options = {} - -if (process.env.DOTENV_CONFIG_ENCODING != null) { - options.encoding = process.env.DOTENV_CONFIG_ENCODING -} - -if (process.env.DOTENV_CONFIG_PATH != null) { - options.path = process.env.DOTENV_CONFIG_PATH -} - -if (process.env.DOTENV_CONFIG_DEBUG != null) { - options.debug = process.env.DOTENV_CONFIG_DEBUG -} - -module.exports = options diff --git a/WebSocketsServer/node_modules/dotenv/lib/main.js b/WebSocketsServer/node_modules/dotenv/lib/main.js deleted file mode 100644 index e6c591c6b..000000000 --- a/WebSocketsServer/node_modules/dotenv/lib/main.js +++ /dev/null @@ -1,113 +0,0 @@ -/* @flow */ -/*:: - -type DotenvParseOptions = { - debug?: boolean -} - -// keys and values from src -type DotenvParseOutput = { [string]: string } - -type DotenvConfigOptions = { - path?: string, // path to .env file - encoding?: string, // encoding of .env file - debug?: string // turn on logging for debugging purposes -} - -type DotenvConfigOutput = { - parsed?: DotenvParseOutput, - error?: Error -} - -*/ - -const fs = require('fs') -const path = require('path') - -function log (message /*: string */) { - console.log(`[dotenv][DEBUG] ${message}`) -} - -const NEWLINE = '\n' -const RE_INI_KEY_VAL = /^\s*([\w.-]+)\s*=\s*(.*)?\s*$/ -const RE_NEWLINES = /\\n/g -const NEWLINES_MATCH = /\n|\r|\r\n/ - -// Parses src into an Object -function parse (src /*: string | Buffer */, options /*: ?DotenvParseOptions */) /*: DotenvParseOutput */ { - const debug = Boolean(options && options.debug) - const obj = {} - - // convert Buffers before splitting into lines and processing - src.toString().split(NEWLINES_MATCH).forEach(function (line, idx) { - // matching "KEY' and 'VAL' in 'KEY=VAL' - const keyValueArr = line.match(RE_INI_KEY_VAL) - // matched? - if (keyValueArr != null) { - const key = keyValueArr[1] - // default undefined or missing values to empty string - let val = (keyValueArr[2] || '') - const end = val.length - 1 - const isDoubleQuoted = val[0] === '"' && val[end] === '"' - const isSingleQuoted = val[0] === "'" && val[end] === "'" - - // if single or double quoted, remove quotes - if (isSingleQuoted || isDoubleQuoted) { - val = val.substring(1, end) - - // if double quoted, expand newlines - if (isDoubleQuoted) { - val = val.replace(RE_NEWLINES, NEWLINE) - } - } else { - // remove surrounding whitespace - val = val.trim() - } - - obj[key] = val - } else if (debug) { - log(`did not match key and value when parsing line ${idx + 1}: ${line}`) - } - }) - - return obj -} - -// Populates process.env from .env file -function config (options /*: ?DotenvConfigOptions */) /*: DotenvConfigOutput */ { - let dotenvPath = path.resolve(process.cwd(), '.env') - let encoding /*: string */ = 'utf8' - let debug = false - - if (options) { - if (options.path != null) { - dotenvPath = options.path - } - if (options.encoding != null) { - encoding = options.encoding - } - if (options.debug != null) { - debug = true - } - } - - try { - // specifying an encoding returns a string instead of a buffer - const parsed = parse(fs.readFileSync(dotenvPath, { encoding }), { debug }) - - Object.keys(parsed).forEach(function (key) { - if (!Object.prototype.hasOwnProperty.call(process.env, key)) { - process.env[key] = parsed[key] - } else if (debug) { - log(`"${key}" is already defined in \`process.env\` and will not be overwritten`) - } - }) - - return { parsed } - } catch (e) { - return { error: e } - } -} - -module.exports.config = config -module.exports.parse = parse diff --git a/WebSocketsServer/node_modules/easy-stack/es5.js b/WebSocketsServer/node_modules/easy-stack/es5.js deleted file mode 100644 index a756a7bbf..000000000 --- a/WebSocketsServer/node_modules/easy-stack/es5.js +++ /dev/null @@ -1,74 +0,0 @@ -function Stack(){ - Object.defineProperties( - this, - { - add:{ - enumerable:true, - writable:false, - value:addToStack - }, - next:{ - enumerable:true, - writable:false, - value:run - }, - clear:{ - enumerable:true, - writable:false, - value:clearStack - }, - contents:{ - enumerable:false, - get:getStack, - set:setStack - }, - autoRun:{ - enumerable:true, - writable:true, - value:true - }, - stop:{ - enumerable:true, - writable:true, - value:false - } - } - ); - - var stack=[]; - var running=false; - var stop=false; - - function clearStack(){ - stack=[]; - return stack; - } - - function getStack(){ - return stack; - } - - function setStack(val){ - stack=val; - return stack; - } - - function addToStack(){ - for(var i in arguments){ - stack.unshift(arguments[i]); - } - if(!running && !this.stop && this.autoRun){ - this.next(); - } - } - - function run(){ - running=true; - if(stack.length<1 || this.stop){ - running=false; - return; - } - - stack.shift().bind(this)(); - } -} diff --git a/WebSocketsServer/node_modules/easy-stack/example/basic.js b/WebSocketsServer/node_modules/easy-stack/example/basic.js deleted file mode 100644 index f0d7fbb11..000000000 --- a/WebSocketsServer/node_modules/easy-stack/example/basic.js +++ /dev/null @@ -1,18 +0,0 @@ -var Stack=require('../stack'); -//create a new Stack instance -var stack=new Stack; -stack.autoRun=false; - -for(var i=0; i<50; i++){ - //add a bunch of stuff to the stack - stack.add(makeRequest.bind(stack,i)); -} - -stack.next(); - -function makeRequest(index){ - //do stuff - console.log(`making LIFO request ${index}`); - - this.next(); -} diff --git a/WebSocketsServer/node_modules/easy-stack/package.json b/WebSocketsServer/node_modules/easy-stack/package.json deleted file mode 100644 index 3b7e5ab52..000000000 --- a/WebSocketsServer/node_modules/easy-stack/package.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "_from": "easy-stack@^1.0.0", - "_id": "easy-stack@1.0.0", - "_inBundle": false, - "_integrity": "sha1-EskbMIWjfwuqM26UhurEv5Tj54g=", - "_location": "/easy-stack", - "_phantomChildren": {}, - "_requested": { - "type": "range", - "registry": true, - "raw": "easy-stack@^1.0.0", - "name": "easy-stack", - "escapedName": "easy-stack", - "rawSpec": "^1.0.0", - "saveSpec": null, - "fetchSpec": "^1.0.0" - }, - "_requiredBy": [ - "/js-queue" - ], - "_resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.0.tgz", - "_shasum": "12c91b3085a37f0baa336e9486eac4bf94e3e788", - "_spec": "easy-stack@^1.0.0", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\WebSockets-Server\\node_modules\\js-queue", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/easy-stack/issues" - }, - "bundleDependencies": false, - "deprecated": false, - "description": "Simple JS stack with auto run for node and browsers", - "engines": { - "node": ">=6.0.0" - }, - "homepage": "https://github.com/RIAEvangelist/easy-stack#readme", - "keywords": [ - "stack", - "node", - "js", - "auto", - "run", - "execute", - "browser", - "react" - ], - "license": "DBAD", - "main": "stack.js", - "name": "easy-stack", - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/easy-stack.git" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "1.0.0" -} diff --git a/WebSocketsServer/node_modules/easy-stack/stack.js b/WebSocketsServer/node_modules/easy-stack/stack.js deleted file mode 100644 index bfadd1dee..000000000 --- a/WebSocketsServer/node_modules/easy-stack/stack.js +++ /dev/null @@ -1,39 +0,0 @@ -class Stack{ - constructor(){ - this.stack=[]; - this.autoRun=true; - this.running=false; - this.stop=false; - } - - clear(){ - this.stack=[]; - return this.stack; - } - - contents(val){ - if(val){ - this.stack=val; - } - return this.stack; - } - - add(...callbacks){ - this.stack.push(...callbacks); - if(!this.running && !this.stop && this.autoRun){ - this.next(); - } - } - - next(){ - this.running=true; - if(this.stack.length<1 || this.stop){ - this.running=false; - return; - } - - this.stack.pop().bind(this)(); - } -} - -module.exports=Stack; diff --git a/WebSocketsServer/node_modules/event-pubsub/bower.json b/WebSocketsServer/node_modules/event-pubsub/bower.json deleted file mode 100644 index a207b0a5d..000000000 --- a/WebSocketsServer/node_modules/event-pubsub/bower.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "event-pubsub", - "description": "Super light and fast Extensible PubSub events and EventEmitters for Node and the browser with support for ES6 by default, and ES5 versions for older verions of node and older IE/Safari versions. Easy for any developer level. No frills, just high speed pubsub events!", - "main": "event-pubsub.js", - "authors": [ - "Brandon Nozaki Miller" - ], - "license": "DBAD", - "keywords": [ - "event", - "events", - "pubsub", - "node", - "browser" - ], - "homepage": "https://github.com/RIAEvangelist/event-pubsub", - "moduleType": [ - "globals", - "node" - ], - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" - ] -} diff --git a/WebSocketsServer/node_modules/event-pubsub/es5.js b/WebSocketsServer/node_modules/event-pubsub/es5.js deleted file mode 100644 index 7faf8b737..000000000 --- a/WebSocketsServer/node_modules/event-pubsub/es5.js +++ /dev/null @@ -1,143 +0,0 @@ -'use strict'; - -function EventPubSub() { - this._events_={}; - this.publish=this.trigger=this.emit=emit; - this.subscribe=this.on=on; - this.once=once; - this.unSubscribe=this.off=off; - this.emit$=emit$; - - function on(type,handler,once){ - if(!handler){ - throw new ReferenceError('handler not defined.'); - } - - if(!this._events_[type]){ - this._events_[type]=[]; - } - - if(once){ - handler._once_ = once; - } - this._events_[type].push(handler); - return this; - } - - function once(type,handler){ - return this.on(type, handler, true); - } - - function off(type,handler){ - if(!this._events_[type]){ - return this; - } - - if(!handler){ - throw new ReferenceError('handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler'); - } - - if(handler=='*'){ - delete this._events_[type]; - return this; - } - - var handlers=this._events_[type]; - - while(handlers.includes(handler)){ - handlers.splice( - handlers.indexOf(handler), - 1 - ); - } - - if(handlers.length<1){ - delete this._events_[type]; - } - - return this; - } - - function emit(type){ - this.emit$.apply(this, arguments); - if(!this._events_[type]){ - return this; - } - arguments.splice=Array.prototype.splice; - arguments.splice(0,1); - - var handlers=this._events_[type]; - var onceHandled=[]; - - for(var i in handlers){ - var handler=handlers[i]; - handler.apply(this, arguments); - if(handler._once_){ - onceHandled.push(handler); - } - } - - for(var i in onceHandled){ - this.off( - type, - onceHandled[i] - ); - } - - return this; - } - - function emit$(type, args){ - if(!this._events_['*']){ - return this; - } - - var catchAll=this._events_['*']; - - args.shift=Array.prototype.shift; - args.shift(type); - - for(var handler of catchAll){ - handler.apply(this, args); - } - - return this; - } - - return this; -} - -if (!Array.prototype.includes) { - Array.prototype.includes = function(searchElement /*, fromIndex*/) { - 'use strict'; - if (this == null) { - throw new TypeError('Array.prototype.includes called on null or undefined'); - } - - var O = Object(this); - var len = parseInt(O.length, 10) || 0; - if (len === 0) { - return false; - } - var n = parseInt(arguments[1], 10) || 0; - var k; - if (n >= 0) { - k = n; - } else { - k = len + n; - if (k < 0) {k = 0;} - } - var currentElement; - while (k < len) { - currentElement = O[k]; - if (searchElement === currentElement || - (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN - return true; - } - k++; - } - return false; - }; -} - -module.exports=EventPubSub; diff --git a/WebSocketsServer/node_modules/event-pubsub/es6.js b/WebSocketsServer/node_modules/event-pubsub/es6.js deleted file mode 100644 index e9e859f9b..000000000 --- a/WebSocketsServer/node_modules/event-pubsub/es6.js +++ /dev/null @@ -1,99 +0,0 @@ -'use strict'; - -class EventPubSub { - constructor( scope ) { - this._events_ = {}; - this.publish = this.trigger = this.emit; - this.subscribe = this.on; - this.unSubscribe = this.off; - } - - on( type, handler, once ) { - if ( !handler ) { - throw new ReferenceError( 'handler not defined.' ); - } - - if ( !this._events_[ type ] ) { - this._events_[ type ] = []; - } - - if(once){ - handler._once_ = once; - } - - this._events_[ type ].push( handler ); - return this; - } - - once( type, handler ) { - return this.on( type, handler, true ); - } - - off( type, handler ) { - if ( !this._events_[ type ] ) { - return this; - } - - if ( !handler ) { - throw new ReferenceError( 'handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler' ); - } - - if ( handler == '*' ) { - delete this._events_[ type ]; - return this; - } - - const handlers = this._events_[ type ]; - - while ( handlers.includes( handler ) ) { - handlers.splice( - handlers.indexOf( handler ), - 1 - ); - } - - if ( handlers.length < 1 ) { - delete this._events_[ type ]; - } - - return this; - } - - emit( type, ...args ) { - if ( !this._events_[ type ] ) { - return this.emit$( type, ...args ); - } - - const handlers = this._events_[ type ]; - const onceHandled=[]; - - for ( let handler of handlers ) { - handler.apply( this, args ); - if(handler._once_){ - onceHandled.push(handler); - } - } - - for(let handler of onceHandled){ - this.off(type,handler); - } - - return this.emit$( type, ...args ); - } - - emit$( type, ...args ) { - if ( !this._events_[ '*' ] ) { - return this; - } - - const catchAll = this._events_[ '*' ]; - - for ( let handler of catchAll ) { - handler.call( this, type, ...args ); - } - - return this; - } -} - -module.exports = EventPubSub; diff --git a/WebSocketsServer/node_modules/event-pubsub/event-pubsub-browser-es5.js b/WebSocketsServer/node_modules/event-pubsub/event-pubsub-browser-es5.js deleted file mode 100644 index 03f27625e..000000000 --- a/WebSocketsServer/node_modules/event-pubsub/event-pubsub-browser-es5.js +++ /dev/null @@ -1,141 +0,0 @@ -'use strict'; - -window.EventPubSub=function EventPubSub() { - this._events_={}; - this.publish=this.trigger=this.emit=emit; - this.subscribe=this.on=on; - this.once=once; - this.unSubscribe=this.off=off; - this.emit$=emit$; - - function on(type,handler,once){ - if(!handler){ - throw new ReferenceError('handler not defined.'); - } - - if(!this._events_[type]){ - this._events_[type]=[]; - } - - if(once){ - handler._once_ = once; - } - this._events_[type].push(handler); - return this; - } - - function once(type,handler){ - return this.on(type, handler, true); - } - - function off(type,handler){ - if(!this._events_[type]){ - return this; - } - - if(!handler){ - throw new ReferenceError('handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler'); - } - - if(handler=='*'){ - delete this._events_[type]; - return this; - } - - var handlers=this._events_[type]; - - while(handlers.includes(handler)){ - handlers.splice( - handlers.indexOf(handler), - 1 - ); - } - - if(handlers.length<1){ - delete this._events_[type]; - } - - return this; - } - - function emit(type){ - this.emit$.apply(this, arguments); - if(!this._events_[type]){ - return this; - } - arguments.splice=Array.prototype.splice; - arguments.splice(0,1); - - var handlers=this._events_[type]; - var onceHandled=[]; - - for(var i in handlers){ - var handler=handlers[i]; - handler.apply(this, arguments); - if(handler._once_){ - onceHandled.push(handler); - } - } - - for(var i in onceHandled){ - this.off( - type, - onceHandled[i] - ); - } - - return this; - } - - function emit$(type, args){ - if(!this._events_['*']){ - return this; - } - - var catchAll=this._events_['*']; - - args.shift=Array.prototype.shift; - args.shift(type); - - for(var handler of catchAll){ - handler.apply(this, args); - } - - return this; - } - - return this; -} - -if (!Array.prototype.includes) { - Array.prototype.includes = function(searchElement /*, fromIndex*/) { - 'use strict'; - if (this == null) { - throw new TypeError('Array.prototype.includes called on null or undefined'); - } - - var O = Object(this); - var len = parseInt(O.length, 10) || 0; - if (len === 0) { - return false; - } - var n = parseInt(arguments[1], 10) || 0; - var k; - if (n >= 0) { - k = n; - } else { - k = len + n; - if (k < 0) {k = 0;} - } - var currentElement; - while (k < len) { - currentElement = O[k]; - if (searchElement === currentElement || - (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN - return true; - } - k++; - } - return false; - }; -} diff --git a/WebSocketsServer/node_modules/event-pubsub/event-pubsub-browser.js b/WebSocketsServer/node_modules/event-pubsub/event-pubsub-browser.js deleted file mode 100644 index d0bcd7b56..000000000 --- a/WebSocketsServer/node_modules/event-pubsub/event-pubsub-browser.js +++ /dev/null @@ -1,130 +0,0 @@ -'use strict'; - -window.EventPubSub=class EventPubSub { - constructor( scope ) { - this._events_ = {}; - this.publish = this.trigger = this.emit; - this.subscribe = this.on; - this.unSubscribe = this.off; - } - - on( type, handler, once ) { - if ( !handler ) { - throw new ReferenceError( 'handler not defined.' ); - } - - if ( !this._events_[ type ] ) { - this._events_[ type ] = []; - } - - if(once){ - handler._once_ = once; - } - - this._events_[ type ].push( handler ); - return this; - } - - once( type, handler ) { - return this.on( type, handler, true ); - } - - off( type, handler ) { - if ( !this._events_[ type ] ) { - return this; - } - - if ( !handler ) { - throw new ReferenceError( 'handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler' ); - } - - if ( handler == '*' ) { - delete this._events_[ type ]; - return this; - } - - const handlers = this._events_[ type ]; - - while ( handlers.includes( handler ) ) { - handlers.splice( - handlers.indexOf( handler ), - 1 - ); - } - - if ( handlers.length < 1 ) { - delete this._events_[ type ]; - } - - return this; - } - - emit( type, ...args ) { - if ( !this._events_[ type ] ) { - return this.emit$( type, ...args ); - } - - const handlers = this._events_[ type ]; - const onceHandled=[]; - - for ( let handler of handlers ) { - handler.apply( this, args ); - if(handler._once_){ - onceHandled.push(handler); - } - } - - for(let handler of onceHandled){ - this.off(type,handler); - } - - return this.emit$( type, ...args ); - } - - emit$( type, ...args ) { - if ( !this._events_[ '*' ] ) { - return this; - } - - const catchAll = this._events_[ '*' ]; - - for ( let handler of catchAll ) { - handler.call( this, type, ...args ); - } - - return this; - } -} - -if (!Array.prototype.includes) { - Array.prototype.includes = function(searchElement /*, fromIndex*/) { - 'use strict'; - if (this == null) { - throw new TypeError('Array.prototype.includes called on null or undefined'); - } - - var O = Object(this); - var len = parseInt(O.length, 10) || 0; - if (len === 0) { - return false; - } - var n = parseInt(arguments[1], 10) || 0; - var k; - if (n >= 0) { - k = n; - } else { - k = len + n; - if (k < 0) {k = 0;} - } - var currentElement; - while (k < len) { - currentElement = O[k]; - if (searchElement === currentElement || - (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN - return true; - } - k++; - } - return false; - }; -} diff --git a/WebSocketsServer/node_modules/event-pubsub/event-pubsub.js b/WebSocketsServer/node_modules/event-pubsub/event-pubsub.js deleted file mode 100644 index 65bd02419..000000000 --- a/WebSocketsServer/node_modules/event-pubsub/event-pubsub.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -let EventPubSub = require('./es5'); -if(process.version[1]>5){ - EventPubSub = require('./es6'); -} - -module.exports=EventPubSub; diff --git a/WebSocketsServer/node_modules/event-pubsub/package.json b/WebSocketsServer/node_modules/event-pubsub/package.json deleted file mode 100644 index 0ec9ca8b0..000000000 --- a/WebSocketsServer/node_modules/event-pubsub/package.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "_from": "event-pubsub@4.3.0", - "_id": "event-pubsub@4.3.0", - "_inBundle": false, - "_integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==", - "_location": "/event-pubsub", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "event-pubsub@4.3.0", - "name": "event-pubsub", - "escapedName": "event-pubsub", - "rawSpec": "4.3.0", - "saveSpec": null, - "fetchSpec": "4.3.0" - }, - "_requiredBy": [ - "/node-ipc" - ], - "_resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz", - "_shasum": "f68d816bc29f1ec02c539dc58c8dd40ce72cb36e", - "_spec": "event-pubsub@4.3.0", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\WebSockets-Server\\node_modules\\node-ipc", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/event-pubsub/issues" - }, - "bundleDependencies": false, - "deprecated": false, - "description": "Super light and fast Extensible PubSub events and EventEmitters for Node and the browser with support for ES6 by default, and ES5 versions for older verions of node and older IE/Safari versions. Easy for any developer level. No frills, just high speed pubsub events!", - "directories": { - "example": "examples" - }, - "engines": { - "node": ">=4.0.0" - }, - "homepage": "https://github.com/RIAEvangelist/event-pubsub", - "keywords": [ - "event", - "events", - "pubsub", - "node", - "browser" - ], - "license": "Unlicense", - "main": "event-pubsub.js", - "name": "event-pubsub", - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/event-pubsub.git" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "4.3.0" -} diff --git a/WebSocketsServer/node_modules/js-message/Message.js b/WebSocketsServer/node_modules/js-message/Message.js deleted file mode 100644 index 9a4698232..000000000 --- a/WebSocketsServer/node_modules/js-message/Message.js +++ /dev/null @@ -1,71 +0,0 @@ -function Message() { - Object.defineProperties( - this, { - data: { - enumerable: true, - get: getData, - set: setData - }, - type: { - enumerable: true, - get: getType, - set: setType - }, - load:{ - enumarable:true, - writable:false, - value:parse - }, - JSON: { - enumerable: true, - get: getJSON - } - } - ); - - var type = ''; - var data = {}; - - function getType() { - return type; - } - - function getData() { - return data; - } - - function getJSON() { - return JSON.stringify( - { - type: type, - data: data - } - ); - } - - function setType(value) { - type = value; - } - - function setData(value) { - data = value; - } - - function parse(message){ - try{ - var message=JSON.parse(message); - type=message.type; - data=message.data; - }catch(err){ - var badMessage=message; - type='error', - data={ - message:'Invalid JSON response format', - err:err, - response:badMessage - } - } - } -} - -module.exports=Message; diff --git a/WebSocketsServer/node_modules/js-message/js-message-vanilla.js b/WebSocketsServer/node_modules/js-message/js-message-vanilla.js deleted file mode 100644 index 0c49c2b6c..000000000 --- a/WebSocketsServer/node_modules/js-message/js-message-vanilla.js +++ /dev/null @@ -1,75 +0,0 @@ -( - function(){ - function Message() { - Object.defineProperties( - this, { - data: { - enumerable: true, - get: getData, - set: setData - }, - type: { - enumerable: true, - get: getType, - set: setType - }, - load:{ - enumarable:true, - writable:false, - value:parse - }, - JSON: { - enumerable: true, - get: getJSON - } - } - ); - - var type = ''; - var data = {}; - - function getType() { - return type; - } - - function getData() { - return data; - } - - function getJSON() { - return JSON.stringify( - { - type: type, - data: data - } - ); - } - - function setType(value) { - type = value; - } - - function setData(value) { - data = value; - } - - function parse(message){ - try{ - var message=JSON.parse(message); - type=message.type; - data=message.data; - }catch(err){ - var badMessage=message; - type='error', - data={ - message:'Invalid JSON response format', - err:err, - response:badMessage - } - } - } - } - - window.message=Message; - } -)(); diff --git a/WebSocketsServer/node_modules/js-message/package.json b/WebSocketsServer/node_modules/js-message/package.json deleted file mode 100644 index 5ebf51ee3..000000000 --- a/WebSocketsServer/node_modules/js-message/package.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "_from": "js-message@1.0.5", - "_id": "js-message@1.0.5", - "_inBundle": false, - "_integrity": "sha1-IwDSSxrwjondCVvBpMnJz8uJLRU=", - "_location": "/js-message", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "js-message@1.0.5", - "name": "js-message", - "escapedName": "js-message", - "rawSpec": "1.0.5", - "saveSpec": null, - "fetchSpec": "1.0.5" - }, - "_requiredBy": [ - "/node-ipc" - ], - "_resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.5.tgz", - "_shasum": "2300d24b1af08e89dd095bc1a4c9c9cfcb892d15", - "_spec": "js-message@1.0.5", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\WebSockets-Server\\node_modules\\node-ipc", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/js-message/issues" - }, - "bundleDependencies": false, - "dependencies": {}, - "deprecated": false, - "description": "normalized JS Object and JSON message and event protocol for node.js, vanialla js, react.js, components, actions, stores and dispatchers", - "devDependencies": {}, - "engines": { - "node": ">=0.6.0" - }, - "homepage": "https://github.com/RIAEvangelist/js-message#readme", - "keywords": [ - "message", - "normalize", - "events", - "js", - "json", - "protocol", - "ipc", - "node", - "nodejs", - "node.js", - "react", - "react.js", - "reactjs", - "websocket", - "websockets", - "web", - "socket", - "sockets", - "ws", - "flux", - "reflux", - "component", - "components", - "store", - "stores", - "action", - "actions" - ], - "license": "DBAD", - "main": "Message.js", - "name": "js-message", - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/js-message.git" - }, - "scripts": { - "start": "node devServer.js", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "1.0.5" -} diff --git a/WebSocketsServer/node_modules/js-queue/package.json b/WebSocketsServer/node_modules/js-queue/package.json deleted file mode 100644 index 4287eec41..000000000 --- a/WebSocketsServer/node_modules/js-queue/package.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "_from": "js-queue@2.0.0", - "_id": "js-queue@2.0.0", - "_inBundle": false, - "_integrity": "sha1-NiITz4YPRo8BJfxslqvBdCUx+Ug=", - "_location": "/js-queue", - "_phantomChildren": {}, - "_requested": { - "type": "version", - "registry": true, - "raw": "js-queue@2.0.0", - "name": "js-queue", - "escapedName": "js-queue", - "rawSpec": "2.0.0", - "saveSpec": null, - "fetchSpec": "2.0.0" - }, - "_requiredBy": [ - "/node-ipc" - ], - "_resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.0.tgz", - "_shasum": "362213cf860f468f0125fc6c96abc1742531f948", - "_spec": "js-queue@2.0.0", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\WebSockets-Server\\node_modules\\node-ipc", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/js-queue/issues" - }, - "bundleDependencies": false, - "dependencies": { - "easy-stack": "^1.0.0" - }, - "deprecated": false, - "description": "Simple JS queue with auto run for node and browsers", - "engines": { - "node": ">=1.0.0" - }, - "homepage": "https://github.com/RIAEvangelist/js-queue#readme", - "keywords": [ - "queue", - "node", - "js", - "auto", - "run", - "execute", - "browser", - "react" - ], - "license": "DBAD", - "main": "queue.js", - "name": "js-queue", - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/js-queue.git" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "2.0.0" -} diff --git a/WebSocketsServer/node_modules/js-queue/queue-vanilla.js b/WebSocketsServer/node_modules/js-queue/queue-vanilla.js deleted file mode 100644 index 6f15495ae..000000000 --- a/WebSocketsServer/node_modules/js-queue/queue-vanilla.js +++ /dev/null @@ -1,74 +0,0 @@ -function Queue(){ - Object.defineProperties( - this, - { - add:{ - enumerable:true, - writable:false, - value:addToQueue - }, - next:{ - enumerable:true, - writable:false, - value:run - }, - clear:{ - enumerable:true, - writable:false, - value:clearQueue - }, - contents:{ - enumerable:false, - get:getQueue, - set:setQueue - }, - autoRun:{ - enumerable:true, - writable:true, - value:true - }, - stop:{ - enumerable:true, - writable:true, - value:false - } - } - ); - - var queue=[]; - var running=false; - var stop=false; - - function clearQueue(){ - queue=[]; - return queue; - } - - function getQueue(){ - return queue; - } - - function setQueue(val){ - queue=val; - return queue; - } - - function addToQueue(){ - for(var i in arguments){ - queue.push(arguments[i]); - } - if(!running && !this.stop && this.autoRun){ - this.next(); - } - } - - function run(){ - running=true; - if(queue.length<1 || this.stop){ - running=false; - return; - } - - queue.shift().bind(this)(); - } -} diff --git a/WebSocketsServer/node_modules/js-queue/queue.js b/WebSocketsServer/node_modules/js-queue/queue.js deleted file mode 100644 index a8698d7e9..000000000 --- a/WebSocketsServer/node_modules/js-queue/queue.js +++ /dev/null @@ -1,76 +0,0 @@ -function Queue(asStack){ - Object.defineProperties( - this, - { - add:{ - enumerable:true, - writable:false, - value:addToQueue - }, - next:{ - enumerable:true, - writable:false, - value:run - }, - clear:{ - enumerable:true, - writable:false, - value:clearQueue - }, - contents:{ - enumerable:false, - get:getQueue, - set:setQueue - }, - autoRun:{ - enumerable:true, - writable:true, - value:true - }, - stop:{ - enumerable:true, - writable:true, - value:false - } - } - ); - - var queue=[]; - var running=false; - var stop=false; - - function clearQueue(){ - queue=[]; - return queue; - } - - function getQueue(){ - return queue; - } - - function setQueue(val){ - queue=val; - return queue; - } - - function addToQueue(){ - for(var i in arguments){ - queue.push(arguments[i]); - } - if(!running && !this.stop && this.autoRun){ - this.next(); - } - } - - function run(){ - running=true; - if(queue.length<1 || this.stop){ - running=false; - return; - } - - queue.shift().bind(this)(); - } -} - -module.exports=Queue; diff --git a/WebSocketsServer/node_modules/js-queue/stack.js b/WebSocketsServer/node_modules/js-queue/stack.js deleted file mode 100644 index a9c25640e..000000000 --- a/WebSocketsServer/node_modules/js-queue/stack.js +++ /dev/null @@ -1,3 +0,0 @@ -const Stack=require('easy-stack'); - -module.exports = Stack; diff --git a/WebSocketsServer/node_modules/node-ipc/dao/client.js b/WebSocketsServer/node_modules/node-ipc/dao/client.js deleted file mode 100644 index 41ce50411..000000000 --- a/WebSocketsServer/node_modules/node-ipc/dao/client.js +++ /dev/null @@ -1,257 +0,0 @@ -'use strict'; - -const net = require('net'), - tls = require('tls'), - EventParser = require('../entities/EventParser.js'), - Message = require('js-message'), - fs = require('fs'), - Queue = require('js-queue'); - -let Events = require('event-pubsub/es5'); -if(process.version[1]>4){ - Events = require('event-pubsub'); -} - -let eventParser = new EventParser(); - -class Client extends Events{ - constructor(config,log){ - super(); - Object.assign( - this, - { - Client : Client, - config : config, - queue : new Queue, - socket : false, - connect : connect, - emit : emit, - log : log, - retriesRemaining:config.maxRetries||0, - explicitlyDisconnected: false - } - ); - - eventParser=new EventParser(this.config); - } -} - -function emit(type,data){ - this.log('dispatching event to ', this.id, this.path, ' : ', type, ',', data); - - let message=new Message; - message.type=type; - message.data=data; - - if(this.config.rawBuffer){ - message=new Buffer(type,this.config.encoding); - }else{ - message=eventParser.format(message); - } - - if(!this.config.sync){ - this.socket.write(message); - return; - } - - this.queue.add( - syncEmit.bind(this,message) - ); -} - -function syncEmit(message){ - this.log('dispatching event to ', this.id, this.path, ' : ', message); - this.socket.write(message); -} - -function connect(){ - //init client object for scope persistance especially inside of socket events. - let client=this; - - client.log('requested connection to ', client.id, client.path); - if(!this.path){ - client.log('\n\n######\nerror: ', client.id ,' client has not specified socket path it wishes to connect to.'); - return; - } - - const options={}; - - if(!client.port){ - client.log('Connecting client on Unix Socket :', client.path); - - options.path=client.path; - - if (process.platform ==='win32' && !client.path.startsWith('\\\\.\\pipe\\')){ - options.path = options.path.replace(/^\//, ''); - options.path = options.path.replace(/\//g, '-'); - options.path= `\\\\.\\pipe\\${options.path}`; - } - - client.socket = net.connect(options); - }else{ - options.host=client.path; - options.port=client.port; - - if(client.config.interface.localAddress){ - options.localAddress=client.config.interface.localAddress; - } - - if(client.config.interface.localPort){ - options.localPort=client.config.interface.localPort; - } - - if(client.config.interface.family){ - options.family=client.config.interface.family; - } - - if(client.config.interface.hints){ - options.hints=client.config.interface.hints; - } - - if(client.config.interface.lookup){ - options.lookup=client.config.interface.lookup; - } - - if(!client.config.tls){ - client.log('Connecting client via TCP to', options); - client.socket = net.connect(options); - }else{ - client.log('Connecting client via TLS to', client.path ,client.port,client.config.tls); - if(client.config.tls.private){ - client.config.tls.key=fs.readFileSync(client.config.tls.private); - } - if(client.config.tls.public){ - client.config.tls.cert=fs.readFileSync(client.config.tls.public); - } - if(client.config.tls.trustedConnections){ - if(typeof client.config.tls.trustedConnections === 'string'){ - client.config.tls.trustedConnections=[client.config.tls.trustedConnections]; - } - client.config.tls.ca=[]; - for(let i=0; i4){ - Events = require('event-pubsub'); -} - -let eventParser = new EventParser(); - -class Server extends Events{ - constructor(path,config,log,port){ - super(); - Object.assign( - this, - { - config : config, - path : path, - port : port, - udp4 : false, - udp6 : false, - log : log, - server : false, - sockets : [], - emit : emit, - broadcast : broadcast - } - ); - - eventParser=new EventParser(this.config); - - this.on( - 'close', - serverClosed.bind(this) - ); - } - - onStart(socket){ - this.trigger( - 'start', - socket - ); - } - - stop(){ - this.server.close(); - } - - start(){ - if(!this.path){ - this.log('Socket Server Path not specified, refusing to start'); - return; - } - - if(this.config.unlink){ - fs.unlink( - this.path, - startServer.bind(this) - ); - }else{ - startServer.bind(this)(); - } - } -} - -function emit(socket, type, data){ - this.log('dispatching event to socket', ' : ', type, data); - - let message=new Message; - message.type=type; - message.data=data; - - if(this.config.rawBuffer){ - this.log(this.config.encoding) - message=new Buffer(type,this.config.encoding); - }else{ - message=eventParser.format(message); - } - - if(this.udp4 || this.udp6){ - - if(!socket.address || !socket.port){ - this.log('Attempting to emit to a single UDP socket without supplying socket address or port. Redispatching event as broadcast to all connected sockets'); - this.broadcast(type,data); - return; - } - - this.server.write( - message, - socket - ); - return; - } - - socket.write(message); -} - -function broadcast(type,data){ - this.log('broadcasting event to all known sockets listening to ', this.path,' : ', ((this.port)?this.port:''), type, data); - let message=new Message; - message.type=type; - message.data=data; - - if(this.config.rawBuffer){ - message=new Buffer(type,this.config.encoding); - }else{ - message=eventParser.format(message); - } - - if(this.udp4 || this.udp6){ - for(let i=1, count=this.sockets.length; i0){ - let message=new Message; - message.load(data.shift()); - - // Only set the sock id if it is specified. - if (message.data && message.data.id){ - sock.id=message.data.id; - } - - this.log('received event of : ',message.type,message.data); - - this.publish( - message.type, - message.data, - sock - ); - } -} - -function socketClosed(socket){ - this.publish( - 'close', - socket - ); -} - -function serverCreated(socket) { - this.sockets.push(socket); - - if(socket.setEncoding){ - socket.setEncoding(this.config.encoding); - } - - this.log('## socket connection to server detected ##'); - socket.on( - 'close', - socketClosed.bind(this) - ); - - socket.on( - 'error', - function(err){ - this.log('server socket error',err); - - this.publish('error',err); - }.bind(this) - ); - - socket.on( - 'data', - gotData.bind(this,socket) - ); - - socket.on( - 'message', - function(msg,rinfo) { - if (!rinfo){ - return; - } - - this.log('Received UDP message from ', rinfo.address, rinfo.port); - let data; - - if(this.config.rawSocket){ - data=new Buffer(msg,this.config.encoding); - }else{ - data=msg.toString(); - } - socket.emit('data',data,rinfo); - }.bind(this) - ); - - this.publish( - 'connect', - socket - ); - - if(this.config.rawBuffer){ - return; - } -} - -function startServer() { - this.log( - 'starting server on ',this.path, - ((this.port)?`:${this.port}`:'') - ); - - if(!this.udp4 && !this.udp6){ - this.log('starting TLS server',this.config.tls); - if(!this.config.tls){ - this.server=net.createServer( - serverCreated.bind(this) - ); - }else{ - startTLSServer.bind(this)(); - } - }else{ - this.server=dgram.createSocket( - ((this.udp4)? 'udp4':'udp6') - ); - this.server.write=UDPWrite.bind(this); - this.server.on( - 'listening', - function UDPServerStarted() { - serverCreated.bind(this)(this.server); - }.bind(this) - ); - } - - this.server.on( - 'error', - function(err){ - this.log('server error',err); - - this.publish( - 'error', - err - ); - }.bind(this) - ); - - this.server.maxConnections=this.config.maxConnections; - - if(!this.port){ - this.log('starting server as', 'Unix || Windows Socket'); - if (process.platform ==='win32'){ - this.path = this.path.replace(/^\//, ''); - this.path = this.path.replace(/\//g, '-'); - this.path= `\\\\.\\pipe\\${this.path}`; - } - - this.server.listen( - this.path, - this.onStart.bind(this) - ); - - return; - } - - if(!this.udp4 && !this.udp6){ - this.log('starting server as', (this.config.tls?'TLS':'TCP')); - this.server.listen( - this.port, - this.path, - this.onStart.bind(this) - ); - return; - } - - this.log('starting server as',((this.udp4)? 'udp4':'udp6')); - - this.server.bind( - this.port, - this.path - ); - - this.onStart( - { - address : this.path, - port : this.port - } - ); -} - -function startTLSServer(){ - this.log('starting TLS server',this.config.tls); - if(this.config.tls.private){ - this.config.tls.key=fs.readFileSync(this.config.tls.private); - }else{ - this.config.tls.key=fs.readFileSync(`${__dirname}/../local-node-ipc-certs/private/server.key`); - } - if(this.config.tls.public){ - this.config.tls.cert=fs.readFileSync(this.config.tls.public); - }else{ - this.config.tls.cert=fs.readFileSync(`${__dirname}/../local-node-ipc-certs/server.pub`); - } - if(this.config.tls.dhparam){ - this.config.tls.dhparam=fs.readFileSync(this.config.tls.dhparam); - } - if(this.config.tls.trustedConnections){ - if(typeof this.config.tls.trustedConnections === 'string'){ - this.config.tls.trustedConnections=[this.config.tls.trustedConnections]; - } - this.config.tls.ca=[]; - for(let i=0; i 0) { - // getting the family of first network interface available - IPType = networkInterfaces [ - Object.keys( networkInterfaces )[0] - ][0].family; - } - return IPType; -} - -module.exports=Defaults; diff --git a/WebSocketsServer/node_modules/node-ipc/entities/EventParser.js b/WebSocketsServer/node_modules/node-ipc/entities/EventParser.js deleted file mode 100644 index 8ac1f2bda..000000000 --- a/WebSocketsServer/node_modules/node-ipc/entities/EventParser.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -const Defaults = require('./Defaults.js'); - -class Parser{ - constructor(config){ - if(!config){ - config=new Defaults; - } - this.delimiter=config.delimiter; - } - - format(message){ - if(!message.data && message.data!==false && message.data!==0){ - message.data={}; - } - if(message.data['_maxListeners']){ - message.data={}; - } - - message=message.JSON+this.delimiter; - return message; - } - - parse(data){ - let events=data.split(this.delimiter); - events.pop(); - return events; - } -} - -module.exports=Parser; diff --git a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/goodbye-client.js b/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/goodbye-client.js deleted file mode 100644 index 9d5ce05d6..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/goodbye-client.js +++ /dev/null @@ -1,44 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'goodbye'; -ipc.config.retry= 1500; -ipc.config.maxRetries= 10; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'goodbye' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/hello-client.js deleted file mode 100644 index 74136333d..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/hello-client.js +++ /dev/null @@ -1,50 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.maxRetries=10; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data.message); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/world-server.js b/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/world-server.js deleted file mode 100644 index 2bef44794..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/Multi-Client-Broadcast/world-server.js +++ /dev/null @@ -1,51 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -var messages={ - goodbye:false, - hello:false -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - ipc.log('got a message from', (data.id), (data.message)); - messages[data.id]=true; - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - - if(messages.hello && messages.goodbye){ - ipc.log('got all required events, telling clients to kill connection'); - ipc.server.broadcast( - 'kill.connection', - { - id:ipc.config.id - } - ); - } - } - ); - } -); - - - - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/basic/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/basic/hello-client.js deleted file mode 100644 index 6ae692edf..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/basic/hello-client.js +++ /dev/null @@ -1,39 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/basic/world-server.js b/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/basic/world-server.js deleted file mode 100644 index 6c8790170..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/basic/world-server.js +++ /dev/null @@ -1,44 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.maxConnections=1; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log('DISCONNECTED\n\n',arguments); - } - ); - } -); - -ipc.server.on( - 'error', - function(err){ - ipc.log('Got an ERROR!',err); - } -); - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/basicSync/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/basicSync/hello-client.js deleted file mode 100644 index 292415053..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/basicSync/hello-client.js +++ /dev/null @@ -1,46 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.sync= true; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - - //queue up a bunch of requests to be sent synchronously - for(var i=0; i<10; i++){ - ipc.of.world.emit( - 'message', - 'hello'+i - ); - } - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data,'\n\n'); - } - ); - } -); - -console.log(ipc); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/basicSync/world-server.js b/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/basicSync/world-server.js deleted file mode 100644 index 3e817da13..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/basicSync/world-server.js +++ /dev/null @@ -1,45 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.sync = true; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - //fake some synch procedural code - setTimeout( - function(){ - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - }, - 3000 - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/hello-client.js deleted file mode 100644 index b6ac81f6b..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/hello-client.js +++ /dev/null @@ -1,35 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'hello' - ); - } - ); - - ipc.of.world.on( - 'data', - function(data){ - ipc.log('got a message from world : ', data,data.toString()); - } - ); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/world.server.js b/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/world.server.js deleted file mode 100644 index 5da4de4d5..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TCPSocket/rawBuffer/world.server.js +++ /dev/null @@ -1,40 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.serveNet( - function(){ - ipc.server.on( - 'connect', - function(socket){ - ipc.server.emit( - socket, - 'hello' - ); - } - ); - - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data,data.toString()); - ipc.server.emit( - socket, - 'goodbye' - ); - } - ); - } -); - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/goodbye-client.js b/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/goodbye-client.js deleted file mode 100644 index 508702d01..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/goodbye-client.js +++ /dev/null @@ -1,47 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'goodbye'; -ipc.config.retry= 1500; -ipc.config.maxRetries= 10; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'goodbye' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/hello-client.js deleted file mode 100644 index 16fd21fc3..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/hello-client.js +++ /dev/null @@ -1,53 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.maxRetries=10; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data.message); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/world-server.js b/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/world-server.js deleted file mode 100644 index 0c52c268d..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/Multi-Client-Broadcast-basic/world-server.js +++ /dev/null @@ -1,55 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key' -}; - -var messages={ - goodbye:false, - hello:false -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - ipc.log('got a message from', (data.id), (data.message)); - messages[data.id]=true; - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - - if(messages.hello && messages.goodbye){ - ipc.log('got all required events, telling clients to kill connection'); - ipc.server.broadcast( - 'kill.connection', - { - id:ipc.config.id - } - ); - } - } - ); - } -); - - - - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/hello-client.js deleted file mode 100644 index 15771565b..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/hello-client.js +++ /dev/null @@ -1,42 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/world-server.js b/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/world-server.js deleted file mode 100644 index 3cbcd8e38..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-local-only/world-server.js +++ /dev/null @@ -1,42 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -//node-ipc will default to its local certs -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/hello-client.js deleted file mode 100644 index bda3eb701..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/hello-client.js +++ /dev/null @@ -1,47 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.tls={ - private: __dirname+'/../../../local-node-ipc-certs/private/client.key', - public: __dirname+'/../../../local-node-ipc-certs/client.pub', - rejectUnauthorized:false, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/server.pub' - ] -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/world-server.js b/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/world-server.js deleted file mode 100644 index 56eee122b..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-more-secure/world-server.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key', - dhparam: __dirname+'/../../../local-node-ipc-certs/private/dhparam.pem', - requestCert: true, - rejectUnauthorized:false, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/client.pub' - ] -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/hello-client.js deleted file mode 100644 index 26d5b1da6..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/hello-client.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.networkHost='localhost'; -ipc.config.tls={ - private: __dirname+'/../../../local-node-ipc-certs/private/client.key', - public: __dirname+'/../../../local-node-ipc-certs/client.pub', - rejectUnauthorized:true, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/server.pub' - ] -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/world-server.js b/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/world-server.js deleted file mode 100644 index ee984a4e1..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic-most-secure/world-server.js +++ /dev/null @@ -1,49 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.networkHost='localhost'; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key', - dhparam: __dirname+'/../../../local-node-ipc-certs/private/dhparam.pem', - requestCert: true, - rejectUnauthorized:true, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/client.pub' - ] -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic/hello-client.js deleted file mode 100644 index 15771565b..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic/hello-client.js +++ /dev/null @@ -1,42 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'message', - 'hello' - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic/world-server.js b/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic/world-server.js deleted file mode 100644 index a52c3602a..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basic/world-server.js +++ /dev/null @@ -1,42 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key' -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basicSync/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basicSync/hello-client.js deleted file mode 100644 index 405db4468..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basicSync/hello-client.js +++ /dev/null @@ -1,47 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.sync= true; -ipc.config.tls={ - rejectUnauthorized:false -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - - //queue up a bunch of requests to be sent synchronously - for(var i=0; i<10; i++){ - ipc.of.world.emit( - 'message', - 'hello'+i - ); - } - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basicSync/world-server.js b/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basicSync/world-server.js deleted file mode 100644 index aec87c100..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/basicSync/world-server.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.sync= true; -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key' -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message : ', data); - setTimeout( - function(){ - ipc.server.emit( - socket, - 'message', - data+' world!' - ); - }, - 3000 - ); - } - ); - - ipc.server.on( - 'socket.disconnected', - function(data,socket){ - console.log(arguments); - } - ); - } -); - - - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/hello-client.js deleted file mode 100644 index f0c66ad22..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/hello-client.js +++ /dev/null @@ -1,45 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; -ipc.config.networkHost='localhost'; - -ipc.config.tls={ - private: __dirname+'/../../../local-node-ipc-certs/private/client.key', - public: __dirname+'/../../../local-node-ipc-certs/client.pub', - rejectUnauthorized:true, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/server.pub' - ] -}; - -ipc.connectToNet( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'hello' - ); - } - ); - - ipc.of.world.on( - 'data', - function(data){ - ipc.log('got a message from world : ', data,data.toString()); - } - ); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/world.server.js b/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/world.server.js deleted file mode 100644 index f0d0b29af..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/TLSSocket/rawBuffer-only-works-with-most-secure/world.server.js +++ /dev/null @@ -1,53 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; -ipc.config.networkHost='localhost'; - -ipc.config.tls={ - public: __dirname+'/../../../local-node-ipc-certs/server.pub', - private: __dirname+'/../../../local-node-ipc-certs/private/server.key', - dhparam: __dirname+'/../../../local-node-ipc-certs/private/dhparam.pem', - requestCert: true, - rejectUnauthorized:true, - trustedConnections: [ - __dirname+'/../../../local-node-ipc-certs/client.pub' - ] -}; - -ipc.serveNet( - function(){ - ipc.server.on( - 'connect', - function(socket){ - console.log('connection detected'); - ipc.server.emit( - socket, - 'hello' - ); - } - ); - - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data,data.toString()); - ipc.server.emit( - socket, - 'goodbye' - ); - } - ); - } -); - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/goodbye-client.js b/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/goodbye-client.js deleted file mode 100644 index d98a7b061..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/goodbye-client.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * Since there is no client relationship - * with UDP sockets sockets are not kept - * open. - * - * This means the order sockets are opened - * is important. - * - * Start World first. Then you can start - * hello or goodbye in any order you - * choose. - * - * *************************************/ - -ipc.config.id = 'goodbye'; -ipc.config.retry= 1500; - -ipc.serveNet( - 8002, //we set the port here because the hello client and world server are already using the default of 8000 and the port 8001. So we can not bind to those while hello and world are connected to them. - 'udp4', - function(){ - ipc.server.on( - 'message', - function(data){ - ipc.log('got Data'); - ipc.log('got a message from ', data.id ,' : ', data.message); - } - ); - ipc.server.emit( - { - address : 'localhost', - port : ipc.config.networkPort - }, - 'message', - { - id : ipc.config.id, - message : 'Goodbye' - } - ); - } -); - - - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/hello-client.js deleted file mode 100644 index ecc0b45a4..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/hello-client.js +++ /dev/null @@ -1,48 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * Since there is no client relationship - * with UDP sockets sockets are not kept - * open. - * - * This means the order sockets are opened - * is important. - * - * Start World first. Then you can start - * hello or goodbye in any order you - * choose. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; - -ipc.serveNet( - 8001, //we set the port here because the world server is already using the default of 8000. So we can not bind to 8000 while world is using it. - 'udp4', - function(){ - ipc.server.on( - 'message', - function(data){ - ipc.log('got Data'); - ipc.log('got a message from ', data.id ,' : ', data.message); - } - ); - ipc.server.emit( - { - address : 'localhost', - port : ipc.config.networkPort - }, - 'message', - { - id : ipc.config.id, - message : 'Hello' - } - ); - } -); - - - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/world-server.js b/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/world-server.js deleted file mode 100644 index 97f927088..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/Multi-Client-Broadcast/world-server.js +++ /dev/null @@ -1,63 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * Since there is no client relationship - * with UDP sockets sockets are not kept - * open. - * - * This means the order sockets are opened - * is important. - * - * Start World first. Then you can start - * hello or goodbye in any order you - * choose. - * - ***************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -var messages={ - goodbye:false, - hello:false -}; - -ipc.serveNet( - 'udp4', - function(){ - console.log(123); - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message from ', data.id ,' : ', data.message); - messages[data.id]=true; - ipc.server.emit( - socket, - 'message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - - if(messages.hello && messages.goodbye){ - ipc.log('got all required events, telling evryone how muchg I am loved!'); - ipc.server.broadcast( - 'message', - { - id : ipc.config.id, - message : 'Everybody Loves The World! Got messages from hello and goodbye!' - } - ); - } - } - ); - - console.log(ipc.server); - } -); - - - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/basic/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/basic/hello-client.js deleted file mode 100644 index f731b1ba8..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/basic/hello-client.js +++ /dev/null @@ -1,52 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * UDP Client is really a UDP server - * - * Dedicated UDP sockets on the same - * machine can not be bound to in the - * traditional client/server method - * - * Every UDP socket is it's own UDP server - * And so must have a unique port on its - * machine, unlike TCP or Unix Sockts - * which can share on the same machine. - * - * Since there is no open client server - * relationship, you should start world - * first and then hello. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; - -ipc.serveNet( - 8001, //we set the port here because the world server is already using the default of 8000. So we can not bind to 8000 while world is using it. - 'udp4', - function(){ - ipc.server.on( - 'message', - function(data){ - ipc.log('got Data'); - ipc.log('got a message from ', data.id ,' : ', data.message); - } - ); - ipc.server.emit( - { - address : 'localhost', - port : ipc.config.networkPort - }, - 'message', - { - id : ipc.config.id, - message : 'Hello' - } - ); - } -); - - - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/basic/world-server.js b/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/basic/world-server.js deleted file mode 100644 index 0f7aa4543..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/basic/world-server.js +++ /dev/null @@ -1,47 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * UDP Client is really a UDP server - * - * Dedicated UDP sockets on the same - * machine can not be bound to in the - * traditional client/server method - * - * Every UDP socket is it's own UDP server - * And so must have a unique port on its - * machine, unlike TCP or Unix Sockts - * which can share on the same machine. - * - * Since there is no open client server - * relationship, you should start world - * first and then hello. - * - ***************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -ipc.serveNet( - 'udp4', - function(){ - ipc.server.on( - 'message', - function(data,socket){ - ipc.log('got a message from ', data.id ,' : ', data.message); - ipc.server.emit( - socket, - 'message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - } - ); - } -); - - - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/hello-client.js deleted file mode 100644 index 73cd13ac5..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/hello-client.js +++ /dev/null @@ -1,35 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.serveNet( - 8001, //we set the port here because the world server is already using the default of 8000. So we can not bind to 8000 while world is using it. - 'udp4', - function(){ - ipc.server.on( - 'data', - function(data){ - ipc.log('got a message from world ', data, data.toString()); - } - ); - ipc.server.emit( - { - address : 'localhost', - port : ipc.config.networkPort - }, - 'hello' - ); - } -); - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/world.server.js b/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/world.server.js deleted file mode 100644 index d0c34f7e2..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/UDPSocket/rawBuffer/world.server.js +++ /dev/null @@ -1,43 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * UDP Client is really a UDP server - * - * Dedicated UDP sockets on the same - * machine can not be bound to in the - * traditional client/server method - * - * Every UDP socket is it's own UDP server - * And so must have a unique port on its - * machine, unlike TCP or Unix Sockts - * which can share on the same machine. - * - * Since there is no open client server - * relationship, you should start world - * first and then hello. - * - ***************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.serveNet( - 'udp4', - function(){ - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data,data.toString()); - ipc.server.emit( - socket, - 'goodbye' - ); - } - ); - } -); - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-client.js b/WebSocketsServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-client.js deleted file mode 100644 index eca2a889c..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-client.js +++ /dev/null @@ -1,31 +0,0 @@ -const fs = require('fs'); -const ipc = require('../../node-ipc'); - -const socketPath = '/tmp/ipc.sock'; - -//loop forever so you can see the pid of the cluster sever change in the logs -setInterval( - function() { - ipc.connectTo( - 'world', - socketPath, - connecting - ); - }, - 2000 -); - -function connecting(socket) { - ipc.of.world.on( - 'connect', - function() { - ipc.of.world.emit( - 'currentDate', - { - message: new Date().toISOString() - } - ); - ipc.disconnect('world'); - } - ); -} diff --git a/WebSocketsServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-server.js b/WebSocketsServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-server.js deleted file mode 100644 index b0942a338..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/clusterUnixSocket/cluster-server.js +++ /dev/null @@ -1,32 +0,0 @@ -const fs = require('fs'); -const ipc=require('../../../node-ipc'); -const cpuCount = require('os').cpus().length; -const cluster = require('cluster'); -const socketPath = '/tmp/ipc.sock'; - -ipc.config.unlink = false; - -if (cluster.isMaster) { - if (fs.existsSync(socketPath)) { - fs.unlinkSync(socketPath); - } - - for (let i = 0; i < cpuCount; i++) { - cluster.fork(); - } -}else{ - ipc.serve( - socketPath, - function() { - ipc.server.on( - 'currentDate', - function(data,socket) { - console.log(`pid ${process.pid} got: `, data); - } - ); - } - ); - - ipc.server.start(); - console.log(`pid ${process.pid} listening on ${socketPath}`); -} diff --git a/WebSocketsServer/node_modules/node-ipc/example/rawBuffer/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/rawBuffer/hello-client.js deleted file mode 100644 index f22ab5376..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/rawBuffer/hello-client.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict'; - -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='hex'; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - //make a 6 byte buffer for example - const myBuffer=new Buffer(6).fill(0); - - myBuffer.writeUInt16BE(0x02,0); - myBuffer.writeUInt32BE(0xffeecc,2); - - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - myBuffer - ); - } - ); - - ipc.of.world.on( - 'data', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/rawBuffer/world.server.js b/WebSocketsServer/node_modules/node-ipc/example/rawBuffer/world.server.js deleted file mode 100644 index f27a02cd5..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/rawBuffer/world.server.js +++ /dev/null @@ -1,40 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='hex'; - -ipc.serve( - function(){ - ipc.server.on( - 'connect', - function(socket){ - ipc.server.emit( - socket, - [0xaa] - ); - } - ); - - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data); - ipc.server.emit( - socket, - [0x0d,0xee] - ); - } - ); - } -); - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/goodbye-client.js b/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/goodbye-client.js deleted file mode 100644 index 57d455eec..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/goodbye-client.js +++ /dev/null @@ -1,43 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'goodbye'; -ipc.config.retry= 1500; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'goodbye' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/hello-client.js deleted file mode 100644 index d556c4694..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/hello-client.js +++ /dev/null @@ -1,49 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - ipc.of.world.on( - 'kill.connection', - function(data){ - ipc.log('world requested kill.connection'); - ipc.disconnect('world'); - } - ); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/world-server.js b/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/world-server.js deleted file mode 100644 index 69cfb31c0..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/Multi-Client-Broadcast/world-server.js +++ /dev/null @@ -1,51 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -var messages={ - goodbye:false, - hello:false -}; - -ipc.serve( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - ipc.log('got a message from', (data.id), (data.message)); - messages[data.id]=true; - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - - if(messages.hello && messages.goodbye){ - ipc.log('got all required events, telling clients to kill connection'); - ipc.server.broadcast( - 'kill.connection', - { - id:ipc.config.id - } - ); - } - } - ); - } -); - - - - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/basic/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/basic/hello-client.js deleted file mode 100644 index c6d87cb27..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/basic/hello-client.js +++ /dev/null @@ -1,44 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry = 1000; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello' - } - ); - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - - console.log(ipc.of.world.destroy); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/basic/world-server.js b/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/basic/world-server.js deleted file mode 100644 index 6b3052242..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/basic/world-server.js +++ /dev/null @@ -1,33 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; - -ipc.serve( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - } - ); - } -); - - - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/hello-client.js deleted file mode 100644 index 3142677a2..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/hello-client.js +++ /dev/null @@ -1,49 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry = 1000; -ipc.config.sync= true; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - - //queue up a bunch of requests to be sent synchronously - for(var i=0; i<10; i++){ - ipc.of.world.emit( - 'app.message', - { - id : ipc.config.id, - message : 'hello'+i - } - ); - } - } - ); - ipc.of.world.on( - 'disconnect', - function(){ - ipc.log('disconnected from world'); - } - ); - ipc.of.world.on( - 'app.message', - function(data){ - ipc.log('got a message from world : ', data); - } - ); - - console.log(ipc.of.world.destroy); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/world-server.js b/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/world-server.js deleted file mode 100644 index c76e1bb6f..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/basicSync/world-server.js +++ /dev/null @@ -1,39 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.sync= true; - -ipc.serve( - function(){ - ipc.server.on( - 'app.message', - function(data,socket){ - setTimeout( - function(){ - ipc.server.emit( - socket, - 'app.message', - { - id : ipc.config.id, - message : data.message+' world!' - } - ); - }, - 2000 - ); - } - ); - } -); - - - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/hello-client.js b/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/hello-client.js deleted file mode 100644 index 9c7042a90..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/hello-client.js +++ /dev/null @@ -1,35 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'hello'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.connectTo( - 'world', - function(){ - ipc.of.world.on( - 'connect', - function(){ - ipc.log('## connected to world ##', ipc.config.delay); - ipc.of.world.emit( - 'hello' - ); - } - ); - - ipc.of.world.on( - 'data', - function(data){ - ipc.log('got a message from world : ', data,data.toString()); - } - ); - } -); diff --git a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/world.server.js b/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/world.server.js deleted file mode 100644 index c3ed83c9a..000000000 --- a/WebSocketsServer/node_modules/node-ipc/example/unixWindowsSocket/rawBuffer/world.server.js +++ /dev/null @@ -1,40 +0,0 @@ -const ipc=require('../../../node-ipc'); - -/***************************************\ - * - * You should start both hello and world - * then you will see them communicating. - * - * *************************************/ - -ipc.config.id = 'world'; -ipc.config.retry= 1500; -ipc.config.rawBuffer=true; -ipc.config.encoding='ascii'; - -ipc.serve( - function(){ - ipc.server.on( - 'connect', - function(socket){ - ipc.server.emit( - socket, - 'hello' - ); - } - ); - - ipc.server.on( - 'data', - function(data,socket){ - ipc.log('got a message', data,data.toString()); - ipc.server.emit( - socket, - 'goodbye' - ); - } - ); - } -); - -ipc.server.start(); diff --git a/WebSocketsServer/node_modules/node-ipc/node-ipc.js b/WebSocketsServer/node_modules/node-ipc/node-ipc.js deleted file mode 100644 index 1c6336061..000000000 --- a/WebSocketsServer/node_modules/node-ipc/node-ipc.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -const IPC = require('./services/IPC.js'); - -class IPCModule extends IPC{ - constructor(){ - super(); - //include IPC to make extensible - Object.defineProperty( - this, - 'IPC', - { - enumerable:true, - writable:false, - value:IPC - } - ) - } -} - -module.exports=new IPCModule; diff --git a/WebSocketsServer/node_modules/node-ipc/package.json b/WebSocketsServer/node_modules/node-ipc/package.json deleted file mode 100644 index ba49befef..000000000 --- a/WebSocketsServer/node_modules/node-ipc/package.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "_from": "node-ipc", - "_id": "node-ipc@9.1.1", - "_inBundle": false, - "_integrity": "sha512-FAyICv0sIRJxVp3GW5fzgaf9jwwRQxAKDJlmNFUL5hOy+W4X/I5AypyHoq0DXXbo9o/gt79gj++4cMr4jVWE/w==", - "_location": "/node-ipc", - "_phantomChildren": {}, - "_requested": { - "type": "tag", - "registry": true, - "raw": "node-ipc", - "name": "node-ipc", - "escapedName": "node-ipc", - "rawSpec": "", - "saveSpec": null, - "fetchSpec": "latest" - }, - "_requiredBy": [ - "#USER", - "/" - ], - "_resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.1.1.tgz", - "_shasum": "4e245ed6938e65100e595ebc5dc34b16e8dd5d69", - "_spec": "node-ipc", - "_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\WebSockets-Server", - "author": { - "name": "Brandon Nozaki Miller" - }, - "bugs": { - "url": "https://github.com/RIAEvangelist/node-ipc/issues" - }, - "bundleDependencies": false, - "dependencies": { - "event-pubsub": "4.3.0", - "js-message": "1.0.5", - "js-queue": "2.0.0" - }, - "deprecated": false, - "description": "A nodejs module for local and remote Inter Process Communication (IPC), Neural Networking, and able to facilitate machine learning.", - "devDependencies": { - "codacy-coverage": "2.0.0", - "istanbul": "0.4.1", - "jasmine": "2.4.1", - "node-cmd": "2.0.0" - }, - "directories": { - "example": "example" - }, - "engines": { - "node": ">=4.0.0" - }, - "homepage": "http://riaevangelist.github.io/node-ipc/", - "keywords": [ - "IPC", - "Neural Networking", - "Machine Learning", - "inter", - "process", - "communication", - "unix", - "windows", - "win", - "socket", - "TCP", - "UDP", - "domain", - "sockets", - "threaded", - "communication", - "multi", - "process", - "shared", - "memory" - ], - "license": "DBAD", - "main": "node-ipc.js", - "name": "node-ipc", - "pre-commit": [ - "cover" - ], - "repository": { - "type": "git", - "url": "git+https://github.com/RIAEvangelist/node-ipc.git" - }, - "scripts": { - "cover": "istanbul cover -x **/spec/** -dir ./spec/coverage jasmine", - "coverup": "cat ./spec/coverage/lcov.info | codacy-coverage", - "test": "istanbul cover -x **/spec/** -dir ./spec/coverage jasmine", - "test-windows": "istanbul cover -x **/spec/** -dir ./spec/coverage ./node_modules/jasmine/bin/jasmine.js" - }, - "version": "9.1.1" -} diff --git a/WebSocketsServer/node_modules/node-ipc/services/IPC.js b/WebSocketsServer/node_modules/node-ipc/services/IPC.js deleted file mode 100644 index 3a6edc7f5..000000000 --- a/WebSocketsServer/node_modules/node-ipc/services/IPC.js +++ /dev/null @@ -1,337 +0,0 @@ -'use strict'; - -const Defaults = require('../entities/Defaults.js'), - Client = require('../dao/client.js'), - Server = require('../dao/socketServer.js'), - util = require('util'); - -class IPC{ - constructor(){ - Object.defineProperties( - this, - { - config : { - enumerable:true, - writable:true, - value:new Defaults - }, - connectTo : { - enumerable:true, - writable:false, - value:connect - }, - connectToNet: { - enumerable:true, - writable:false, - value:connectNet - }, - disconnect : { - enumerable:true, - writable:false, - value:disconnect - }, - serve : { - enumerable:true, - writable:false, - value:serve - }, - serveNet : { - enumerable:true, - writable:false, - value:serveNet - }, - of : { - enumerable:true, - writable:true, - value:{} - }, - server : { - enumerable:true, - writable:true, - configurable:true, - value:false - }, - log : { - enumerable:true, - writable:false, - value:log - } - } - ); - } -} - -function log(...args){ - if(this.config.silent){ - return; - } - - for(let i=0, count=args.length; i 0) { - console.log("Superalgos Web Server cannot be started. Reason: the port " + port + " is already in use by another application. The web server cannot be started until either you stop the other application or you change the port number at the WebServer/.env file for an unused one. (variable name VIRTUAL_PORT)") - return - } - console.log('[ERROR] Web Sockets Server -> server -> uncaughtException -> err.message = ' + err.message) - console.log('[ERROR] Web Sockets Server -> server -> uncaughtException -> err.stack = ' + err.stack) - process.exit(1) -}) - -process.on('unhandledRejection', (reason, p) => { - console.log('[ERROR] Web Sockets Server -> server -> unhandledRejection -> reason = ' + JSON.stringify(reason)) - console.log('[ERROR] Web Sockets Server -> server -> unhandledRejection -> p = ' + JSON.stringify(p)) - process.exit(1) -}) - -try { - ipc.connectTo( - 'world', - function () { - ipc.of.world.on( - 'connect', - function () { - - let lastNonce = -1 - - ipc.log('## connected to world ##'.rainbow, ipc.config.delay); - - let eventCommand = { - action: 'greetings', - from: 'Web Sockets Server' - } - - ipc.of.world.emit( - 'message', - JSON.stringify(eventCommand) - ) - - wss = new WebSocket.Server({ port: port }) - - wss.on('connection', ws => { - ws.on('message', message => { - - if (ipc.config.silent !== true) { - console.log(`Received message from browser => ${message}`) - } - - //console.log('Message Received From Browser: ' + message) - - let dividerPosition = message.indexOf('->') - let nonce = message.substring(0, dividerPosition) - let messageToEventServer = message.substring(dividerPosition + 2, message.length) - - if (isNaN(nonce) || nonce === "") { - console.log('[ERROR] Web Sockets Server -> server -> connectTo -> onMessageFromBrowser -> Nonce is not a Number. message = ' + message) - console.log('[ERROR] Web Sockets Server -> server -> connectTo -> onMessageFromBrowser -> Nonce is not a Number. nonce = ' + nonce) - return - } - - if (nonce === "1") { // this happens once the browser is restarted, and the server is running since a previous session. - lastNonce = 0 - } - - if (Number(nonce) < Number(lastNonce)) { - console.log('[ERROR] Web Sockets Server -> server -> connectTo -> onMessageFromBrowser -> Nonce received is less than Last Nonce. message = ' + message) - console.log('[ERROR] Web Sockets Server -> server -> connectTo -> onMessageFromBrowser -> Nonce received is less than Last Nonce. nonce = ' + nonce) - console.log('[ERROR] Web Sockets Server -> server -> connectTo -> onMessageFromBrowser -> Nonce received is less than Last Nonce. lastNonce = ' + lastNonce) - return - } - - lastNonce = nonce - - try { - let jsonCheck = JSON.parse(messageToEventServer) - } catch (err) { - console.log('[ERROR] Web Sockets Server -> server -> connectTo -> onMessageFromBrowser -> Message received from the browser is not a valid JSON. message = ' + message) - console.log('[ERROR] Web Sockets Server -> server -> connectTo -> onMessageFromBrowser -> Message received from the browser is not a valid JSON. messageToEventServer = ' + messageToEventServer) - return - } - - let acknowledgeMessage = { - action: 'Acknowledge', - nonce: nonce - } - - ws.send(JSON.stringify(acknowledgeMessage)) - - ipc.of.world.emit( - 'message', - messageToEventServer - ) - }) - - ipc.of.world.on( - 'message', - function (data) { - ipc.log('got a message from Event Server : '.debug, data); - - try { - let jsonCheck = JSON.parse(data) - } catch (err) { - console.log('[ERROR] Web Sockets Server -> server -> connectTo -> onMessageFromEventServer -> Data received from the Event Server is not a valid JSON. data = ' + data) - } - - ws.send(data) - } - ); - }) - - console.log('Web Socket Server Started.') - } - ); - ipc.of.world.on( - 'disconnect', - function () { - ipc.log('disconnected from world'.notice); - } - ); - } - ); -} catch (err) { - console.log('[ERROR] Web Sockets Server -> server -> connectTo -> err.message = ' + err.message) -} -