From 7a8f882bc35b6c3fa41a38a4dfaf29dd46c43e77 Mon Sep 17 00:00:00 2001 From: Julien Sergent Date: Thu, 1 Apr 2021 02:46:16 +0200 Subject: [PATCH 1/2] WIP --- .gitignore | 2 +- .prettierrc | 3 + .vscode/settings.json | 3 + README.md | 26 +- package-lock.json | 2947 +++++++++++++++++--- package.json | 30 +- src/config/config.binance.ts | 110 +- src/config/config.gdax.ts | 114 +- src/config/index.ts | 15 +- src/config/platform.ts | 6 +- src/index.ts | 34 +- src/markets/binance/accounts.ts | 39 +- src/markets/binance/index.ts | 148 +- src/markets/binance/orders.ts | 501 ++-- src/markets/gdax/accounts.ts | 196 +- src/markets/gdax/index.ts | 169 +- src/markets/gdax/orders.ts | 400 +-- src/typings.d.ts | 106 +- src/vendor/chart/chart-analyzer.ts | 298 +- src/vendor/chart/chart-work.ts | 16 +- src/vendor/chart/chart-worker.ts | 637 +++-- src/vendor/chart/chart.ts | 54 +- src/vendor/chart/equation.ts | 98 +- src/vendor/chart/maths.ts | 42 +- src/vendor/chart/point.ts | 14 +- src/vendor/chart/smoothing.ts | 6 +- src/vendor/chart/trend.enum.ts | 8 +- src/vendor/chart/worker-speed.ts | 6 +- src/vendor/interfaces/currency.enum.ts | 760 ++--- src/vendor/interfaces/market.ts | 46 +- src/vendor/interfaces/order-status.enum.ts | 8 +- src/vendor/interfaces/order-type.enum.ts | 17 +- src/vendor/interfaces/trader.ts | 6 +- src/vendor/logger/index.ts | 28 +- src/vendor/market/accounts.ts | 41 +- src/vendor/market/currency-info.ts | 25 +- src/vendor/market/order.ts | 30 +- src/vendor/market/orders.ts | 63 +- src/vendor/slack/index.ts | 61 +- src/vendor/trader/data.ts | 38 +- src/vendor/trader/index.ts | 1085 +++---- src/vendor/trader/trade-type.ts | 8 +- src/vendor/trader/trade.ts | 16 +- src/vendor/trader/trader-state.ts | 8 +- 44 files changed, 5457 insertions(+), 2811 deletions(-) create mode 100644 .prettierrc create mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index b89472b..2e9bf38 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ node_modules/ dist/ data.json -envfile \ No newline at end of file +.env diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..cce9d3c --- /dev/null +++ b/.prettierrc @@ -0,0 +1,3 @@ +{ + "semi": false +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..78664b2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.tabSize": 2 +} diff --git a/README.md b/README.md index 6f0605d..11f563b 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,8 @@ ## Installation ```bash -git clone https://gitlab.com/MadDeveloper/bot-warhead.git theddy +git clone https://gitlab.com/MadDeveloper/trading-bot.git theddy cd theddy -npm install --global typescript lite-server npm install ``` @@ -13,12 +12,12 @@ Create your API keys on the platform (binance, gdax, etc.) and export them as en For exemple, on Linux, add to your ~/.bashrc the following lines: ```bash -export BINANCE_API_KEY=lorem -export BINANCE_API_SECRET=lorem -export BINANCE_API_PASSPHRASE=lorem -export GDAX_API_KEY=lorem -export GDAX_API_SECRET=lorem -export GDAX_API_PASSPHRASE=lorem +export BINANCE_API_KEY= +export BINANCE_API_SECRET= +export BINANCE_API_PASSPHRASE= +export GDAX_API_KEY= +export GDAX_API_SECRET= +export GDAX_API_PASSPHRASE= ``` ## Getting started @@ -34,7 +33,7 @@ Or one by step: ```bash npm run build && npm start -```` +``` If you want to see in realtime the chart: @@ -45,13 +44,14 @@ npm run chart And then you can go to http://localhost:3000 and watch the magic happening! ## Docker + ### Setup ```bash -touch envfile +touch .env ``` -Then add the following lines to the envfile: +Then add the following lines to the .env file: ```bash BINANCE_API_KEY=xxxxxx @@ -77,11 +77,11 @@ npm run docker:build ### Run ```bash -docker run -it --env-file envfile -p 3000:3000 theddy +docker run -it --env-file .env -p 3000:3000 theddy ``` or ```bash npm run docker:run -``` \ No newline at end of file +``` diff --git a/package-lock.json b/package-lock.json index fb9b965..b184bbb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,33 +1,46 @@ { "name": "bot", - "version": "0.3.0", + "version": "0.3.7", "lockfileVersion": 1, "requires": true, "dependencies": { + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "requires": { + "defer-to-connect": "^1.0.1" + } + }, "@types/node": { - "version": "8.5.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.9.tgz", - "integrity": "sha512-s+c3AjymyAccTI4hcgNFK4mToH8l+hyPDhu4LIkn71lRy56FLijGu00fyLgldjM/846Pmk9N4KFUs2P8GDs0pA==", + "version": "14.14.37", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz", + "integrity": "sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==", "dev": true }, "@types/rx": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@types/rx/-/rx-4.1.1.tgz", - "integrity": "sha1-WY/JSla67ZdfGUV04PVy/Y5iekg=", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@types/rx/-/rx-4.1.2.tgz", + "integrity": "sha512-1r8ZaT26Nigq7o4UBGl+aXB2UMFUIdLPP/8bLIP0x3d0pZL46ybKKjhWKaJQWIkLl5QCLD0nK3qTOO1QkwdFaA==", "dev": true, "requires": { - "@types/rx-core": "4.0.3", - "@types/rx-core-binding": "4.0.4", - "@types/rx-lite": "4.0.5", - "@types/rx-lite-aggregates": "4.0.3", - "@types/rx-lite-async": "4.0.2", - "@types/rx-lite-backpressure": "4.0.3", - "@types/rx-lite-coincidence": "4.0.3", - "@types/rx-lite-experimental": "4.0.1", - "@types/rx-lite-joinpatterns": "4.0.1", - "@types/rx-lite-testing": "4.0.1", - "@types/rx-lite-time": "4.0.3", - "@types/rx-lite-virtualtime": "4.0.3" + "@types/rx-core": "*", + "@types/rx-core-binding": "*", + "@types/rx-lite": "*", + "@types/rx-lite-aggregates": "*", + "@types/rx-lite-async": "*", + "@types/rx-lite-backpressure": "*", + "@types/rx-lite-coincidence": "*", + "@types/rx-lite-experimental": "*", + "@types/rx-lite-joinpatterns": "*", + "@types/rx-lite-testing": "*", + "@types/rx-lite-time": "*", + "@types/rx-lite-virtualtime": "*" } }, "@types/rx-core": { @@ -42,17 +55,17 @@ "integrity": "sha512-5pkfxnC4w810LqBPUwP5bg7SFR/USwhMSaAeZQQbEHeBp57pjKXRlXmqpMrLJB4y1oglR/c2502853uN0I+DAQ==", "dev": true, "requires": { - "@types/rx-core": "4.0.3" + "@types/rx-core": "*" } }, "@types/rx-lite": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/rx-lite/-/rx-lite-4.0.5.tgz", - "integrity": "sha512-KZk5XTR1dm/kNgBx8iVpjno6fRYtAUQWBOmj+O8j724+nk097sz4fOoHJNpCkOJUtHUurZlJC7QvSFCZHbkC+w==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/rx-lite/-/rx-lite-4.0.6.tgz", + "integrity": "sha512-oYiDrFIcor9zDm0VDUca1UbROiMYBxMLMaM6qzz4ADAfOmA9r1dYEcAFH+2fsPI5BCCjPvV9pWC3X3flbrvs7w==", "dev": true, "requires": { - "@types/rx-core": "4.0.3", - "@types/rx-core-binding": "4.0.4" + "@types/rx-core": "*", + "@types/rx-core-binding": "*" } }, "@types/rx-lite-aggregates": { @@ -61,7 +74,7 @@ "integrity": "sha512-MAGDAHy8cRatm94FDduhJF+iNS5//jrZ/PIfm+QYw9OCeDgbymFHChM8YVIvN2zArwsRftKgE33QfRWvQk4DPg==", "dev": true, "requires": { - "@types/rx-lite": "4.0.5" + "@types/rx-lite": "*" } }, "@types/rx-lite-async": { @@ -70,7 +83,7 @@ "integrity": "sha512-vTEv5o8l6702ZwfAM5aOeVDfUwBSDOs+ARoGmWAKQ6LOInQ8J4/zjM7ov12fuTpktUKdMQjkeCp07Vd73mPkxw==", "dev": true, "requires": { - "@types/rx-lite": "4.0.5" + "@types/rx-lite": "*" } }, "@types/rx-lite-backpressure": { @@ -79,7 +92,7 @@ "integrity": "sha512-Y6aIeQCtNban5XSAF4B8dffhIKu6aAy/TXFlScHzSxh6ivfQBQw6UjxyEJxIOt3IT49YkS+siuayM2H/Q0cmgA==", "dev": true, "requires": { - "@types/rx-lite": "4.0.5" + "@types/rx-lite": "*" } }, "@types/rx-lite-coincidence": { @@ -88,7 +101,7 @@ "integrity": "sha512-1VNJqzE9gALUyMGypDXZZXzR0Tt7LC9DdAZQ3Ou/Q0MubNU35agVUNXKGHKpNTba+fr8GdIdkC26bRDqtCQBeQ==", "dev": true, "requires": { - "@types/rx-lite": "4.0.5" + "@types/rx-lite": "*" } }, "@types/rx-lite-experimental": { @@ -97,7 +110,7 @@ "integrity": "sha1-xTL1y98/LBXaFt7Ykw0bKYQCPL0=", "dev": true, "requires": { - "@types/rx-lite": "4.0.5" + "@types/rx-lite": "*" } }, "@types/rx-lite-joinpatterns": { @@ -106,7 +119,7 @@ "integrity": "sha1-9w/jcFGKhDLykVjMkv+1a05K/D4=", "dev": true, "requires": { - "@types/rx-lite": "4.0.5" + "@types/rx-lite": "*" } }, "@types/rx-lite-testing": { @@ -115,7 +128,7 @@ "integrity": "sha1-IbGdEfTf1v/vWp0WSOnIh5v+Iek=", "dev": true, "requires": { - "@types/rx-lite-virtualtime": "4.0.3" + "@types/rx-lite-virtualtime": "*" } }, "@types/rx-lite-time": { @@ -124,7 +137,7 @@ "integrity": "sha512-ukO5sPKDRwCGWRZRqPlaAU0SKVxmWwSjiOrLhoQDoWxZWg6vyB9XLEZViKOzIO6LnTIQBlk4UylYV0rnhJLxQw==", "dev": true, "requires": { - "@types/rx-lite": "4.0.5" + "@types/rx-lite": "*" } }, "@types/rx-lite-virtualtime": { @@ -133,7 +146,49 @@ "integrity": "sha512-3uC6sGmjpOKatZSVHI2xB1+dedgml669ZRvqxy+WqmGJDVusOdyxcKfyzjW0P3/GrCiN4nmRkLVMhPwHCc5QLg==", "dev": true, "requires": { - "@types/rx-lite": "4.0.5" + "@types/rx-lite": "*" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "dependencies": { + "mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==" + }, + "mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "requires": { + "mime-db": "1.46.0" + } + } + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "requires": { + "es6-promisify": "^5.0.0" } }, "ajv": { @@ -141,19 +196,77 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + } + }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "requires": { + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "dev": true, + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", "requires": { - "color-convert": "1.9.1" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, "asn1": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", @@ -164,10 +277,15 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" }, - "async-limiter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + }, + "async-each-series": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/async-each-series/-/async-each-series-0.1.1.tgz", + "integrity": "sha1-dhfBkXQB/Yykooqtzj266Yr+tDI=" }, "asynckit": { "version": "0.4.0", @@ -184,42 +302,359 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base64-arraybuffer": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", + "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=" + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=" + }, "bcrypt-pbkdf": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", "optional": true, "requires": { - "tweetnacl": "0.14.5" + "tweetnacl": "^0.14.3" + } + }, + "bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" + }, + "binance-api-node": { + "version": "0.10.34", + "resolved": "https://registry.npmjs.org/binance-api-node/-/binance-api-node-0.10.34.tgz", + "integrity": "sha512-iThCps2Kl5Hdr3g9dLrIGIKIRW7fiaCpY7cFavAkorRpv1GM+YPhPNPLJzt69BRQvUmxv1+3QMbyKlzg8jvWEg==", + "requires": { + "isomorphic-fetch": "^2.2.1", + "isomorphic-ws": "^4.0.1", + "lodash.zipobject": "^4.1.3", + "reconnecting-websocket": "^4.2.0", + "ws": "^7.2.0" + }, + "dependencies": { + "ws": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==" + } } }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, "bintrees": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", "integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=" }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" + }, "boom": { "version": "2.10.1", "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "requires": { - "hoek": "2.16.3" + "hoek": "2.x.x" + } + }, + "boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-sync": { + "version": "2.26.14", + "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-2.26.14.tgz", + "integrity": "sha512-3TtpsheGolJT6UFtM2CZWEcGJmI4ZEvoCKiKE2bvcDnPxRkhQT4nIGVtfiyPcoHKXGM0LwMOZmYJNWfiNfVXWA==", + "requires": { + "browser-sync-client": "^2.26.14", + "browser-sync-ui": "^2.26.14", + "bs-recipes": "1.3.4", + "bs-snippet-injector": "^2.0.1", + "chokidar": "^3.5.1", + "connect": "3.6.6", + "connect-history-api-fallback": "^1", + "dev-ip": "^1.0.1", + "easy-extender": "^2.3.4", + "eazy-logger": "3.1.0", + "etag": "^1.8.1", + "fresh": "^0.5.2", + "fs-extra": "3.0.1", + "http-proxy": "^1.18.1", + "immutable": "^3", + "localtunnel": "^2.0.1", + "micromatch": "^4.0.2", + "opn": "5.3.0", + "portscanner": "2.1.1", + "qs": "6.2.3", + "raw-body": "^2.3.2", + "resp-modifier": "6.0.2", + "rx": "4.1.0", + "send": "0.16.2", + "serve-index": "1.9.1", + "serve-static": "1.13.2", + "server-destroy": "1.0.1", + "socket.io": "2.4.0", + "ua-parser-js": "^0.7.18", + "yargs": "^15.4.1" + }, + "dependencies": { + "qs": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", + "integrity": "sha1-HPyyXBCpsrSDBT/zn138kjOQjP4=" + } + } + }, + "browser-sync-client": { + "version": "2.26.14", + "resolved": "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-2.26.14.tgz", + "integrity": "sha512-be0m1MchmKv/26r/yyyolxXcBi052aYrmaQep5nm8YNMjFcEyzv0ZoOKn/c3WEXNlEB/KeXWaw70fAOJ+/F1zQ==", + "requires": { + "etag": "1.8.1", + "fresh": "0.5.2", + "mitt": "^1.1.3", + "rxjs": "^5.5.6" + }, + "dependencies": { + "rxjs": { + "version": "5.5.12", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", + "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", + "requires": { + "symbol-observable": "1.0.1" + } + } + } + }, + "browser-sync-ui": { + "version": "2.26.14", + "resolved": "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-2.26.14.tgz", + "integrity": "sha512-6oT1sboM4KVNnWCCJDMGbRIeTBw97toMFQ+srImvwQ6J5t9KMgizaIX8HcKLiemsUMSJkgGM9RVKIpq2UblgOA==", + "requires": { + "async-each-series": "0.1.1", + "connect-history-api-fallback": "^1", + "immutable": "^3", + "server-destroy": "1.0.1", + "socket.io-client": "^2.4.0", + "stream-throttle": "^0.1.3" + } + }, + "bs-recipes": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz", + "integrity": "sha1-DS1NSKcYyMBEdp/cT4lZLci2lYU=" + }, + "bs-snippet-injector": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bs-snippet-injector/-/bs-snippet-injector-2.0.1.tgz", + "integrity": "sha1-YbU5PxH1JVntEgaTEANDtu2wTdU=" + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + } } }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "chalk": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", - "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", - "dev": true, + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==" + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "requires": { + "mimic-response": "^1.0.0" } }, "co": { @@ -228,42 +663,122 @@ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" }, "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "dev": true, + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "color-name": "1.1.3" + "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "combined-stream": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "connect": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", + "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.0", + "parseurl": "~1.3.2", + "utils-merge": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==" + }, + "connect-logger": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/connect-logger/-/connect-logger-0.0.1.tgz", + "integrity": "sha1-TZmZeKHSC7RgjnzUNNdBZSJVF0s=", + "requires": { + "moment": "*" } }, + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { - "lru-cache": "4.1.1", - "shebang-command": "1.2.0", - "which": "1.3.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, "cryptiles": { @@ -271,15 +786,20 @@ "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", "requires": { - "boom": "2.10.1" + "boom": "2.x.x" } }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" }, "dependencies": { "assert-plus": { @@ -289,39 +809,267 @@ } } }, - "delay": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/delay/-/delay-2.0.0.tgz", - "integrity": "sha1-kRLq3APk7H4AKXM3iW8nO72R+uU=", + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", "requires": { - "p-defer": "1.0.0" + "mimic-response": "^1.0.0" } }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==" + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "dev-ip": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dev-ip/-/dev-ip-1.0.1.tgz", + "integrity": "sha1-p2o+0YVb56ASu4rBbLgPPADcKPA=" + }, + "dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "requires": { + "is-obj": "^2.0.0" + } + }, "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "dev": true }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, + "easy-extender": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/easy-extender/-/easy-extender-2.3.4.tgz", + "integrity": "sha512-8cAwm6md1YTiPpOvDULYJL4ZS6WfM5/cTeVVh4JsvyYZAoqlRVUpHL9Gr5Fy7HA6xcSZicUia3DeAgO3Us8E+Q==", + "requires": { + "lodash": "^4.17.10" + } + }, + "eazy-logger": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eazy-logger/-/eazy-logger-3.1.0.tgz", + "integrity": "sha512-/snsn2JqBtUSSstEl4R0RKjkisGHAhvYj89i7r3ytNUKW12y178KDZwXLXIgwDqLW6E/VRMT9qfld7wvFae8bQ==", + "requires": { + "tfunk": "^4.0.0" + } + }, "ecc-jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", "optional": true, "requires": { - "jsbn": "0.1.1" + "jsbn": "~0.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "engine.io": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.5.0.tgz", + "integrity": "sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA==", + "requires": { + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "debug": "~4.1.0", + "engine.io-parser": "~2.2.0", + "ws": "~7.4.2" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ws": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==" + } + } + }, + "engine.io-client": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.1.tgz", + "integrity": "sha512-oVu9kBkGbcggulyVF0kz6BV3ganqUeqXvD79WOFKa+11oK692w1NyFkuEj4xrkFRpZhn92QOqTk4RQq5LiBXbQ==", + "requires": { + "component-emitter": "~1.3.0", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.2.0", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "ws": "~7.4.2", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "ws": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==" + } + } + }, + "engine.io-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz", + "integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.4", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" } }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, "event-stream": { "version": "3.3.4", @@ -329,15 +1077,20 @@ "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { - "duplexer": "0.1.1", - "from": "0.1.7", - "map-stream": "0.1.0", + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", "pause-stream": "0.0.11", - "split": "0.3.3", - "stream-combiner": "0.0.4", - "through": "2.3.8" + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" } }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", @@ -349,15 +1102,66 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", - "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "follow-redirects": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz", + "integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==" + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -368,17 +1172,38 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" } }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, "from": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", "dev": true }, + "fs-extra": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", + "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^3.0.0", + "universalify": "^0.1.0" + } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, "gdax": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/gdax/-/gdax-0.5.1.tgz", @@ -390,12 +1215,25 @@ "ws": "3.0.0" } }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" }, "dependencies": { "assert-plus": { @@ -405,6 +1243,45 @@ } } }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "requires": { + "ini": "1.3.7" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + }, "har-schema": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", @@ -415,25 +1292,57 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" + "ajv": "^4.9.1", + "har-schema": "^1.0.5" } }, - "has-flag": { + "has-ansi": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", - "dev": true + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } + } + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==" }, "hawk": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" } }, "hoek": { @@ -441,32 +1350,228 @@ "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + } + } + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, "http-signature": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.1", - "sshpk": "1.13.1" + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-proxy-agent": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz", + "integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==", + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" } }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=" + }, + "immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=" + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==" + }, "int": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/int/-/int-0.2.0.tgz", "integrity": "sha1-WJ8FsDuNjAjJGMiIR4TLYqlO9H4=" }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "requires": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + } + }, + "is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-number-like": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-number-like/-/is-number-like-1.0.8.tgz", + "integrity": "sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA==", + "requires": { + "lodash.isfinite": "^3.3.2" + } + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, + "isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==" + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -478,22 +1583,35 @@ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "optional": true }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stable-stringify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "requires": { - "jsonify": "0.0.0" + "jsonify": "~0.0.0" } }, "json-stringify-safe": { @@ -501,6 +1619,14 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, + "jsonfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", + "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, "jsonify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", @@ -524,14 +1650,120 @@ } } }, - "lru-cache": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", - "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", - "dev": true, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "requires": { + "json-buffer": "3.0.0" + } + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "package-json": "^6.3.0" + } + }, + "limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" + }, + "lite-server": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/lite-server/-/lite-server-2.6.1.tgz", + "integrity": "sha512-d3oyB/C8AU4EwYQHlLxcu6vTQDnCaLb81v1KKNYABmFS5oeJ11A+YxlqtpbTclID1AFddJfcB5klf0q98vYIMw==", + "requires": { + "browser-sync": "^2.26.13", + "connect-history-api-fallback": "^1.6.0", + "connect-logger": "^0.0.1", + "lodash": "^4.17.20", + "minimist": "^1.2.5" + } + }, + "localtunnel": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-2.0.1.tgz", + "integrity": "sha512-LiaI5wZdz0xFkIQpXbNI62ZnNn8IMsVhwxHmhA+h4vj8R9JG/07bQHWwQlyy7b95/5fVOCHJfIHv+a5XnkvaJA==", + "requires": { + "axios": "0.21.1", + "debug": "4.3.1", + "openurl": "1.1.1", + "yargs": "16.2.0" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.isfinite": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", + "integrity": "sha1-+4m2WpqAKBgz8LdHizpRBPiY67M=" + }, + "lodash.zipobject": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lodash.zipobject/-/lodash.zipobject-4.1.3.tgz", + "integrity": "sha1-s5n1q6j/YqdG9peb8gshT5ZNvvg=" + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } } }, "map-stream": { @@ -540,6 +1772,20 @@ "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", "dev": true }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, "mime-db": { "version": "1.30.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", @@ -550,27 +1796,71 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", "requires": { - "mime-db": "1.30.0" + "mime-db": "~1.30.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" } }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mitt": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-1.2.0.tgz", + "integrity": "sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw==" + }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, "node-binance-api": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/node-binance-api/-/node-binance-api-0.4.8.tgz", - "integrity": "sha512-5JBmRIBxuKtyQzAJ6iHB8h72rEWUfGmAqCV3gRS6Z9TMH56uAFnwYpRMbDLfqIGR7iDSgV3NZ2KtSchG/MyrdA==", + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/node-binance-api/-/node-binance-api-0.12.5.tgz", + "integrity": "sha512-tapf/OCGaMiHrfvOgPu67osXwq03jFq+WtKgDB0XR6uRvSnOf+fMWMsnbyioHcJSXpd3sdcyR5VkjPGZmkUuHw==", "requires": { - "request": "2.83.0", - "ws": "3.3.3" + "async": "^3.1.0", + "https-proxy-agent": "^3.0.1", + "json-bigint": "^1.0.0", + "request": "^2.88.0", + "socks-proxy-agent": "^4.0.2", + "string-hash": "^1.1.3", + "url": "^0.11.0", + "ws": "^7.2.0" }, "dependencies": { "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.0.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "assert-plus": { @@ -583,40 +1873,32 @@ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, - "boom": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", - "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", - "requires": { - "hoek": "4.2.0" - } + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, - "cryptiles": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "requires": { - "boom": "5.2.0" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.2.0" - } - } + "delayed-stream": "~1.0.0" } }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "form-data": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", - "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" } }, "har-schema": { @@ -625,99 +1907,170 @@ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "requires": { - "ajv": "5.5.2", - "har-schema": "2.0.0" + "ajv": "^6.12.3", + "har-schema": "^2.0.0" } }, - "hawk": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", - "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", - "requires": { - "boom": "4.3.1", - "cryptiles": "3.1.2", - "hoek": "4.2.0", - "sntp": "2.1.0" - } - }, - "hoek": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", - "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==" - }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.13.1" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, + "mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==" + }, + "mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "requires": { + "mime-db": "1.46.0" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "request": { - "version": "2.83.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", - "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", - "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.3.1", - "har-validator": "5.0.3", - "hawk": "6.0.2", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.17", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.1", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.3", - "tunnel-agent": "0.6.0", - "uuid": "3.2.1" - } - }, - "sntp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", - "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "requires": { - "hoek": "4.2.0" + "psl": "^1.1.28", + "punycode": "^2.1.1" } }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, "ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==" + } + } + }, + "node-cleanup": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz", + "integrity": "sha1-esGavSl+Caf3KnFUXZUbUX5N3iw=", + "dev": true + }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, + "nodemon": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.7.tgz", + "integrity": "sha512-XHzK69Awgnec9UzHr1kc8EomQh4sjTQ8oRf8TsGrSmHDx9/UmiGG9E/mM3BuTfNeFwdNBvrqQq/RHL0xIeyFOA==", + "requires": { + "chokidar": "^3.2.2", + "debug": "^3.2.6", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.7", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.3", + "update-notifier": "^4.1.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "async-limiter": "1.0.0", - "safe-buffer": "5.1.1", - "ultron": "1.1.1" + "has-flag": "^3.0.0" } } } }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==" + }, "num": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/num/-/num-0.3.0.tgz", @@ -731,10 +2084,104 @@ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=" + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "openurl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.1.tgz", + "integrity": "sha1-OHW0sO96UsFW8NtB1GCduw+Us4c=" + }, + "opn": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", + "integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==", + "requires": { + "is-wsl": "^1.1.0" + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "parseqs": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" + }, + "parseuri": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true }, "pause-stream": { "version": "0.0.11", @@ -742,7 +2189,7 @@ "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", "dev": true, "requires": { - "through": "2.3.8" + "through": "~2.3" } }, "performance-now": { @@ -750,66 +2197,232 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" }, - "ps-tree": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.1.0.tgz", - "integrity": "sha1-tCGyQUDWID8e08dplrRCewjowBQ=", - "dev": true, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" + }, + "portscanner": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.1.1.tgz", + "integrity": "sha1-6rtAnk3iSVD1oqUW01rnaTQ/u5Y=", "requires": { - "event-stream": "3.3.4" + "async": "1.5.2", + "is-number-like": "^1.0.3" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + } } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" + }, + "prettier": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", "dev": true }, + "ps-tree": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz", + "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==", + "dev": true, + "requires": { + "event-stream": "=3.3.4" + } + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "requires": { + "escape-goat": "^2.0.0" + } + }, "qs": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", + "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.3", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "reconnecting-websocket": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz", + "integrity": "sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==" + }, + "registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "requires": { + "rc": "^1.2.8" + } + }, "request": { "version": "2.81.0", "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.17", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.3", - "tunnel-agent": "0.6.0", - "uuid": "3.2.1" + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.1.1", + "har-validator": "~4.2.1", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "oauth-sign": "~0.8.1", + "performance-now": "^0.2.0", + "qs": "~6.4.0", + "safe-buffer": "^5.0.1", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.0.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "resp-modifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/resp-modifier/-/resp-modifier-6.0.2.tgz", + "integrity": "sha1-sSTeXE+6/LpUH0j/pzlw9KpFa08=", + "requires": { + "debug": "^2.2.0", + "minimatch": "^3.0.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } } }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=" + }, "rxjs": { - "version": "5.5.6", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.6.tgz", - "integrity": "sha512-v4Q5HDC0FHAQ7zcBX7T2IL6O5ltl1a2GX4ENjPXg6SjDY69Cmx9v4113C99a4wGF16ClPv5Z8mghuYorVkg/kg==", + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", "requires": { - "symbol-observable": "1.0.1" + "tslib": "^1.9.0" } }, "safe-buffer": { @@ -817,32 +2430,338 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + } + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + } + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0=" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^3.0.0" } }, "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, "slack-webhook": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slack-webhook/-/slack-webhook-1.0.0.tgz", "integrity": "sha1-8K0bc/J4oU6KsUG5VV9BWdVgXzg=" }, + "smart-buffer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", + "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==" + }, "sntp": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", "requires": { - "hoek": "2.16.3" + "hoek": "2.x.x" + } + }, + "socket.io": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.4.0.tgz", + "integrity": "sha512-9UPJ1UTvKayuQfVv2IQ3k7tCQC/fboDyIK62i99dAQIyHKaBsNdTpwHLgKJ6guRWxRtC9H+138UwpaGuQO9uWQ==", + "requires": { + "debug": "~4.1.0", + "engine.io": "~3.5.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.4.0", + "socket.io-parser": "~3.4.0" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "socket.io-parser": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz", + "integrity": "sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~4.1.0", + "isarray": "2.0.1" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", + "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==" + }, + "socket.io-client": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.4.0.tgz", + "integrity": "sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==", + "requires": { + "backo2": "1.0.2", + "component-bind": "1.0.0", + "component-emitter": "~1.3.0", + "debug": "~3.1.0", + "engine.io-client": "~3.5.0", + "has-binary2": "~1.0.2", + "indexof": "0.0.1", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "socket.io-parser": "~3.3.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "socket.io-parser": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.2.tgz", + "integrity": "sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==", + "requires": { + "component-emitter": "~1.3.0", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "socks": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", + "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", + "requires": { + "ip": "1.1.5", + "smart-buffer": "^4.1.0" + } + }, + "socks-proxy-agent": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", + "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", + "requires": { + "agent-base": "~4.2.1", + "socks": "~2.3.2" + }, + "dependencies": { + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "requires": { + "es6-promisify": "^5.0.0" + } + } } }, "split": { @@ -851,7 +2770,7 @@ "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", "dev": true, "requires": { - "through": "2.3.8" + "through": "2" } }, "sshpk": { @@ -859,14 +2778,14 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "tweetnacl": "~0.14.0" }, "dependencies": { "assert-plus": { @@ -876,13 +2795,48 @@ } } }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, "stream-combiner": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", "dev": true, "requires": { - "duplexer": "0.1.1" + "duplexer": "~0.1.1" + } + }, + "stream-throttle": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/stream-throttle/-/stream-throttle-0.1.3.tgz", + "integrity": "sha1-rdV8jXzHOoFjDTHNVdOWHPr7qcM=", + "requires": { + "commander": "^2.2.0", + "limiter": "^1.0.5" + } + }, + "string-argv": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.1.2.tgz", + "integrity": "sha512-mBqPGEOMNJKXRo7z0keX0wlAhbBAjilUdPW13nN0PecVryZxdHIeM7TqbsSUA7VYuS00HGC6mojP7DlQzfa9ZA==", + "dev": true + }, + "string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=" + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" } }, "stringstream": { @@ -890,52 +2844,112 @@ "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" }, - "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", - "dev": true, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "requires": { - "has-flag": "2.0.0" + "ansi-regex": "^5.0.0" } }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, "symbol-observable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=" }, + "term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==" + }, + "tfunk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tfunk/-/tfunk-4.0.0.tgz", + "integrity": "sha512-eJQ0dGfDIzWNiFNYFVjJ+Ezl/GmwHaFTBTjrtqNPW0S7cuVDBrZrmzUz6VkMeCR4DZFqhd4YtLwsw3i2wYHswQ==", + "requires": { + "chalk": "^1.1.3", + "dlv": "^1.1.3" + } + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "requires": { + "nopt": "~1.0.10" + } + }, "tough-cookie": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", "requires": { - "punycode": "1.4.1" + "punycode": "^1.4.1" } }, "tsc-watch": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/tsc-watch/-/tsc-watch-1.0.16.tgz", - "integrity": "sha512-Z7nRyZQOmyHheMfqKT7+QXZPZR2F07w8KBvDZJuibAlsLPIWjkcyt+gh1R/pT6Zze7bSkfWt0+UjiSvyaM38VQ==", + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/tsc-watch/-/tsc-watch-4.2.9.tgz", + "integrity": "sha512-DlTaoDs74+KUpyWr7dCGhuscAUKCz6CiFduBN7R9RbLJSSN1moWdwoCLASE7+zLgGvV5AwXfYDiEMAsPGaO+Vw==", "dev": true, "requires": { - "chalk": "2.3.0", - "cross-spawn": "5.1.0", - "ps-tree": "1.1.0", - "typescript": "2.7.1" + "cross-spawn": "^7.0.3", + "node-cleanup": "^2.1.2", + "ps-tree": "^1.2.0", + "string-argv": "^0.1.1", + "strip-ansi": "^6.0.0" } }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { @@ -944,17 +2958,171 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "optional": true }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.1.tgz", - "integrity": "sha512-bqB1yS6o9TNA9ZC/MJxM0FZzPnZdtHj0xWK/IZ5khzVqdpGul/R/EIiHRgFXlwTD7PSIaYVnGKq1QgMCu2mnqw==", - "dev": true + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==" + }, + "ua-parser-js": { + "version": "0.7.26", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.26.tgz", + "integrity": "sha512-VwIvGlFNmpKbjzRt51jpbbFTrKIEgGHxIwA8Y69K1Bqc6bTIV7TaGGABOkghSFQWsLmcRB4drGvpfv9z2szqoQ==" }, "ultron": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" }, + "undefsafe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", + "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", + "requires": { + "debug": "^2.2.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "requires": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + } + } + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "requires": { + "prepend-http": "^2.0.0" + } + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, "uuid": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", @@ -965,9 +3133,9 @@ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "requires": { - "assert-plus": "1.0.0", + "assert-plus": "^1.0.0", "core-util-is": "1.0.2", - "extsprintf": "1.3.0" + "extsprintf": "^1.2.0" }, "dependencies": { "assert-plus": { @@ -977,13 +3145,67 @@ } } }, + "whatwg-fetch": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + }, "which": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "requires": { + "string-width": "^4.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } }, "ws": { @@ -991,8 +3213,8 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-3.0.0.tgz", "integrity": "sha1-mN2wAFbIOQy3Ued4h4hJf5kQO2w=", "requires": { - "safe-buffer": "5.0.1", - "ultron": "1.1.1" + "safe-buffer": "~5.0.1", + "ultron": "~1.1.0" }, "dependencies": { "safe-buffer": { @@ -1002,11 +3224,92 @@ } } }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "y18n": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", + "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==" + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==" + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "yargs-parser": { + "version": "20.2.7", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", + "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==" + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" } } } diff --git a/package.json b/package.json index aeefce4..8482e11 100644 --- a/package.json +++ b/package.json @@ -5,27 +5,33 @@ "main": "index.js", "scripts": { "build": "tsc", - "docker:build": "docker build -t theddy .", - "docker:run": "docker run -it --env-file envfile -p 3000:3000 theddy", - "start": "node ./dist/index.js", "build:start": "npm run build && npm start", "build:start:scratch": "rm -f data.json && npm run build:start", "chart": "lite-server", - "watch": "tsc-watch --onSuccess \"nodemon -w dist/ dist/index.js\"" + "docker:build": "docker build -t theddy .", + "docker:run": "docker run -it --env-file .env -p 3000:3000 theddy", + "load:env-var": "set -o allexport; source .env; set +o allexport", + "start": "node ./dist/index.js", + "dev": "tsc-watch --onSuccess \"nodemon -w dist/ dist/index.js\"" }, "keywords": [], "author": "", "license": "MIT", "dependencies": { - "delay": "^2.0.0", + "binance-api-node": "^0.10.34", + "delay": "^5.0.0", "gdax": "^0.5.1", - "node-binance-api": "^0.4.8", - "rxjs": "^5.5.6", - "slack-webhook": "^1.0.0" + "lite-server": "^2.6.1", + "node-binance-api": "^0.12.5", + "nodemon": "^2.0.7", + "rxjs": "^6.6.7", + "slack-webhook": "^1.0.0", + "typescript": "^4.2.3" }, "devDependencies": { - "@types/node": "^8.5.2", - "@types/rx": "^4.1.1", - "tsc-watch": "^1.0.13" + "@types/node": "^14.14.37", + "@types/rx": "^4.1.2", + "prettier": "^2.2.1", + "tsc-watch": "^4.2.9" } -} \ No newline at end of file +} diff --git a/src/config/config.binance.ts b/src/config/config.binance.ts index aa66403..b7d9fb7 100644 --- a/src/config/config.binance.ts +++ b/src/config/config.binance.ts @@ -1,64 +1,64 @@ -import { Config } from '../typings'; -import { Currency } from '../vendor/interfaces/currency.enum'; -import { Smoothing } from '../vendor/chart/smoothing'; -import { Platform } from './platform'; +import { Config } from "../typings" +import { Smoothing } from "../vendor/chart/smoothing" +import { Currency } from "../vendor/interfaces/currency.enum" +import { Platform } from "./platform" const binanceConfig: Config = { - app: { - debug: true, - platform: Platform.BINANCE - }, - network: { - retryIntervalWhenConnectionIsLost: 3000 // ms - }, - api: { - sandbox: true - }, - trader: { - // Quantities strategy - quantityOfBaseCurrencyToUse: 100, // in % (BTC, ETH, LTC, ...) - quantityOfQuoteCurrencyToUse: 100, // in % (€, $) - maxQuantityQuoteCurrencyToUse: 0.0022, // 100€, 100 BTC (max quantity) - minQuantityQuoteCurrencyToUse: 0.001, // 50€, 50 BTC - - // Probitability strategy & exit strategies + app: { + debug: true, + platform: Platform.BINANCE, + }, + network: { + retryIntervalWhenConnectionIsLost: 3000, // ms + }, + api: { + sandbox: true, + }, + trader: { + // Quantities strategy + quantityOfBaseCurrencyToUse: 100, // in % (BTC, ETH, LTC, ...) + quantityOfQuoteCurrencyToUse: 100, // in % (€, $) + maxQuantityQuoteCurrencyToUse: 0.0022, // 100€, 100 BTC (max quantity) + minQuantityQuoteCurrencyToUse: 0.001, // 50€, 50 BTC - // Max threshold - sellWhenPriceExceedsMaxThresholdOfProfitability: true, - maxThresholdOfProfitability: 0.8, // in % - - // Min threshold - sellWhenPriceExceedsMinThresholdOfProfitability: true, - minThresholdOfProfitability: 0.4, // how many % profitability wanted when selling - quantityToSellWhenPriceExceedsMinThresholdOfProfitability: 30, // in % + // Probitability strategy & exit strategies - useExitStrategyInCaseOfLosses: true, - sellWhenLossRateReaches: 1 // in % - }, - market: { - currency: Currency.BCPTBTC, - orderFees: 0.0003 // <=> 0.1% - }, - account: { - quoteCurrency: Currency.BTC, // €, $, BTC - baseCurrency: Currency.BCPT // BTC, ETH, LTC, ... - }, - chart: { - tickerInterval: 1000 * 30, // ms - reductionOfTheTickerIntervalOnSpeedMode: 0.5, // <=> we reduce by 50% the ticker interval + // Max threshold + sellWhenPriceExceedsMaxThresholdOfProfitability: true, + maxThresholdOfProfitability: 0.8, // in % - minPriceDifferenceToApproveNewPoint: 0.1, // in %. <=> 0.1% - smoothing: Smoothing.MOVING_AVERAGE, + // Min threshold + sellWhenPriceExceedsMinThresholdOfProfitability: true, + minThresholdOfProfitability: 0.4, // how many % profitability wanted when selling + quantityToSellWhenPriceExceedsMinThresholdOfProfitability: 30, // in % - // Pump & dump - thresholdRateToApproveInversion: 0.6, // in % (Pump/Dump) - thresholdMaxRateToApproveInversion: 1, // in % (Pump/Dump) - numberOfUpPointsToValidatePump: 3, - numberOfDownPointsToValidateDump: 3, - validatePumpWhenBigPumpIsDetected: false, - ignoreBigPumpWhenBuying: true, // when price rate between two points exceeds thresholdMaxRateToApproveInversion - validateDumpWhenBigDumpIsDetected: false - } + useExitStrategyInCaseOfLosses: true, + sellWhenLossRateReaches: 1, // in % + }, + market: { + currency: (process.env.MARKET_CURRENCY ?? Currency.BTC_EUR) as Currency, + orderFees: 0.0003, // <=> 0.1% + }, + account: { + quoteCurrency: (process.env.QUOTE_CURRENCY ?? Currency.EUR) as Currency, // €, $, BTC + baseCurrency: (process.env.BASE_CURRENCY ?? Currency.BTC) as Currency, // BTC, ETH, LTC, ... + }, + chart: { + tickerInterval: 1000 * 30, // ms + reductionOfTheTickerIntervalOnSpeedMode: 0.5, // <=> we reduce by 50% the ticker interval + + minPriceDifferenceToApproveNewPoint: 0.1, // in %. <=> 0.1% + smoothing: Smoothing.MOVING_AVERAGE, + + // Pump & dump + thresholdRateToApproveInversion: 0.6, // in % (Pump/Dump) + thresholdMaxRateToApproveInversion: 1, // in % (Pump/Dump) + numberOfUpPointsToValidatePump: 3, + numberOfDownPointsToValidateDump: 3, + validatePumpWhenBigPumpIsDetected: false, + ignoreBigPumpWhenBuying: true, // when price rate between two points exceeds thresholdMaxRateToApproveInversion + validateDumpWhenBigDumpIsDetected: false, + }, } export default binanceConfig diff --git a/src/config/config.gdax.ts b/src/config/config.gdax.ts index dab5cd3..d6dfa29 100644 --- a/src/config/config.gdax.ts +++ b/src/config/config.gdax.ts @@ -1,64 +1,64 @@ -import { Config } from '../typings'; -import { Currency } from '../vendor/interfaces/currency.enum'; -import { Smoothing } from '../vendor/chart/smoothing'; -import { Platform } from './platform'; +import { Config } from "../typings" +import { Currency } from "../vendor/interfaces/currency.enum" +import { Smoothing } from "../vendor/chart/smoothing" +import { Platform } from "./platform" const gdaxConfig: Config = { - app: { - debug: true, - platform: Platform.GDAX - }, - network: { - retryIntervalWhenConnectionIsLost: 5000 // ms - }, - api: { - uri: 'https://api.gdax.com', - websocketURI: 'wss://ws-feed.gdax.com', - sandboxWebsocketURI: 'wss://ws-feed-public.sandbox.gdax.com', - sandboxURI: 'https://api-public.sandbox.gdax.com', - sandbox: false - }, - trader: { - // Quantities strategy - quantityOfBaseCurrencyToUse: 100, // in % (BTC, ETH, LTC, ...) + app: { + debug: true, + platform: Platform.GDAX, + }, + network: { + retryIntervalWhenConnectionIsLost: 5000, // ms + }, + api: { + uri: "https://api.gdax.com", + websocketURI: "wss://ws-feed.gdax.com", + sandboxWebsocketURI: "wss://ws-feed-public.sandbox.gdax.com", + sandboxURI: "https://api-public.sandbox.gdax.com", + sandbox: false, + }, + trader: { + // Quantities strategy + quantityOfBaseCurrencyToUse: 100, // in % (BTC, ETH, LTC, ...) - quantityOfQuoteCurrencyToUse: 100, // in % (€, $) - maxQuantityQuoteCurrencyToUse: 0.0022, // 100€, 100 BTC (max quantity) - minQuantityQuoteCurrencyToUse: 0.001, // 50€, 50 BTC - - // Probitability strategy & exit strategies - sellWhenPriceExceedsMaxThresholdOfProfitability: true, - sellWhenPriceExceedsMinThresholdOfProfitability: true, - quantityToSellWhenPriceExceedsMinThresholdOfProfitability: 30, // in % - maxThresholdOfProfitability: 2, // in % - minThresholdOfProfitability: 0.5, // in %. How many % profitability wanted when selling - useExitStrategyInCaseOfLosses: true, - sellWhenLossRateReaches: 10 // in % - }, - market: { - currency: Currency.BTC_EUR, - orderFees: 0.001 // <=> 0.1% - }, - account: { - quoteCurrency: Currency.EUR, // €, $, BTC - baseCurrency: Currency.BTC // BTC, ETH, LTC, ... - }, - chart: { - tickerInterval: 1000 * 15, // ms - reductionOfTheTickerIntervalOnSpeedMode: 0.5, // <=> we reduce by 50% the ticker interval + quantityOfQuoteCurrencyToUse: 100, // in % (€, $) + maxQuantityQuoteCurrencyToUse: 0.0022, // 100€, 100 BTC (max quantity) + minQuantityQuoteCurrencyToUse: 0.001, // 50€, 50 BTC - minPriceDifferenceToApproveNewPoint: 0.07, // <=> 0.1% - smoothing: Smoothing.SAMPLE, + // Probitability strategy & exit strategies + sellWhenPriceExceedsMaxThresholdOfProfitability: true, + sellWhenPriceExceedsMinThresholdOfProfitability: true, + quantityToSellWhenPriceExceedsMinThresholdOfProfitability: 30, // in % + maxThresholdOfProfitability: 2, // in % + minThresholdOfProfitability: 0.5, // in %. How many % profitability wanted when selling + useExitStrategyInCaseOfLosses: true, + sellWhenLossRateReaches: 10, // in % + }, + market: { + currency: Currency.BTC_EUR, + orderFees: 0.001, // <=> 0.1% + }, + account: { + quoteCurrency: Currency.EUR, // €, $, BTC + baseCurrency: Currency.BTC, // BTC, ETH, LTC, ... + }, + chart: { + tickerInterval: 1000 * 15, // ms + reductionOfTheTickerIntervalOnSpeedMode: 0.5, // <=> we reduce by 50% the ticker interval - // Pump & dump - thresholdRateToApproveInversion: 1, // in % - thresholdMaxRateToApproveInversion: 2, // in % - numberOfUpPointsToValidatePump: 3, - numberOfDownPointsToValidateDump: 3, - validatePumpWhenBigPumpIsDetected: true, - ignoreBigPumpWhenBuying: true, - validateDumpWhenBigDumpIsDetected: false - } + minPriceDifferenceToApproveNewPoint: 0.07, // <=> 0.1% + smoothing: Smoothing.SAMPLE, + + // Pump & dump + thresholdRateToApproveInversion: 1, // in % + thresholdMaxRateToApproveInversion: 2, // in % + numberOfUpPointsToValidatePump: 3, + numberOfDownPointsToValidateDump: 3, + validatePumpWhenBigPumpIsDetected: true, + ignoreBigPumpWhenBuying: true, + validateDumpWhenBigDumpIsDetected: false, + }, } -export default gdaxConfig \ No newline at end of file +export default gdaxConfig diff --git a/src/config/index.ts b/src/config/index.ts index f2e69b9..e851e08 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -1,6 +1,13 @@ -import { Config } from "../typings"; -import { Platform } from './platform'; +import { Config } from "../typings" +import binanceConfig from "./config.binance" +import gdaxConfig from "./config.gdax" +import { Platform } from "./platform" -const platform = Platform.BINANCE +const platform = process.env.PLATFORM ?? Platform.BINANCE -export const config: Config = require(`./config.${platform}`).default \ No newline at end of file +export const config: Config = + platform === Platform.BINANCE + ? binanceConfig + : platform === Platform.GDAX + ? gdaxConfig + : null diff --git a/src/config/platform.ts b/src/config/platform.ts index 0534892..ee36550 100644 --- a/src/config/platform.ts +++ b/src/config/platform.ts @@ -1,4 +1,4 @@ export enum Platform { - GDAX = 'gdax', - BINANCE = 'binance' -} \ No newline at end of file + GDAX = "gdax", + BINANCE = "binance", +} diff --git a/src/index.ts b/src/index.ts index 0d6f7e6..effd596 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,20 +1,28 @@ -import './rxjs.extensions' -import Trader from './vendor/trader/index'; -import {  config } from './config'; -import { Platform } from './config/platform'; -import Market from './vendor/interfaces/market'; -import Slack from './vendor/slack/index'; +import { config } from "./config" +import { Platform } from "./config/platform" +import BinanceMarket from "./markets/binance" +import GdaxMarket from "./markets/gdax" +import "./rxjs.extensions" +import Market from "./vendor/interfaces/market" +import Trader from "./vendor/trader/index" async function start() { - // Load market - const market: Market = new (require(`./markets/${config.app.platform}`).default)() + // Load market + if (!Object.values(Platform).includes(config.app.platform)) { + throw new Error(`Invalid market platform: ${config.app.platform}`) + } - await market.init() + const market: Market = + config.app.platform === Platform.BINANCE + ? new BinanceMarket() + : new GdaxMarket() - // Make trader trade - const trader = new Trader(market) + await market.init() - trader.trade() + // Make trader trade + const trader = new Trader(market) + + trader.trade() } -start() \ No newline at end of file +start() diff --git a/src/markets/binance/accounts.ts b/src/markets/binance/accounts.ts index a2c0c97..f8b267d 100644 --- a/src/markets/binance/accounts.ts +++ b/src/markets/binance/accounts.ts @@ -1,29 +1,26 @@ -import Market from '../../vendor/interfaces/market'; -import * as Gdax from 'gdax'; -import { Currency } from '../../vendor/interfaces/currency.enum'; -import { Account, CoinbaseAccount } from 'gdax'; -import { Accounts } from '../../vendor/market/accounts'; -import { promisify } from 'util'; +import { Binance } from "binance-api-node" +import { Currency } from "../../vendor/interfaces/currency.enum" +import { Accounts } from "../../vendor/market/accounts" class BinanceAccounts implements Accounts { - allMarketAccounts: any[] + client: Binance - client: any + constructor(client: Binance) { + this.client = client + } - constructor(client: Gdax.AuthenticatedClient) { - this.client = client - } - - async availableFunds(currency: Currency): Promise { - const getBalances = promisify(this.client.balance) - const balances = await getBalances() + async availableFunds(currency: Currency): Promise { + const { balances } = await this.client.accountInfo() + const currencyBalance = balances.find( + (balance) => balance.asset === currency + ) - if (!balances[currency]) { - throw new Error(`Currency ${currency} was not found in the balances`) - } - - return parseFloat(balances[currency].available) + if (!currencyBalance) { + throw new Error(`Currency ${currency} was not found in the balances`) } + + return parseFloat(currencyBalance.free) + } } -export default BinanceAccounts \ No newline at end of file +export default BinanceAccounts diff --git a/src/markets/binance/index.ts b/src/markets/binance/index.ts index 73e735f..4d7d9e8 100644 --- a/src/markets/binance/index.ts +++ b/src/markets/binance/index.ts @@ -1,89 +1,83 @@ -import * as binance from 'node-binance-api'; -import BinanceAccounts from './accounts'; -import BinanceOrders from './orders'; -import Logger from '../../vendor/logger/index'; -import Market from '../../vendor/interfaces/market'; -import Orders from '../../vendor/market/orders'; -import { Accounts } from '../../vendor/market/accounts'; -import { config } from '../../config'; -import { Currency } from '../../vendor/interfaces/currency.enum'; -import { CurrencyInfo } from '../../vendor/market/currency-info'; -import { promisify } from 'util'; -import { Subject } from 'rxjs/Subject'; -import { Subscription } from 'rxjs/Subscription'; +import BinanceService, { Binance } from "binance-api-node" +import { Subject } from "rxjs" +import { config } from "../../config" +import { Currency } from "../../vendor/interfaces/currency.enum" +import Market from "../../vendor/interfaces/market" +import { Accounts } from "../../vendor/market/accounts" +import { CurrencyInfo } from "../../vendor/market/currency-info" +import Orders from "../../vendor/market/orders" +import BinanceAccounts from "./accounts" +import BinanceOrders from "./orders" class BinanceMarket implements Market { - currency: Currency - orders: Orders - accounts: Accounts - publicClient: any - client: any - price$: Subject - lastPrice: number - price: number - sandbox: boolean - lastTicker: any - initialized: boolean - currencyInfo: CurrencyInfo - - constructor() { - this.currency = config.market.currency - this.sandbox = config.api.sandbox - this.price$ = new Subject() + currency: Currency + orders: Orders + accounts: Accounts + publicClient: any + client: Binance + price$: Subject + lastPrice: number + price: number + sandbox: boolean + lastTicker: any + initialized: boolean + currencyInfo: CurrencyInfo + + constructor() { + this.currency = config.market.currency + this.sandbox = config.api.sandbox + this.price$ = new Subject() + } + + async init() { + this.client = BinanceService({ + apiKey: process.env.BINANCE_API_KEY, + apiSecret: process.env.BINANCE_API_SECRET, + }) + this.orders = new BinanceOrders(this.client, this) + this.accounts = new BinanceAccounts(this.client) + + await this.loadCurrencyInfo() + + this.initialized = true + } + + async ping() { + // TODO: implement ping test here + return true + } + + watchCurrencyPrice() { + throw new Error( + "BinanceMarket #watchCurrencyPrice() method is not implemented" + ) + } + + async getCurrencyPrice() { + if (!this.initialized) { + throw new Error( + "BinanceMarket #getCurrencyPrice() cannot be used without being initialized" + ) } - async init() { - this.client = binance - this.orders = new BinanceOrders(this.client, this) - this.accounts = new BinanceAccounts(this.client) - - this.client.options({ - APIKEY: process.env.BINANCE_API_KEY, - APISECRET: process.env.BINANCE_API_SECRET, - useServerTime: true, // If you get timestamp errors, synchronize to server time at startup - test: config.api.sandbox - }) + this.lastTicker = await this.client.prices({ symbol: this.currency }) - await this.loadCurrencyInfo() - - this.initialized = true - } + const currencyTicker = this.lastTicker[this.currency] - async ping() { - // TODO: implement ping test here - return true - } - - watchCurrencyPrice() { - throw new Error('BinanceMarket #watchCurrencyPrice() method is not implemented') - } - - async getCurrencyPrice() { - if (!this.initialized) { - throw new Error('BinanceMarket #getCurrencyPrice() cannot be used without being initialized') - } - - const prices = promisify(this.client.prices) - - this.lastTicker = await prices(this.currency) - - const currencyTicker = this.lastTicker[this.currency] - - return parseFloat(currencyTicker) - } + return parseFloat(currencyTicker) + } - async loadCurrencyInfo() { - const exchangeInfo = promisify(this.client.exchangeInfo) - const data = await exchangeInfo() + async loadCurrencyInfo() { + const { symbols } = await this.client.exchangeInfo() - for (let currencyInfo of data.symbols) { - if (currencyInfo.symbol === this.currency) { - this.currencyInfo = currencyInfo + for (let symbolData of symbols) { + if (symbolData.symbol === this.currency) { + this.currencyInfo = symbolData - break - } - } + break + } } + } } -export default BinanceMarket \ No newline at end of file +export default BinanceMarket diff --git a/src/markets/binance/orders.ts b/src/markets/binance/orders.ts index 74c20aa..b62edb4 100644 --- a/src/markets/binance/orders.ts +++ b/src/markets/binance/orders.ts @@ -1,257 +1,286 @@ -import * as Gdax from 'gdax'; -import Logger from '../../vendor/logger/index'; -import Market from '../../vendor/interfaces/market'; -import { Currency } from '../../vendor/interfaces/currency.enum'; -import { CurrencyFilter, CurrencyInfo } from '../../vendor/market/currency-info'; -import { LimitOrder } from 'gdax'; -import { OrderResult, OrderFill } from '../../vendor/market/order'; -import { Orders } from '../../vendor/market/orders'; -import { OrderStatus } from '../../vendor/interfaces/order-status.enum'; -import { OrderType } from '../../vendor/interfaces/order-type.enum'; -import { promisify } from 'util'; -import { floatSafeRemainder, truncateLongDigits } from '../../vendor/chart/maths'; -import { config } from '../../config/index'; +import { + Binance, + Order, + SymbolLotSizeFilter, + SymbolMinNotionalFilter, +} from "binance-api-node" +import { config } from "../../config/index" +import { + floatSafeRemainder, + truncateLongDigits, +} from "../../vendor/chart/maths" +import { Currency } from "../../vendor/interfaces/currency.enum" +import Market from "../../vendor/interfaces/market" +import { OrderSide, OrderType } from "../../vendor/interfaces/order-type.enum" +import Logger from "../../vendor/logger/index" +import { CurrencyInfo } from "../../vendor/market/currency-info" +import { OrderResult } from "../../vendor/market/order" +import { Orders } from "../../vendor/market/orders" class BinanceOrders implements Orders { - pending: OrderResult[] = [] - done: OrderResult[] = [] - canceled: OrderResult[] = [] - lastOrder: OrderResult - client: any - market: Market - - constructor(client: any, market: Market) { - this.client = client - this.market = market + pending: Order[] = [] + done: Order[] = [] + canceled: Order[] = [] + lastOrder: Order + client: Binance + market: Market + + constructor(client: Binance, market: Market) { + this.client = client + this.market = market + } + + async all(symbol?: Currency): Promise { + return this.client.allOrders({ + symbol, + useServerTime: true, + }) + } + + buyOrders(): Order[] { + return this.pending.filter((order) => order.side === OrderSide.BUY) + } + + sellOrders(): Order[] { + return this.pending.filter((order) => order.side === OrderSide.SELL) + } + + async buyLimit( + currency: Currency, + quantity: number, + price: number, + allowTaker = false + ) { + return this.lastOrder + } + + async buyMarket(currency: Currency, funds: number, price: number) { + try { + const orderParams = { + symbol: currency, + side: OrderSide.BUY, + type: OrderType.MARKET, + quantity: this.normalizeQuantity(funds / price).toString(), + } + const order = config.api.sandbox + ? await this.fakeOrder(orderParams) + : await this.client.order({ ...orderParams, side: "BUY" }) + + if (!order) { + throw Error( + `Error when trying to buy with a market order: ${JSON.stringify( + order, + null, + 2 + )}` + ) + } + + Logger.debug("Buy response from market") + Logger.debug(JSON.stringify(order, null, 2)) + + this.lastOrder = this.forgeOrder(order) + this.done.push({ ...this.lastOrder }) + + return this.lastOrder + } catch (error) { + Logger.error(error.toJSON ? error.toJSON() : error) } - - async all(): Promise { - const orders: OrderResult[] = await this.client.getOrders() - - return orders - } - - buyOrders(): OrderResult[] { - return this.pending.filter(order => order.side === OrderType.BUY) - } - - sellOrders(): OrderResult[] { - return this.pending.filter(order => order.side === OrderType.SELL) + } + + async buyStop( + currency: Currency, + price: number, + funds: number = null + ): Promise { + throw new Error("BinancerOrder#buyStop() method not implemented.") + } + + async sellLimit( + currency: Currency, + quantity: number, + price: number, + allowTaker = false + ): Promise { + throw new Error("BinancerOrder#sellLimit() method not implemented.") + } + + async sellMarket(currency: Currency, size: number): Promise { + const orderParams = { + symbol: currency, + side: OrderSide.SELL, + type: OrderType.MARKET, + quantity: this.normalizeQuantity(size).toString(), } - - async buyLimit(currency: Currency, quantity: number, price: number, allowTaker = false): Promise { - return this.lastOrder - } - - async buyMarket(currency: Currency, funds: number, marketPrice: number): Promise { - const buy = config.api.sandbox ? this.fakeBuyMarket : promisify(this.client.marketBuy) - - try { - const quantity = this.normalizeQuantity(funds / marketPrice) - const response = await buy(currency, quantity, { newOrderRespType: 'FULL' }) - - if (!response) { - throw Error(`Error when trying to buy with a market order: ${JSON.stringify(response, null, 2)}`) - } - - Logger.debug('Buy response from market') - Logger.debug(JSON.stringify(response, null, 2)) - - this.lastOrder = this.forgeOrderResult(response) - this.lastOrder.price = this.computeFillsWeightedAveragePrice(this.lastOrder) - this.done.push({ ...this.lastOrder }) - - return this.lastOrder - } catch (error) { - Logger.error(error.toJSON ? error.toJSON() : error) - } + const order = config.api.sandbox + ? await this.fakeOrder(orderParams) + : await this.client.order({ ...orderParams, side: "SELL" }) + + if (!order) { + throw Error( + `Error when trying to sell with a market order: ${JSON.stringify( + order, + null, + 2 + )}` + ) } - async buyStop(currency: Currency, price: number, funds: number = null): Promise { - return this.lastOrder + Logger.debug("Sell response from market") + Logger.debug(JSON.stringify(order, null, 2)) + + this.lastOrder = order + this.done.push({ ...this.lastOrder }) + + return this.lastOrder + } + + async sellStop( + currency: Currency, + price: number, + size: number + ): Promise { + return this.lastOrder + } + + cancel(order: Order) { + this.pending = this.pending.filter( + (current) => current.orderId !== order.orderId + ) + this.canceled.push(order) + + return this.client.cancelOrder({ + symbol: order.symbol, + orderId: order.orderId, + useServerTime: true, + }) + } + + normalizeQuantity(quantity: number): number { + const currencyInfo: CurrencyInfo = this.market.currencyInfo + const currencyLotSizeFilter = this.getLotSizeFilter(currencyInfo) + const currencyMinNotionalFilter = this.getMinNotionalFilter(currencyInfo) + const minQuantity = parseFloat(currencyLotSizeFilter.minQty) + const maxQuantity = parseFloat(currencyLotSizeFilter.maxQty) + const stepSize = parseFloat(currencyLotSizeFilter.stepSize) + const minNotional = parseFloat(currencyMinNotionalFilter.minNotional) + const numberOfDigits = Number(currencyInfo.baseAssetPrecision) + + quantity = truncateLongDigits(quantity, numberOfDigits) + + if (quantity < minQuantity) { + if (config.api.sandbox) { + // in sandbox mode we do not throw an error, we just notify and set to minQuantity + quantity = minQuantity + Logger.debug( + `Quantity is below the minQuantity, but in sandbox mode this error can be ignored.` + ) + } else { + throw new Error( + `Cannot normalize quantity, the quantity is below the minQuantity (quantity: ${quantity}, minQuantity: ${minQuantity})` + ) + } } - async sellLimit(currency: Currency, quantity: number, price: number, allowTaker = false): Promise { - return this.lastOrder + if (floatSafeRemainder(quantity, stepSize) !== 0) { + // floatSafeRemainder => reel js remainder + Logger.debug( + `Remove remainder from quantity with step size. Quantity: ${quantity} ; stepSize: ${stepSize} ; quantity after remainder: ${Number( + quantity - floatSafeRemainder(quantity, stepSize) + ).toFixed(numberOfDigits)}` + ) + quantity = parseFloat( + Number(quantity - floatSafeRemainder(quantity, stepSize)).toFixed( + numberOfDigits + ) + ) } - async sellMarket(currency: Currency, size: number): Promise { - const sell = config.api.sandbox ? this.fakeSellMarket : promisify(this.client.marketSell) - const quantity = this.normalizeQuantity(size) - const response = await sell(currency, quantity, { newOrderRespType: 'FULL' }) - - if (!response) { - throw Error(`Error when trying to sell with a market order: ${JSON.stringify(response, null, 2)}`) - } - - Logger.debug('Sell response from market') - Logger.debug(JSON.stringify(response, null, 2)) - - this.lastOrder = this.forgeOrderResult(response) - this.lastOrder.price = this.computeFillsWeightedAveragePrice(this.lastOrder) - this.done.push({ ...this.lastOrder }) - - return this.lastOrder + if (quantity > maxQuantity) { + quantity = maxQuantity } - async sellStop(currency: Currency, price: number, size: number): Promise { - return this.lastOrder + const normalizedQuantity = truncateLongDigits(quantity, numberOfDigits) + + Logger.debug(`Quantity normalized: ${normalizedQuantity}`) + + return normalizedQuantity + } + + getMinQuantity(): number { + const currencyLotSizeFilter = this.getLotSizeFilter( + this.market.currencyInfo + ) + + return parseFloat(currencyLotSizeFilter.minQty) + } + + private async fakeOrder({ + symbol, + side, + quantity, + price, + type, + }: { + symbol: Currency + side: OrderSide + quantity: string + price?: string + type?: OrderType + }): Promise { + return { + symbol, + clientOrderId: "fake", + cummulativeQuoteQty: "", + orderId: 0, + orderListId: 0, + transactTime: Date.now(), + price: price ?? "0.00000000", + origQty: quantity, + executedQty: quantity, + status: "FILLED", + timeInForce: "GTC", + type, + side: side === OrderSide.BUY ? "BUY" : "SELL", } - - cancel(order: OrderResult) { - this.pending = this.pending.filter(current => current.id !== order.id) - this.canceled.push(order) - - return this.client.cancelOrder(order.id) + } + + private getLotSizeFilter(currencyInfo: CurrencyInfo): SymbolLotSizeFilter { + return currencyInfo.filters.find( + (filter) => filter.filterType.toUpperCase() === "LOT_SIZE" + ) as SymbolLotSizeFilter + } + + private getMinNotionalFilter( + currencyInfo: CurrencyInfo + ): SymbolMinNotionalFilter { + return currencyInfo.filters.find( + (filter) => filter.filterType.toUpperCase() === "MIN_NOTIONAL" + ) as SymbolMinNotionalFilter + } + + private forgeOrder(order: Order): Order { + return { + ...order, + price: this.computeFillsWeightedAveragePrice(order), } + } - normalizeQuantity(quantity: number): number { - const currencyInfo: CurrencyInfo = this.market.currencyInfo - const currencyLotSizeFilter = this.getLotSizeFilter(currencyInfo) - const currencyMinNotionalFilter = this.getMinNotionalFilter(currencyInfo) - const minQuantity = parseFloat(currencyLotSizeFilter.minQty) - const maxQuantity = parseFloat(currencyLotSizeFilter.maxQty) - const stepSize = parseFloat(currencyLotSizeFilter.stepSize) - const minNotional = parseFloat(currencyMinNotionalFilter.minNotional) - const numberOfDigits = Number(currencyInfo.baseAssetPrecision) - - quantity = truncateLongDigits(quantity, numberOfDigits) - - if (quantity < minQuantity) { - if (config.api.sandbox) { - // in sandbox mode we do not throw an error, we just notify and set to minQuantity - quantity = minQuantity - Logger.debug(`Quantity is below the minQuantity, but in sandbox mode this error can be ignored.`) - } else { - throw new Error(`Cannot normalize quantity, the quantity is below the minQuantity (quantity: ${quantity}, minQuantity: ${minQuantity})`) - } - } - - if (floatSafeRemainder(quantity, stepSize) !== 0) { // floatSafeRemainder => reel js remainder - Logger.debug(`Remove remainder from quantity with step size. Quantity: ${quantity} ; stepSize: ${stepSize} ; quantity after remainder: ${Number(quantity - floatSafeRemainder(quantity, stepSize)).toFixed(numberOfDigits)}`) - quantity = parseFloat(Number(quantity - floatSafeRemainder(quantity, stepSize)).toFixed(numberOfDigits)) - } - - if (quantity > maxQuantity) { - quantity = maxQuantity - } - - const normalizedQuantity = truncateLongDigits(quantity, numberOfDigits) - - Logger.debug(`Quantity normalized: ${normalizedQuantity}`) - - return normalizedQuantity + private computeFillsWeightedAveragePrice(order: Order): string { + if (!Array.isArray(order.fills)) { + return null } - getMinQuantity(): number { - const currencyLotSizeFilter = this.getLotSizeFilter(this.market.currencyInfo) + let quantitySum = 0 + let sum = 0 - return parseFloat(currencyLotSizeFilter.minQty) - } + order.fills.forEach((fill) => { + sum += parseFloat(fill.qty) * parseFloat(fill.price) + quantitySum += parseFloat(fill.qty) + }) - private async fakeBuyMarket(currency: Currency, quantity: number) { - return { - orderId: 'fake', - symbol: currency, - clientOrderId: 'fake', - transactionTime: Date.now(), - price: '0.00000000', - origQty: quantity.toString(), - executedQty: quantity.toString(), - status: 'FILLED', - timeInForce: 'GTC', - type: 'MARKET', - side: 'BUY' - } - } - - private async fakeSellMarket(currency: Currency, quantity: number) { - return { - orderId: 'fake', - symbol: currency, - clientOrderId: 'fake', - transactionTime: Date.now(), - price: '0.00000000', - origQty: quantity.toString(), - executedQty: quantity.toString(), - status: 'FILLED', - timeInForce: 'GTC', - type: 'MARKET', - side: 'SELL' - } - } - - private getLotSizeFilter(currencyInfo: CurrencyInfo): CurrencyFilter { - let filter: CurrencyFilter - - currencyInfo.filters.forEach(currentFilter => { - if (currentFilter.filterType.toUpperCase() === 'LOT_SIZE') { - filter = currentFilter - } - }) - - return filter - } - - private getMinNotionalFilter(currencyInfo: CurrencyInfo): CurrencyFilter { - let filter: CurrencyFilter - - currencyInfo.filters.forEach(currentFilter => { - if (currentFilter.filterType.toUpperCase() === 'MIN_NOTIONAL') { - filter = currentFilter - } - }) - - return filter - } - - private forgeOrderResult(order: any): OrderResult { - return { - id: order.orderId, - symbol: order.symbol, - clientOrderId: order.clientOrderId, - transactionTime: order.transactionTime, - price: parseFloat(order.price), - originQuantity: parseFloat(order.origQty), - executedQuantity: parseFloat(order.executedQty), - status: order.status, - timeInForce: order.timeInForce, - type: order.type, - side: order.side, - fills: this.forgeOrderResultFills(order) - } - } - - private forgeOrderResultFills(order: any): OrderFill[] { - const fills = order.fills - - if (!Array.isArray(fills)) { - return null - } - - return fills.map((fill: any): OrderFill => ({ - price: parseFloat(fill.price), - quantity: parseFloat(fill.qty), - commission: parseFloat(fill.commission), - commissionAsset: fill.commissionAsset - })) - } - - private computeFillsWeightedAveragePrice(order: OrderResult): number { - if (!Array.isArray(order.fills)) { - return null - } - - let quantitySum = 0 - let sum = 0 - - order.fills.forEach(fill => { - sum += (fill.quantity * fill.price) - quantitySum += fill.quantity - }) - - return parseFloat((sum / quantitySum).toFixed(8)) - } + return (sum / quantitySum).toFixed(8) + } } -export default BinanceOrders \ No newline at end of file +export default BinanceOrders diff --git a/src/markets/gdax/accounts.ts b/src/markets/gdax/accounts.ts index bc7ad72..e455ec2 100644 --- a/src/markets/gdax/accounts.ts +++ b/src/markets/gdax/accounts.ts @@ -1,123 +1,131 @@ -import Market from '../../vendor/interfaces/market'; -import * as Gdax from 'gdax'; -import { Currency } from '../../vendor/interfaces/currency.enum'; -import { Account, CoinbaseAccount } from 'gdax'; -import { Accounts } from '../../vendor/market/accounts'; +import * as Gdax from "gdax" +import { Account, CoinbaseAccount } from "gdax" +import { Currency } from "../../vendor/interfaces/currency.enum" +import { Accounts } from "../../vendor/market/accounts" class GdaxAccounts implements Accounts { - // private allAccounts: any[] // FIXME: hard to maintain cache and reload when needed - allMarketAccounts: any[] + allMarketAccounts: any[] - client: Gdax.AuthenticatedClient + client: Gdax.AuthenticatedClient - constructor(client: Gdax.AuthenticatedClient) { - this.client = client - } - - async marketAccounts(): Promise { - if (!Array.isArray(this.allMarketAccounts)) { - this.allMarketAccounts = await this.client.getCoinbaseAccounts() - } + constructor(client: Gdax.AuthenticatedClient) { + this.client = client + } - return this.allMarketAccounts + async marketAccounts(): Promise { + if (!Array.isArray(this.allMarketAccounts)) { + this.allMarketAccounts = await this.client.getCoinbaseAccounts() } - async marketAccountByCurrency(currency: string): Promise { - const marketAccounts = await this.marketAccounts() - const marketAccountsFound = marketAccounts.filter(account => account.currency === currency) + return this.allMarketAccounts + } - if (marketAccountsFound.length === 0) { - return null - } + async marketAccountByCurrency(currency: string): Promise { + const marketAccounts = await this.marketAccounts() + const marketAccountsFound = marketAccounts.filter( + (account) => account.currency === currency + ) - return marketAccountsFound[0] + if (marketAccountsFound.length === 0) { + return null } - accounts(): Promise { - return this.client.getAccounts() - // FIXME: need to be more flexible and permets cache reload - // if (!Array.isArray(this.allAccounts)) { - // this.allAccounts = await this.client.getAccounts() - // } + return marketAccountsFound[0] + } - // return this.allAccounts - } + accounts(): Promise { + return this.client.getAccounts() + // FIXME: need to be more flexible and permets cache reload + // if (!Array.isArray(this.allAccounts)) { + // this.allAccounts = await this.client.getAccounts() + // } - account(id: string): Promise { - return this.client.getAccount(id) - } + // return this.allAccounts + } - history(accountId: string): Promise { - return this.client.getAccountHistory(accountId) - } + account(id: string): Promise { + return this.client.getAccount(id) + } - async availableFunds(currency: Currency): Promise { - const account = await this.accountByCurrency(currency) + history(accountId: string): Promise { + return this.client.getAccountHistory(accountId) + } - return parseFloat(account.available) - } + async availableFunds(currency: Currency): Promise { + const account = await this.accountByCurrency(currency) - async fundsOnHold(currency: Currency): Promise { - const account = await this.accountByCurrency(currency) + return parseFloat(account.available) + } - return parseInt(account.holds) - } + async fundsOnHold(currency: Currency): Promise { + const account = await this.accountByCurrency(currency) - async hasFundsOnHold(currency: Currency): Promise { - const fundsOnHold = await this.fundsOnHold(currency) + return parseInt(account.holds) + } - return fundsOnHold > 0 - } + async hasFundsOnHold(currency: Currency): Promise { + const fundsOnHold = await this.fundsOnHold(currency) - async accountByCurrency(currency: Currency): Promise { - const accounts = await this.accounts() - const accountsFound = accounts.filter(account => account.currency === currency) + return fundsOnHold > 0 + } - if (accountsFound.length === 0) { - return null - } + async accountByCurrency(currency: Currency): Promise { + const accounts = await this.accounts() + const accountsFound = accounts.filter( + (account) => account.currency === currency + ) - return accountsFound[0] + if (accountsFound.length === 0) { + return null } - deposit(amount: number, paymentMethod: any): Promise { - return this.client.deposit({ - amount, - currency: paymentMethod.currency, - payment_method_id: paymentMethod.id - }) + return accountsFound[0] + } + + deposit(amount: number, paymentMethod: any): Promise { + return this.client.deposit({ + amount, + currency: paymentMethod.currency, + payment_method_id: paymentMethod.id, + }) + } + + withdraw(amount: number, currency: Currency, address: string): Promise { + return this.client.withdrawCrypto({ + amount, + currency, + coinbase_account_id: address, + }) + } + + withdrawCrypto( + amount: number, + currency: Currency, + address: string + ): Promise { + return this.client.withdrawCrypto({ + amount, + currency, + crypto_address: address, + }) + } + + paymentMethods(): Promise { + return (this.client).getPaymentMethods() + } + + async paymentMethodByCurrency(currency: Currency): Promise { + const paymentMethods = await this.paymentMethods() + const paymentMethodsFound = paymentMethods.filter( + (method) => method.currency === currency + ) + + if (paymentMethods.length === 0) { + return null } - withdraw(amount: number, currency: Currency, address: string): Promise { - return this.client.withdrawCrypto({ - amount, - currency, - coinbase_account_id: address - }) - } - - withdrawCrypto(amount: number, currency: Currency, address: string): Promise { - return this.client.withdrawCrypto({ - amount, - currency, - crypto_address: address - }) - } - - paymentMethods(): Promise { - return (this.client).getPaymentMethods() - } - - async paymentMethodByCurrency(currency: Currency): Promise { - const paymentMethods = await this.paymentMethods() - const paymentMethodsFound = paymentMethods.filter(method => method.currency === currency) - - if (paymentMethods.length === 0) { - return null - } - - return paymentMethods[0] - } + return paymentMethods[0] + } } -export default GdaxAccounts \ No newline at end of file +export default GdaxAccounts diff --git a/src/markets/gdax/index.ts b/src/markets/gdax/index.ts index 743b83f..1db9eeb 100644 --- a/src/markets/gdax/index.ts +++ b/src/markets/gdax/index.ts @@ -1,94 +1,111 @@ -import * as Gdax from 'gdax'; -import GdaxAccounts from './accounts'; -import GdaxOrders from './orders'; -import Logger from '../../vendor/logger/index'; -import Market from '../../vendor/interfaces/market'; -import Orders from '../../vendor/market/orders'; -import { Accounts } from '../../vendor/market/accounts'; -import { config } from '../../config'; -import { Currency } from '../../vendor/interfaces/currency.enum'; -import { Subject } from 'rxjs/Subject'; -import { Subscription } from 'rxjs/Subscription'; +import * as Gdax from "gdax" +import { Subject } from "rxjs" +import { config } from "../../config" +import { Currency } from "../../vendor/interfaces/currency.enum" +import Market from "../../vendor/interfaces/market" +import Logger from "../../vendor/logger/index" +import { Accounts } from "../../vendor/market/accounts" +import Orders from "../../vendor/market/orders" +import GdaxAccounts from "./accounts" +import GdaxOrders from "./orders" -class GdaxService implements Market { - currency: Currency - orders: Orders - accounts: Accounts - publicClient: Gdax.PublicClient - client: Gdax.AuthenticatedClient - socket: Gdax.WebsocketClient - channels: string[] - price$: Subject - lastPrice: number - price: number - sandbox: boolean - lastTicker: Gdax.ProductTicker - initialized: boolean +class GdaxMarket implements Market { + currency: Currency + orders: Orders + accounts: Accounts + publicClient: Gdax.PublicClient + client: Gdax.AuthenticatedClient + socket: Gdax.WebsocketClient + channels: string[] + price$: Subject + lastPrice: number + price: number + sandbox: boolean + lastTicker: Gdax.ProductTicker + initialized: boolean - constructor(channels: string[] = ['ticker']) { - this.currency = config.market.currency - this.channels = channels - this.sandbox = config.api.sandbox - this.price$ = new Subject(); - } + constructor(channels: string[] = ["ticker"]) { + this.currency = config.market.currency + this.channels = channels + this.sandbox = config.api.sandbox + this.price$ = new Subject() + } - async init() { - const restURI = this.sandbox ? config.api.sandboxURI : config.api.uri - const websocketURI = this.sandbox ? config.api.sandboxWebsocketURI : config.api.websocketURI - const websocketAuth = this.sandbox ? null : { - key: process.env.GDAX_API_KEY, - secret: process.env.GDAX_API_SECRET, - passphrase: process.env.GDAX_API_PASSPHRASE + async init() { + const restURI = this.sandbox ? config.api.sandboxURI : config.api.uri + const websocketURI = this.sandbox + ? config.api.sandboxWebsocketURI + : config.api.websocketURI + const websocketAuth = this.sandbox + ? null + : { + key: process.env.GDAX_API_KEY, + secret: process.env.GDAX_API_SECRET, + passphrase: process.env.GDAX_API_PASSPHRASE, } - this.publicClient = new Gdax.PublicClient(restURI) - this.client = new Gdax.AuthenticatedClient(process.env.GDAX_API_KEY, process.env.GDAX_API_SECRET, process.env.GDAX_API_PASSPHRASE, restURI) - this.socket = new Gdax.WebsocketClient([this.currency], websocketURI, websocketAuth, { channels: this.channels }) - this.orders = new GdaxOrders(this.client, this.publicClient) - this.accounts = new GdaxAccounts(this.client) + this.publicClient = new Gdax.PublicClient(restURI) + this.client = new Gdax.AuthenticatedClient( + process.env.GDAX_API_KEY, + process.env.GDAX_API_SECRET, + process.env.GDAX_API_PASSPHRASE, + restURI + ) + this.socket = new Gdax.WebsocketClient( + [this.currency], + websocketURI, + websocketAuth, + { channels: this.channels } + ) + this.orders = new GdaxOrders(this.client, this.publicClient) + this.accounts = new GdaxAccounts(this.client) - this.listenSocketErrors() - this.initialized = true - } + this.listenSocketErrors() + this.initialized = true + } - async ping() { - // TODO: implement ping test here - return true + async ping() { + // TODO: implement ping test here + return true + } + + watchCurrencyPrice() { + if (!this.initialized) { + throw new Error( + "GdaxMarket #watchCurrencyPrice() cannot be used without being initialized" + ) } - watchCurrencyPrice() { - if (!this.initialized) { - throw new Error('GdaxMarket #watchCurrencyPrice() cannot be used without being initialized') + this.socket.on("message", (data: any) => { + if (data && "ticker" === data.type) { + if (Number.isFinite(this.price)) { + this.lastPrice = this.price } - this.socket.on('message', (data: any) => { - if (data && 'ticker' === data.type) { - if (Number.isFinite(this.price)) { - this.lastPrice = this.price - } + this.price = parseFloat(data.price) + this.price$.next(this.price) + } + }) + } - this.price = parseFloat(data.price) - this.price$.next(this.price) - } - }) + async getCurrencyPrice() { + if (!this.initialized) { + throw new Error( + "GdaxMarket #getCurrencyPrice() cannot be used without being initialized" + ) } - async getCurrencyPrice() { - if (!this.initialized) { - throw new Error('GdaxMarket #getCurrencyPrice() cannot be used without being initialized') - } + this.lastTicker = await this.publicClient.getProductTicker(this.currency) - this.lastTicker = await this.publicClient.getProductTicker(this.currency) + return parseFloat(this.lastTicker.price) + } - return parseFloat(this.lastTicker.price) - } - - private listenSocketErrors() { - this.socket.on('error', error => { - Logger.error('A socket error occured') - Logger.error(error) - }) - } + private listenSocketErrors() { + this.socket.on("error", (error) => { + Logger.error("A socket error occured") + Logger.error(error) + }) + } } -export default GdaxService \ No newline at end of file +export default GdaxMarket diff --git a/src/markets/gdax/orders.ts b/src/markets/gdax/orders.ts index 45e750a..d184e40 100644 --- a/src/markets/gdax/orders.ts +++ b/src/markets/gdax/orders.ts @@ -1,204 +1,250 @@ -import * as Gdax from 'gdax' -import { OrderType } from '../../vendor/interfaces/order-type.enum'; -import { Currency } from '../../vendor/interfaces/currency.enum'; -import { OrderStatus } from '../../vendor/interfaces/order-status.enum'; -import { Orders } from '../../vendor/market/orders'; -import { OrderResult } from '../../vendor/market/order'; +import * as Gdax from "gdax" +import { Currency } from "../../vendor/interfaces/currency.enum" +import { OrderSide } from "../../vendor/interfaces/order-type.enum" +import { OrderResult } from "../../vendor/market/order" +import { Orders } from "../../vendor/market/orders" class GdaxOrders implements Orders { - pending: OrderResult[] = [] - done: OrderResult[] = [] - canceled: OrderResult[] = [] - lastOrder: OrderResult - - constructor( - private client: Gdax.AuthenticatedClient, - private publicClient: Gdax.PublicClient) { } - - async all(): Promise { - const orders: OrderResult[] = await this.client.getOrders() - - return orders - } - - find(id: string, status: OrderType): OrderResult { - let ordersToSearch = [] - - if (OrderType.BUY === status || OrderType.SELL === status) { - ordersToSearch = this.pending.slice() - } else if (OrderType.CANCEL === status) { - ordersToSearch = this.canceled.slice() - } else { - ordersToSearch = this.done - } - - return ordersToSearch.reduce(order => { - if (order.id === id) { - return order - } - - return null - }, null) + pending: OrderResult[] = [] + done: OrderResult[] = [] + canceled: OrderResult[] = [] + lastOrder: OrderResult + + constructor( + private client: Gdax.AuthenticatedClient, + private publicClient: Gdax.PublicClient + ) {} + + async all(): Promise { + const orders: OrderResult[] = await this.client.getOrders() + + return orders + } + + find(id: string, status: OrderSide): OrderResult { + let ordersToSearch = [] + + if (OrderSide.BUY === status || OrderSide.SELL === status) { + ordersToSearch = this.pending.slice() + } else if (OrderSide.CANCEL === status) { + ordersToSearch = this.canceled.slice() + } else { + ordersToSearch = this.done } - buyOrders(): OrderResult[] { - return this.pending.filter(order => order.side === OrderType.BUY) + return ordersToSearch.reduce((order) => { + if (order.id === id) { + return order + } + + return null + }, null) + } + + buyOrders(): OrderResult[] { + return this.pending.filter((order) => order.side === OrderSide.BUY) + } + + sellOrders(): OrderResult[] { + return this.pending.filter((order) => order.side === OrderSide.SELL) + } + + async buyLimit( + currency: Currency, + quantity: number, + price: number, + allowTaker = false + ): Promise { + const response = await this.client.buy({ + type: "limit", + side: "buy", + price: price.toFixed(2), + size: this.normalizeNumber(quantity), + product_id: currency, + post_only: !allowTaker, + }) + + if (response && (response).message) { + throw Error( + `Error when trying to buy with a limit order: ${JSON.stringify( + response, + null, + 2 + )}` + ) } - sellOrders(): OrderResult[] { - return this.pending.filter(order => order.side === OrderType.SELL) + this.lastOrder = this.forgeOrderResult(response) + this.pending.push(this.lastOrder) + + return this.lastOrder + } + + async buyMarket(currency: Currency, funds: number) { + const response = await this.client.buy({ + type: "market", + side: "buy", + size: null, + funds: this.normalizeNumber(funds), + product_id: currency, + }) + + if (response && (response).message) { + throw Error( + `Error when trying to buy with a market order: ${JSON.stringify( + response, + null, + 2 + )}` + ) } - async buyLimit(currency: Currency, quantity: number, price: number, allowTaker = false): Promise { - const response = await this.client.buy({ - type: 'limit', - side: 'buy', - price: price.toFixed(2), - size: this.normalizeNumber(quantity), - product_id: currency, - post_only: !allowTaker - }) - - if (response && (response).message) { - throw Error(`Error when trying to buy with a limit order: ${JSON.stringify(response, null, 2)}`) - } - - this.lastOrder = this.forgeOrderResult(response) - this.pending.push(this.lastOrder) - - return this.lastOrder - } - - async buyMarket(currency: Currency, funds: number) { - const response = await this.client.buy({ - type: 'market', - side: 'buy', - size: null, - funds: this.normalizeNumber(funds), - product_id: currency - }) - - if (response && (response).message) { - throw Error(`Error when trying to buy with a market order: ${JSON.stringify(response, null, 2)}`) - } - - this.lastOrder = this.forgeOrderResult(response) - this.done.push({ ...this.lastOrder }) - - return this.lastOrder + this.lastOrder = this.forgeOrderResult(response) + this.done.push({ ...this.lastOrder }) + + return this.lastOrder + } + + async buyStop(currency: Currency, price: number, funds: number = null) { + const response = await this.client.buy({ + type: "stop", + side: "buy", + size: null, + funds: this.normalizeNumber(funds), + product_id: currency, + }) + + if (response && (response).message) { + throw Error( + `Error when trying to buy with a stop order: ${JSON.stringify( + response, + null, + 2 + )}` + ) } - async buyStop(currency: Currency, price: number, funds: number = null) { - const response = await this.client.buy({ - type: 'stop', - side: 'buy', - size: null, - funds: this.normalizeNumber(funds), - product_id: currency - }) - - if (response && (response).message) { - throw Error(`Error when trying to buy with a stop order: ${JSON.stringify(response, null, 2)}`) - } - - this.lastOrder = this.forgeOrderResult(response) - this.pending.push(this.lastOrder) - - return this.lastOrder + this.lastOrder = this.forgeOrderResult(response) + this.pending.push(this.lastOrder) + + return this.lastOrder + } + + async sellLimit( + currency: Currency, + quantity: number, + price: number, + allowTaker = false + ) { + const response = await this.client.sell({ + type: "limit", + side: "sell", + price: price.toFixed(2), + size: this.normalizeNumber(quantity), + product_id: currency, + post_only: !allowTaker, + }) + + if (response && (response).message) { + throw Error( + `Error when trying to sell with a limit order: ${JSON.stringify( + response, + null, + 2 + )}` + ) } - async sellLimit(currency: Currency, quantity: number, price: number, allowTaker = false) { - const response = await this.client.sell({ - type: 'limit', - side: 'sell', - price: price.toFixed(2), - size: this.normalizeNumber(quantity), - product_id: currency, - post_only: !allowTaker - }) - - if (response && (response).message) { - throw Error(`Error when trying to sell with a limit order: ${JSON.stringify(response, null, 2)}`) - } - - this.lastOrder = this.forgeOrderResult(response) - this.pending.push(this.lastOrder) - - return this.lastOrder + this.lastOrder = this.forgeOrderResult(response) + this.pending.push(this.lastOrder) + + return this.lastOrder + } + + async sellMarket(currency: Currency, size: number) { + const response = await this.client.sell({ + type: "market", + side: "sell", + size: this.normalizeNumber(size), + funds: undefined, // undefined is important here, null value returns 400 from API, and funds is needed by typings + product_id: currency, + }) + + if (response && (response).message) { + throw Error( + `Error when trying to sell with a market order: ${JSON.stringify( + response, + null, + 2 + )}` + ) } - async sellMarket(currency: Currency, size: number) { - const response = await this.client.sell({ - type: 'market', - side: 'sell', - size: this.normalizeNumber(size), - funds: undefined, // undefined is important here, null value returns 400 from API, and funds is needed by typings - product_id: currency - }) - - if (response && (response).message) { - throw Error(`Error when trying to sell with a market order: ${JSON.stringify(response, null, 2)}`) - } - - this.lastOrder = this.forgeOrderResult(response) - this.done.push({ ...this.lastOrder }) - - return this.lastOrder + this.lastOrder = this.forgeOrderResult(response) + this.done.push({ ...this.lastOrder }) + + return this.lastOrder + } + + async sellStop(currency: Currency, price: number, size: number) { + const response = await this.client.sell({ + type: "stop", + side: "sell", + size: this.normalizeNumber(size), + funds: undefined, // undefined is important here, null value returns 400 from API, and funds is needed by typings + product_id: currency, + }) + + if (response && (response).message) { + throw Error( + `Error when trying to sell with a stop order: ${JSON.stringify( + response, + null, + 2 + )}` + ) } - async sellStop(currency: Currency, price: number, size: number) { - const response = await this.client.sell({ - type: 'stop', - side: 'sell', - size: this.normalizeNumber(size), - funds: undefined, // undefined is important here, null value returns 400 from API, and funds is needed by typings - product_id: currency - }) + this.lastOrder = this.forgeOrderResult(response) + this.pending.push(this.lastOrder) - if (response && (response).message) { - throw Error(`Error when trying to sell with a stop order: ${JSON.stringify(response, null, 2)}`) - } + return this.lastOrder + } - this.lastOrder = this.forgeOrderResult(response) - this.pending.push(this.lastOrder) - - return this.lastOrder - } - - cancel(order: OrderResult) { - this.pending = this.pending.filter(current => current.id !== order.id) - this.canceled.push(order) - - return this.client.cancelOrder(order.id) - } + cancel(order: OrderResult) { + this.pending = this.pending.filter((current) => current.id !== order.id) + this.canceled.push(order) - normalizeNumber(price: number): string { - const priceString = price.toString() + return this.client.cancelOrder(order.id) + } - if (priceString.includes('.')) { - const [integers, decimals] = priceString.split('.') + normalizeNumber(price: number): string { + const priceString = price.toString() - return `${integers}.${decimals.substring(0, 8)}` - } + if (priceString.includes(".")) { + const [integers, decimals] = priceString.split(".") - return priceString + return `${integers}.${decimals.substring(0, 8)}` } - private forgeOrderResult(order: any): OrderResult { - return { - id: order.id, - symbol: order.product_id, - clientOrderId: null, - transactionTime: new Date(order.created_at).getTime(), - price: parseFloat(order.price), - originQuantity: parseFloat(order.size), - executedQuantity: parseFloat(order.filled_size), - status: order.status, - timeInForce: order.time_in_force, - type: order.type, - side: order.side - } + return priceString + } + + private forgeOrderResult(order: any): OrderResult { + return { + id: order.id, + symbol: order.product_id, + clientOrderId: null, + transactionTime: new Date(order.created_at).getTime(), + price: parseFloat(order.price), + originQuantity: parseFloat(order.size), + executedQuantity: parseFloat(order.filled_size), + status: order.status, + timeInForce: order.time_in_force, + type: order.type, + side: order.side, } + } } -export default GdaxOrders \ No newline at end of file +export default GdaxOrders diff --git a/src/typings.d.ts b/src/typings.d.ts index c2f5867..6ef5db8 100644 --- a/src/typings.d.ts +++ b/src/typings.d.ts @@ -1,56 +1,56 @@ -import { Currency } from './vendor/interfaces/currency.enum'; -import { Smoothing } from './vendor/chart/smoothing'; -import { Platform } from './config/platform'; +import { Currency } from "./vendor/interfaces/currency.enum" +import { Smoothing } from "./vendor/chart/smoothing" +import { Platform } from "./config/platform" declare interface Config { - app: { - debug: boolean, - platform: Platform - }, - network: { - retryIntervalWhenConnectionIsLost: number // ms - }, - api: { - uri?: string; - websocketURI?: string; - sandboxWebsocketURI?: string; - sandboxURI?: string; - sandbox: boolean; - }, - trader: { - quantityOfBaseCurrencyToUse: number, // in % - quantityOfQuoteCurrencyToUse: number, // in % - maxQuantityQuoteCurrencyToUse: number, - minQuantityQuoteCurrencyToUse: number, - minThresholdOfProfitability: number, // in % + app: { + debug: boolean + platform: Platform + } + network: { + retryIntervalWhenConnectionIsLost: number // ms + } + api: { + uri?: string + websocketURI?: string + sandboxWebsocketURI?: string + sandboxURI?: string + sandbox: boolean + } + trader: { + quantityOfBaseCurrencyToUse: number // in % + quantityOfQuoteCurrencyToUse: number // in % + maxQuantityQuoteCurrencyToUse: number + minQuantityQuoteCurrencyToUse: number + minThresholdOfProfitability: number // in % - // Strategies - useExitStrategyInCaseOfLosses: boolean, - sellWhenLossRateReaches: number, // in % - sellWhenPriceExceedsMaxThresholdOfProfitability: boolean, - sellWhenPriceExceedsMinThresholdOfProfitability: boolean, - quantityToSellWhenPriceExceedsMinThresholdOfProfitability: number, // in % - maxThresholdOfProfitability: number // in % - }, - market: { - currency: Currency, - orderFees: number - }, - account: { - baseCurrency: Currency - quoteCurrency: Currency, - }, - chart: { - thresholdRateToApproveInversion: number, - thresholdMaxRateToApproveInversion: number, - minPriceDifferenceToApproveNewPoint: number, - tickerInterval: number, // ms - reductionOfTheTickerIntervalOnSpeedMode: number, - numberOfUpPointsToValidatePump: number, - numberOfDownPointsToValidateDump: number, - validatePumpWhenBigPumpIsDetected: boolean, - ignoreBigPumpWhenBuying: boolean, - validateDumpWhenBigDumpIsDetected: boolean, - smoothing: Smoothing - } -} \ No newline at end of file + // Strategies + useExitStrategyInCaseOfLosses: boolean + sellWhenLossRateReaches: number // in % + sellWhenPriceExceedsMaxThresholdOfProfitability: boolean + sellWhenPriceExceedsMinThresholdOfProfitability: boolean + quantityToSellWhenPriceExceedsMinThresholdOfProfitability: number // in % + maxThresholdOfProfitability: number // in % + } + market: { + currency: Currency + orderFees: number + } + account: { + baseCurrency: Currency + quoteCurrency: Currency + } + chart: { + thresholdRateToApproveInversion: number + thresholdMaxRateToApproveInversion: number + minPriceDifferenceToApproveNewPoint: number + tickerInterval: number // ms + reductionOfTheTickerIntervalOnSpeedMode: number + numberOfUpPointsToValidatePump: number + numberOfDownPointsToValidateDump: number + validatePumpWhenBigPumpIsDetected: boolean + ignoreBigPumpWhenBuying: boolean + validateDumpWhenBigDumpIsDetected: boolean + smoothing: Smoothing + } +} diff --git a/src/vendor/chart/chart-analyzer.ts b/src/vendor/chart/chart-analyzer.ts index 8cf29e2..f1306b8 100644 --- a/src/vendor/chart/chart-analyzer.ts +++ b/src/vendor/chart/chart-analyzer.ts @@ -1,132 +1,190 @@ -import { ChartWork } from './chart-work'; -import Point from './point'; -import { Trend } from './trend.enum'; -import { config } from '../../config'; -import Equation from './equation'; -import Logger from '../logger/index'; -import ChartWorker from './chart-worker'; +import { ChartWork } from "./chart-work" +import Point from "./point" +import { Trend } from "./trend.enum" +import { config } from "../../config" +import Equation from "./equation" +import Logger from "../logger/index" +import ChartWorker from "./chart-worker" class ChartAnalyzer { - chartWorker: ChartWorker - - constructor(chartWorker: ChartWorker) { - this.chartWorker = chartWorker - } - - detectHollow(works: ChartWork[]): boolean { - let downwardTrendConfirmed = false - let upwardTrendConfirmed = false - - works.forEach(work => { - if (downwardTrendConfirmed && !upwardTrendConfirmed && this.isUpwardTrendConfirmed(work, works) && !this.ignorePump(work)) { - upwardTrendConfirmed = true - } else if (!downwardTrendConfirmed && this.isDownwardTrendConfirmed(work, works)) { - downwardTrendConfirmed = true - } - }) - - Logger.debug(`\nHollow detected at: ${((Number(downwardTrendConfirmed) / 2) + (Number(upwardTrendConfirmed) / 2)) * 100}%`) - - return downwardTrendConfirmed && upwardTrendConfirmed - } - - detectBump(works: ChartWork[]): boolean { - let upwardTrendConfirmed = false - let downwardTrendConfirmed = false - - works.forEach(work => { - if (upwardTrendConfirmed && !downwardTrendConfirmed && this.isDownwardTrendConfirmed(work, works)) { - downwardTrendConfirmed = true - } else if (!upwardTrendConfirmed && this.isUpwardTrendConfirmed(work, works)) { - upwardTrendConfirmed = true - } - }) - - Logger.debug(`\Bump detected at: ${((Number(downwardTrendConfirmed) / 2) + (Number(upwardTrendConfirmed) / 2)) * 100}%`) - - return upwardTrendConfirmed && downwardTrendConfirmed - } - - detectProfitablePump(works: ChartWork[], buyPrice: number): boolean { - const thresholdPriceProfitable = Equation.thresholdPriceOfProfitability(buyPrice) - const lastWork = works[works.length - 1] - let profitablePump = false - - works.forEach(work => { - if (!profitablePump) { - profitablePump = work.price >= thresholdPriceProfitable && this.isUpwardTrendConfirmed(work, works) - } - }) - - return profitablePump - } - - isDownwardTrendConfirmed(work: ChartWork, works: ChartWork[]): boolean { - return this.isBigDumpConfirmed(work) || this.trendsConfirmDownward(work, works) - } - - isUpwardTrendConfirmed(work: ChartWork, works: ChartWork[]): boolean { - return this.isBigPumpConfirmed(work) || this.trendsConfirmUpward(work, works) - } - - ignorePump(work: ChartWork): boolean { - return config.chart.ignoreBigPumpWhenBuying && Math.abs(Equation.rateBetweenValues(work.lastPrice, work.price)) > config.chart.thresholdMaxRateToApproveInversion - } - - isBigDumpConfirmed(work): boolean { - return config.chart.validateDumpWhenBigDumpIsDetected && work.trend === Trend.DOWNWARD && this.rateBetweenPricesConfirmTrend(work.lastPrice, work.price) - } - - isBigPumpConfirmed(work): boolean { - return config.chart.validatePumpWhenBigPumpIsDetected && work.trend === Trend.UPWARD && this.rateBetweenPricesConfirmTrend(work.lastPrice, work.price) - } - - trendsConfirmDownward(work: ChartWork, works: ChartWork[]): boolean { - // number of down needed to confirm downward trend, it is set in the config - let lastWork = work - let numberOfDownDetected = 0 - - for (let index = 0; index < config.chart.numberOfDownPointsToValidateDump; index++) { - if (lastWork) { - if (lastWork.trend === Trend.DOWNWARD) { - ++numberOfDownDetected - } else if (lastWork.trend === Trend.FLAT) { - // if the trend is flat, we ignore the point - index -= 1 - } - - lastWork = this.chartWorker.findPreviousWork(lastWork, works) - } + chartWorker: ChartWorker + + constructor(chartWorker: ChartWorker) { + this.chartWorker = chartWorker + } + + detectHollow(works: ChartWork[]): boolean { + let downwardTrendConfirmed = false + let upwardTrendConfirmed = false + + works.forEach((work) => { + if ( + downwardTrendConfirmed && + !upwardTrendConfirmed && + this.isUpwardTrendConfirmed(work, works) && + !this.ignorePump(work) + ) { + upwardTrendConfirmed = true + } else if ( + !downwardTrendConfirmed && + this.isDownwardTrendConfirmed(work, works) + ) { + downwardTrendConfirmed = true + } + }) + + Logger.debug( + `\nHollow detected at: ${ + (Number(downwardTrendConfirmed) / 2 + + Number(upwardTrendConfirmed) / 2) * + 100 + }%` + ) + + return downwardTrendConfirmed && upwardTrendConfirmed + } + + detectBump(works: ChartWork[]): boolean { + let upwardTrendConfirmed = false + let downwardTrendConfirmed = false + + works.forEach((work) => { + if ( + upwardTrendConfirmed && + !downwardTrendConfirmed && + this.isDownwardTrendConfirmed(work, works) + ) { + downwardTrendConfirmed = true + } else if ( + !upwardTrendConfirmed && + this.isUpwardTrendConfirmed(work, works) + ) { + upwardTrendConfirmed = true + } + }) + + Logger.debug( + `\Bump detected at: ${ + (Number(downwardTrendConfirmed) / 2 + + Number(upwardTrendConfirmed) / 2) * + 100 + }%` + ) + + return upwardTrendConfirmed && downwardTrendConfirmed + } + + detectProfitablePump(works: ChartWork[], buyPrice: number): boolean { + const thresholdPriceProfitable = Equation.thresholdPriceOfProfitability( + buyPrice + ) + const lastWork = works[works.length - 1] + let profitablePump = false + + works.forEach((work) => { + if (!profitablePump) { + profitablePump = + work.price >= thresholdPriceProfitable && + this.isUpwardTrendConfirmed(work, works) + } + }) + + return profitablePump + } + + isDownwardTrendConfirmed(work: ChartWork, works: ChartWork[]): boolean { + return ( + this.isBigDumpConfirmed(work) || this.trendsConfirmDownward(work, works) + ) + } + + isUpwardTrendConfirmed(work: ChartWork, works: ChartWork[]): boolean { + return ( + this.isBigPumpConfirmed(work) || this.trendsConfirmUpward(work, works) + ) + } + + ignorePump(work: ChartWork): boolean { + return ( + config.chart.ignoreBigPumpWhenBuying && + Math.abs(Equation.rateBetweenValues(work.lastPrice, work.price)) > + config.chart.thresholdMaxRateToApproveInversion + ) + } + + isBigDumpConfirmed(work): boolean { + return ( + config.chart.validateDumpWhenBigDumpIsDetected && + work.trend === Trend.DOWNWARD && + this.rateBetweenPricesConfirmTrend(work.lastPrice, work.price) + ) + } + + isBigPumpConfirmed(work): boolean { + return ( + config.chart.validatePumpWhenBigPumpIsDetected && + work.trend === Trend.UPWARD && + this.rateBetweenPricesConfirmTrend(work.lastPrice, work.price) + ) + } + + trendsConfirmDownward(work: ChartWork, works: ChartWork[]): boolean { + // number of down needed to confirm downward trend, it is set in the config + let lastWork = work + let numberOfDownDetected = 0 + + for ( + let index = 0; + index < config.chart.numberOfDownPointsToValidateDump; + index++ + ) { + if (lastWork) { + if (lastWork.trend === Trend.DOWNWARD) { + ++numberOfDownDetected + } else if (lastWork.trend === Trend.FLAT) { + // if the trend is flat, we ignore the point + index -= 1 } - return numberOfDownDetected >= config.chart.numberOfDownPointsToValidateDump + lastWork = this.chartWorker.findPreviousWork(lastWork, works) + } } - trendsConfirmUpward(work: ChartWork, works: ChartWork[]): boolean { - // number of up needed to confirm upward trend, it is set in the config - let lastWork = work - let numberOfUpDetected = 0 - - for (let index = 0; index < config.chart.numberOfUpPointsToValidatePump; index++) { - if (lastWork) { - if (lastWork.trend === Trend.UPWARD) { - ++numberOfUpDetected - } else if (lastWork.trend === Trend.FLAT) { - // if the trend is flat, we ignore the point - index -= 1 - } - - lastWork = this.chartWorker.findPreviousWork(lastWork, works) - } + return numberOfDownDetected >= config.chart.numberOfDownPointsToValidateDump + } + + trendsConfirmUpward(work: ChartWork, works: ChartWork[]): boolean { + // number of up needed to confirm upward trend, it is set in the config + let lastWork = work + let numberOfUpDetected = 0 + + for ( + let index = 0; + index < config.chart.numberOfUpPointsToValidatePump; + index++ + ) { + if (lastWork) { + if (lastWork.trend === Trend.UPWARD) { + ++numberOfUpDetected + } else if (lastWork.trend === Trend.FLAT) { + // if the trend is flat, we ignore the point + index -= 1 } - return numberOfUpDetected >= config.chart.numberOfUpPointsToValidatePump + lastWork = this.chartWorker.findPreviousWork(lastWork, works) + } } - rateBetweenPricesConfirmTrend(priceA, priceB) { - // High price difference confirms immediately a trend - return Math.abs(Equation.rateBetweenValues(priceA, priceB)) >= config.chart.thresholdRateToApproveInversion - } + return numberOfUpDetected >= config.chart.numberOfUpPointsToValidatePump + } + + rateBetweenPricesConfirmTrend(priceA, priceB) { + // High price difference confirms immediately a trend + return ( + Math.abs(Equation.rateBetweenValues(priceA, priceB)) >= + config.chart.thresholdRateToApproveInversion + ) + } } -export default ChartAnalyzer \ No newline at end of file +export default ChartAnalyzer diff --git a/src/vendor/chart/chart-work.ts b/src/vendor/chart/chart-work.ts index f9869cb..ccaeefa 100644 --- a/src/vendor/chart/chart-work.ts +++ b/src/vendor/chart/chart-work.ts @@ -1,10 +1,10 @@ -import { Trend } from './trend.enum' +import { Trend } from "./trend.enum" export interface ChartWork { - id: number - trend: Trend - lastTrend: Trend - lastPrice: number - price: number - time: number -} \ No newline at end of file + id: number + trend: Trend + lastTrend: Trend + lastPrice: number + price: number + time: number +} diff --git a/src/vendor/chart/chart-worker.ts b/src/vendor/chart/chart-worker.ts index 6219a0f..5b2bece 100644 --- a/src/vendor/chart/chart-worker.ts +++ b/src/vendor/chart/chart-worker.ts @@ -1,367 +1,398 @@ -import Market from '../interfaces/market' -import { config } from '../../config'; -import Chart from './chart'; -import Equation from './equation'; -import Point from './point'; -import { Trend } from './trend.enum'; -import { Subject } from 'rxjs/Subject'; -import { ChartWork } from './chart-work'; -import { WorkerSpeed } from './worker-speed'; -import Logger from '../logger/index'; -import * as delay from 'delay' -import { Smoothing } from './smoothing'; +import * as delay from "delay" +import { Subject } from "rxjs" +import { config } from "../../config" +import Market from "../interfaces/market" +import Logger from "../logger/index" +import Chart from "./chart" +import { ChartWork } from "./chart-work" +import Equation from "./equation" +import Point from "./point" +import { Smoothing } from "./smoothing" +import { Trend } from "./trend.enum" +import { WorkerSpeed } from "./worker-speed" class ChartWorker { - chart: Chart - market: Market - lastTrend: Trend - trend: Trend - lastPrice: number - price: number - trend$: Subject - work$: Subject - tickerInterval: number - tickerIntervalRef: NodeJS.Timer - started: boolean - lastId: number - lastTime: number - works: ChartWork[] - allWorks: ChartWork[] // only different from .works property in debug mode - lastWork: ChartWork - mode: WorkerSpeed - - constructor(market: Market) { - this.market = market - this.chart = new Chart() - this.trend$ = new Subject() - this.works = [] - this.allWorks = [] - this.work$ = new Subject() - this.started = false - this.lastId = 0 - this.lastTime = 0 - this.tickerInterval = config.chart.tickerInterval - this.tickerIntervalRef = null - this.mode = WorkerSpeed.NORMAL - this.trend = null - this.lastTrend = null - this.lastPrice = null - } - - initFromWorks(works: ChartWork[], restartFromTime: number) { - this.allWorks = this.copyWorks(works) - - if (this.allWorks.length > 0) { - this.lastWork = this.allWorks[this.allWorks.length - 1] - this.lastTime = this.lastWork.time + this.tickerInterval - this.lastPrice = this.lastWork.lastPrice - this.price = this.lastWork.price - this.trend = this.lastWork.trend - this.lastTrend = this.lastWork.lastTrend - this.lastId = this.lastWork.id + 1 - - works.forEach(work => { - const point = this.extractPointFromWork(work) - - this.chart.createPoint(point.x, point.y) - - if (Number.isFinite(restartFromTime) && work.time >= restartFromTime) { - this.works.push({ ...work }) - } - }) + chart: Chart + market: Market + lastTrend: Trend + trend: Trend + lastPrice: number + price: number + trend$: Subject + work$: Subject + tickerInterval: number + tickerIntervalRef: NodeJS.Timer + started: boolean + lastId: number + lastTime: number + works: ChartWork[] + allWorks: ChartWork[] // only different from .works property in debug mode + lastWork: ChartWork + mode: WorkerSpeed + + constructor(market: Market) { + this.market = market + this.chart = new Chart() + this.trend$ = new Subject() + this.works = [] + this.allWorks = [] + this.work$ = new Subject() + this.started = false + this.lastId = 0 + this.lastTime = 0 + this.tickerInterval = config.chart.tickerInterval + this.tickerIntervalRef = null + this.mode = WorkerSpeed.NORMAL + this.trend = null + this.lastTrend = null + this.lastPrice = null + } + + initFromWorks(works: ChartWork[], restartFromTime: number) { + this.allWorks = this.copyWorks(works) + + if (this.allWorks.length > 0) { + this.lastWork = this.allWorks[this.allWorks.length - 1] + this.lastTime = this.lastWork.time + this.tickerInterval + this.lastPrice = this.lastWork.lastPrice + this.price = this.lastWork.price + this.trend = this.lastWork.trend + this.lastTrend = this.lastWork.lastTrend + this.lastId = this.lastWork.id + 1 + + works.forEach((work) => { + const point = this.extractPointFromWork(work) + + this.chart.createPoint(point.x, point.y) + + if (Number.isFinite(restartFromTime) && work.time >= restartFromTime) { + this.works.push({ ...work }) } + }) } + } - workOnPriceTicker() { - if (this.tickerIntervalRef) { - clearInterval(this.tickerIntervalRef) - } - - this.priceTickerWork() - this.tickerIntervalRef = setInterval(() => this.priceTickerWork(), this.tickerInterval) - } - - changeTickerInterval(newInterval: number) { - if (this.tickerIntervalRef) { - clearInterval(this.tickerIntervalRef) - } - - this.tickerInterval = newInterval - this.tickerIntervalRef = setInterval(() => this.priceTickerWork(), this.tickerInterval) + workOnPriceTicker() { + if (this.tickerIntervalRef) { + clearInterval(this.tickerIntervalRef) } - async priceTickerWork() { - this.lastPrice = this.price - - try { - this.price = await this.market.getCurrencyPrice() - } catch (error) { - // Maybe network error, we stop worker and wait network connection back - Logger.debug('Worker cannot retrieve currency price') - Logger.debug(error) - this.stopWorking() + this.priceTickerWork() + this.tickerIntervalRef = setInterval( + () => this.priceTickerWork(), + this.tickerInterval + ) + } - Logger.debug('Worker will rery until it can get the currency price') - this.price = await this.retryUntilGetCurrencyPrice() - Logger.debug('Worker has retrieved the currency price, it continues the work') - } - - const lastPoint = this.chart.lastPoint() - const newPoint = this.chart.createPoint(this.lastTime, this.price) - - this.lastTrend = this.trend - this.trend = this.computeTrend(lastPoint, newPoint) - this.lastWork = { - id: this.lastId++, - lastPrice: this.lastPrice, - price: this.price, - lastTrend: this.lastTrend, - trend: this.trend, - time: this.lastTime - } - this.notifyWork(this.lastWork) - this.lastTime += this.tickerInterval + changeTickerInterval(newInterval: number) { + if (this.tickerIntervalRef) { + clearInterval(this.tickerIntervalRef) } - fastMode() { - if (this.mode !== WorkerSpeed.FAST) { - this.mode = WorkerSpeed.FAST - this.changeTickerInterval(config.chart.tickerInterval * (1 - config.chart.reductionOfTheTickerIntervalOnSpeedMode)) - } + this.tickerInterval = newInterval + this.tickerIntervalRef = setInterval( + () => this.priceTickerWork(), + this.tickerInterval + ) + } + + async priceTickerWork() { + this.lastPrice = this.price + + try { + this.price = await this.market.getCurrencyPrice() + } catch (error) { + // Maybe network error, we stop worker and wait network connection back + Logger.debug("Worker cannot retrieve currency price") + Logger.debug(error) + this.stopWorking() + + Logger.debug("Worker will rery until it can get the currency price") + this.price = await this.retryUntilGetCurrencyPrice() + Logger.debug( + "Worker has retrieved the currency price, it continues the work" + ) } - normalMode() { - if (this.mode !== WorkerSpeed.NORMAL) { - this.mode = WorkerSpeed.NORMAL - this.changeTickerInterval(config.chart.tickerInterval) - } + const lastPoint = this.chart.lastPoint() + const newPoint = this.chart.createPoint(this.lastTime, this.price) + + this.lastTrend = this.trend + this.trend = this.computeTrend(lastPoint, newPoint) + this.lastWork = { + id: this.lastId++, + lastPrice: this.lastPrice, + price: this.price, + lastTrend: this.lastTrend, + trend: this.trend, + time: this.lastTime, } - - isInFastMode(): boolean { - return this.mode === WorkerSpeed.FAST + this.notifyWork(this.lastWork) + this.lastTime += this.tickerInterval + } + + fastMode() { + if (this.mode !== WorkerSpeed.FAST) { + this.mode = WorkerSpeed.FAST + this.changeTickerInterval( + config.chart.tickerInterval * + (1 - config.chart.reductionOfTheTickerIntervalOnSpeedMode) + ) } + } - isInNormalMode(): boolean { - return this.mode === WorkerSpeed.NORMAL + normalMode() { + if (this.mode !== WorkerSpeed.NORMAL) { + this.mode = WorkerSpeed.NORMAL + this.changeTickerInterval(config.chart.tickerInterval) } + } - computeTrend(lastPoint, newPoint): number { - const leadingCoefficient = Equation.findLineLeadingCoefficient(lastPoint, newPoint) + isInFastMode(): boolean { + return this.mode === WorkerSpeed.FAST + } - return this.determineTrend(leadingCoefficient) - } + isInNormalMode(): boolean { + return this.mode === WorkerSpeed.NORMAL + } - notifyWork(work: ChartWork) { - const copiedWork = { ...work } + computeTrend(lastPoint, newPoint): number { + const leadingCoefficient = Equation.findLineLeadingCoefficient( + lastPoint, + newPoint + ) - this.works.push(copiedWork) - this.allWorks.push(copiedWork) - this.work$.next(copiedWork) - } - - notifyTrend() { - this.trend$.next(this.trend) - } + return this.determineTrend(leadingCoefficient) + } - filterNoise(works: ChartWork[]): ChartWork[] { - const smooting = config.chart.smoothing + notifyWork(work: ChartWork) { + const copiedWork = { ...work } - // FIXME: relink here works between them - // Remap lastPrice, lastTrend, etc., in order to keep the chain logical - // WARN: lastPrice is used for the minThresholdOfProfitability strategy for exemple! So it is important - - switch (smooting) { - case Smoothing.MOVING_AVERAGE: - return this.removePointsTooClose(this.smoothMovingAverage(works)) - - case Smoothing.SAMPLE: - default: - return this.removePointsTooClose(this.removeIsolatedBumpAndHollow(works)) - } - } + this.works.push(copiedWork) + this.allWorks.push(copiedWork) + this.work$.next(copiedWork) + } - smoothMovingAverage(works: ChartWork[]): ChartWork[] { - const numberOfWorks = works.length + notifyTrend() { + this.trend$.next(this.trend) + } - return works.map((work, index) => { - const previousWork = this.findPreviousWork(work, works) - const nextWork = this.findNextWork(work, works) - let smoothedWork = { ...work } + filterNoise(works: ChartWork[]): ChartWork[] { + const smooting = config.chart.smoothing - if (previousWork && nextWork) { - smoothedWork.price = (previousWork.price + work.price + nextWork.price) / 3 - } + // FIXME: relink here works between them + // Remap lastPrice, lastTrend, etc., in order to keep the chain logical + // WARN: lastPrice is used for the minThresholdOfProfitability strategy for exemple! So it is important - if (previousWork) { - smoothedWork.lastTrend = previousWork.trend - smoothedWork.trend = this.computeTrend(this.extractPointFromWork(previousWork), this.extractPointFromWork(smoothedWork)) - } + switch (smooting) { + case Smoothing.MOVING_AVERAGE: + return this.removePointsTooClose(this.smoothMovingAverage(works)) - return smoothedWork - }) + case Smoothing.SAMPLE: + default: + return this.removePointsTooClose( + this.removeIsolatedBumpAndHollow(works) + ) } - - removePointsTooClose(works: ChartWork[]): ChartWork[] { - let lastWorkKept: ChartWork - - return works.filter((work, index) => { - if (index === 0 || !lastWorkKept) { - // First point, we keep it - lastWorkKept = { ...work } - - return true - } - - if (Math.abs(Equation.rateBetweenValues(lastWorkKept.price, work.price)) > config.chart.minPriceDifferenceToApproveNewPoint) { - const pointFromLastWorkKept = this.extractPointFromWork(lastWorkKept) - const pointFromCurrentWork = this.extractPointFromWork(work) - const newTrend = this.computeTrend(pointFromLastWorkKept, pointFromCurrentWork) - - work.lastTrend = lastWorkKept.trend - work.trend = newTrend - work.lastPrice = lastWorkKept.price - lastWorkKept = { ...work } - - return true - } - - return false - }) + } + + smoothMovingAverage(works: ChartWork[]): ChartWork[] { + const numberOfWorks = works.length + + return works.map((work, index) => { + const previousWork = this.findPreviousWork(work, works) + const nextWork = this.findNextWork(work, works) + let smoothedWork = { ...work } + + if (previousWork && nextWork) { + smoothedWork.price = + (previousWork.price + work.price + nextWork.price) / 3 + } + + if (previousWork) { + smoothedWork.lastTrend = previousWork.trend + smoothedWork.trend = this.computeTrend( + this.extractPointFromWork(previousWork), + this.extractPointFromWork(smoothedWork) + ) + } + + return smoothedWork + }) + } + + removePointsTooClose(works: ChartWork[]): ChartWork[] { + let lastWorkKept: ChartWork + + return works.filter((work, index) => { + if (index === 0 || !lastWorkKept) { + // First point, we keep it + lastWorkKept = { ...work } + + return true + } + + if ( + Math.abs(Equation.rateBetweenValues(lastWorkKept.price, work.price)) > + config.chart.minPriceDifferenceToApproveNewPoint + ) { + const pointFromLastWorkKept = this.extractPointFromWork(lastWorkKept) + const pointFromCurrentWork = this.extractPointFromWork(work) + const newTrend = this.computeTrend( + pointFromLastWorkKept, + pointFromCurrentWork + ) + + work.lastTrend = lastWorkKept.trend + work.trend = newTrend + work.lastPrice = lastWorkKept.price + lastWorkKept = { ...work } + + return true + } + + return false + }) + } + + removeIsolatedBumpAndHollow(works: ChartWork[]): ChartWork[] { + const worksLength = works.length + + return works.filter((work, index) => { + if (index === 0 || index === worksLength - 1) { + return true // we keep the first and the last point + } + + const previousWork = works[index - 1] + const nextWork = works[index + 1] + const isolatedBump = + previousWork.trend === Trend.DOWNWARD && + work.trend === Trend.UPWARD && + nextWork.trend === Trend.DOWNWARD + const isolatedHollow = + previousWork.trend === Trend.UPWARD && + work.trend === Trend.DOWNWARD && + nextWork.trend === Trend.UPWARD + + return !isolatedBump && !isolatedHollow + }) + } + + extractPointFromWork(work: ChartWork): Point { + return { + x: work.time, + y: work.price, } + } - removeIsolatedBumpAndHollow(works: ChartWork[]): ChartWork[] { - const worksLength = works.length + startWorking() { + if (this.tickerIntervalRef) { + clearInterval(this.tickerIntervalRef) + } - return works.filter((work, index) => { - if (index === 0 || index === worksLength - 1) { - return true // we keep the first and the last point - } + this.started = true - const previousWork = works[index - 1] - const nextWork = works[index + 1] - const isolatedBump = previousWork.trend === Trend.DOWNWARD && work.trend === Trend.UPWARD && nextWork.trend === Trend.DOWNWARD - const isolatedHollow = previousWork.trend === Trend.UPWARD && work.trend === Trend.DOWNWARD && nextWork.trend === Trend.UPWARD + this.workOnPriceTicker() - return !isolatedBump && !isolatedHollow - }) - } + Logger.debug("Worker is started") + } - extractPointFromWork(work: ChartWork): Point { - return { - x: work.time, - y: work.price - } + stopWorking() { + if (this.tickerIntervalRef) { + clearInterval(this.tickerIntervalRef) } - startWorking() { - if (this.tickerIntervalRef) { - clearInterval(this.tickerIntervalRef) - } + this.started = false - this.started = true + Logger.debug("Worker is stopped") + } + async retryUntilGetCurrencyPrice() { + Logger.debug("Retry to get currency price") - this.workOnPriceTicker() + try { + const price = await this.market.getCurrencyPrice() - Logger.debug('Worker is started') - } + if (price) { + return price + } - stopWorking() { - if (this.tickerIntervalRef) { - clearInterval(this.tickerIntervalRef) - } + await delay(config.network.retryIntervalWhenConnectionIsLost) - this.started = false + return this.retryUntilGetCurrencyPrice() + } catch (error) { + await delay(config.network.retryIntervalWhenConnectionIsLost) - Logger.debug('Worker is stopped') + return this.retryUntilGetCurrencyPrice() } + } - async retryUntilGetCurrencyPrice() { - Logger.debug('Retry to get currency price') - - try { - const price = await this.market.getCurrencyPrice() + copyWorks(works: ChartWork[] = this.works): ChartWork[] { + return works.slice().map((work) => ({ ...work })) + } - if (price) { - return price - } - - await delay(config.network.retryIntervalWhenConnectionIsLost) - - return this.retryUntilGetCurrencyPrice() - } catch (error) { - await delay(config.network.retryIntervalWhenConnectionIsLost) - - return this.retryUntilGetCurrencyPrice() - } + prepareForNewWorks() { + if (this.isInFastMode()) { + this.normalMode() } - copyWorks(works: ChartWork[] = this.works): ChartWork[] { - return works.slice().map(work => ({ ...work })) - } + this.clearWorks() + } - prepareForNewWorks() { - if (this.isInFastMode()) { - this.normalMode() - } + clearWorks() { + this.works = [] + } - this.clearWorks() - } + findPreviousWork(work: ChartWork, works: ChartWork[]): ChartWork { + let previousWork: ChartWork = null - clearWorks() { - this.works = [] - } + works.forEach((current, index) => { + if (current.id === work.id && index > 0) { + previousWork = works[index - 1] + } + }) - findPreviousWork(work: ChartWork, works: ChartWork[]): ChartWork { - let previousWork: ChartWork = null + return previousWork + } - works.forEach((current, index) => { - if (current.id === work.id && index > 0) { - previousWork = works[index - 1] - } - }) + findWork(work: ChartWork, works: ChartWork[]): ChartWork { + let workFound: ChartWork = null - return previousWork - } - - findWork(work: ChartWork, works: ChartWork[]): ChartWork { - let workFound: ChartWork = null + works.forEach((current) => { + if (current.id === work.id) { + workFound = current + } + }) - works.forEach(current => { - if (current.id === work.id) { - workFound = current - } - }) + return workFound + } - return workFound - } + findNextWork(work: ChartWork, works: ChartWork[]): ChartWork { + let nextWork: ChartWork = null + const numberOfWorks = works.length - findNextWork(work: ChartWork, works: ChartWork[]): ChartWork { - let nextWork: ChartWork = null - const numberOfWorks = works.length + works.forEach((current, index) => { + if (current.id === work.id && index < numberOfWorks - 1) { + nextWork = works[index + 1] + } + }) - works.forEach((current, index) => { - if (current.id === work.id && index < numberOfWorks - 1) { - nextWork = works[index + 1] - } - }) + return nextWork + } - return nextWork + private determineTrend(leadingCoefficient: number): Trend { + if (!Number.isFinite(leadingCoefficient)) { + return null } - private determineTrend(leadingCoefficient: number): Trend { - if (!Number.isFinite(leadingCoefficient)) { - return null - } - - if (leadingCoefficient === 0) { - return Trend.FLAT - } else if (leadingCoefficient > 0) { - return Trend.UPWARD - } else { - return Trend.DOWNWARD; - } + if (leadingCoefficient === 0) { + return Trend.FLAT + } else if (leadingCoefficient > 0) { + return Trend.UPWARD + } else { + return Trend.DOWNWARD } + } } -export default ChartWorker \ No newline at end of file +export default ChartWorker diff --git a/src/vendor/chart/chart.ts b/src/vendor/chart/chart.ts index 53b2a39..e5d60d4 100644 --- a/src/vendor/chart/chart.ts +++ b/src/vendor/chart/chart.ts @@ -1,40 +1,42 @@ -import Point from './point'; -import Logger from '../logger/index'; +import Point from "./point" +import Logger from "../logger/index" class Chart { - points: Point[] + points: Point[] - constructor(points: Point[] = []) { - this.points = points + constructor(points: Point[] = []) { + this.points = points + } + + createPoint(x: number, y: number): Point { + if (!Number.isFinite(x) || !Number.isFinite(y)) { + Logger.error( + `Cannot create point on the chart, coordinates are invalid (x: ${x}, y: ${y})` + ) } - createPoint(x: number, y: number): Point { - if (!Number.isFinite(x) || !Number.isFinite(y)) { - Logger.error(`Cannot create point on the chart, coordinates are invalid (x: ${x}, y: ${y})`) - } + const point = new Point(x, y) - const point = new Point(x, y) + this.points.push(point) - this.points.push(point) + return Object.assign({}, point) + } - return Object.assign({}, point) - } + addPoint(point: Point) { + this.points.push(point) + } - addPoint(point: Point) { - this.points.push(point) + lastPoint(): Point { + if (this.points.length === 0) { + return null } - lastPoint(): Point { - if (this.points.length === 0) { - return null - } + return Object.assign({}, this.points[this.points.length - 1]) + } - return Object.assign({}, this.points[this.points.length - 1]) - } - - clearPoints() { - this.points = [] - } + clearPoints() { + this.points = [] + } } -export default Chart \ No newline at end of file +export default Chart diff --git a/src/vendor/chart/equation.ts b/src/vendor/chart/equation.ts index bec0081..c20d220 100644 --- a/src/vendor/chart/equation.ts +++ b/src/vendor/chart/equation.ts @@ -1,59 +1,75 @@ -import Point from './point'; -import { config } from '../../config'; +import Point from "./point" +import { config } from "../../config" class Equation { - static findLineLeadingCoefficient(pointA: Point, pointB: Point): number { - if (!Equation.isValidPoint(pointA) || !Equation.isValidPoint(pointB)) { - return null - } - - return Equation.findLineEquation(pointA, pointB).a + static findLineLeadingCoefficient(pointA: Point, pointB: Point): number { + if (!Equation.isValidPoint(pointA) || !Equation.isValidPoint(pointB)) { + return null } - static findLineEquation(pointA: Point, pointB: Point) { - const a = (pointB.y - pointA.y) / (pointB.x - pointA.x) - const b = pointA.y - (a * pointA.x) + return Equation.findLineEquation(pointA, pointB).a + } - return { - a, - b - } - } + static findLineEquation(pointA: Point, pointB: Point) { + const a = (pointB.y - pointA.y) / (pointB.x - pointA.x) + const b = pointA.y - a * pointA.x - static isValidPoint(point: Point) { - return point && Number.isFinite(point.x) && Number.isFinite(point.y) + return { + a, + b, } + } - static rateBetweenValues(a, b): number { - return 100 * ((b / a) - 1) // from: a * (1 + t/100) = b <=> t = 100(b/a - 1) - } + static isValidPoint(point: Point) { + return point && Number.isFinite(point.x) && Number.isFinite(point.y) + } - static isProfitable(buyPrice, comparedPrice) { - const threshold = Equation.thresholdPriceOfProfitability(buyPrice) + static rateBetweenValues(a, b): number { + return 100 * (b / a - 1) // from: a * (1 + t/100) = b <=> t = 100(b/a - 1) + } - return comparedPrice >= threshold - } + static isProfitable(buyPrice, comparedPrice) { + const threshold = Equation.thresholdPriceOfProfitability(buyPrice) - static isProfitableOnQuantity(quoteCurrencyInvested, size, sellPrice): boolean { - return ((size * sellPrice) * (1 - config.market.orderFees)) > quoteCurrencyInvested - } + return comparedPrice >= threshold + } - static thresholdPriceOfProfitability(buyPrice: number, threshold: number = config.trader.minThresholdOfProfitability): number { - const multiplierFeesIncluded = 1 - config.market.orderFees + static isProfitableOnQuantity( + quoteCurrencyInvested, + size, + sellPrice + ): boolean { + return ( + size * sellPrice * (1 - config.market.orderFees) > quoteCurrencyInvested + ) + } - if (multiplierFeesIncluded === 0) { - throw new Error(`Fees cannot be 100%. Mathematic error when trying to calculate threshold price of profitability (multiplierFeesIncluded = 0, cannot divide by zero)`) - } + static thresholdPriceOfProfitability( + buyPrice: number, + threshold: number = config.trader.minThresholdOfProfitability + ): number { + const multiplierFeesIncluded = 1 - config.market.orderFees - // a = amount invested, p1 = price when bought (with "a" amount), b = amount recovered, p2 = price when sold (give "b" amount) - // b = (1 - fees)^2 * a * (p2/p1) - // b > a <=> p2 > p1 * ((1 + (t / 100)) / ((1 - fees)^2)) - return buyPrice * ((1 + (threshold / 100)) / Math.pow(multiplierFeesIncluded, 2)) + if (multiplierFeesIncluded === 0) { + throw new Error( + `Fees cannot be 100%. Mathematic error when trying to calculate threshold price of profitability (multiplierFeesIncluded = 0, cannot divide by zero)` + ) } - static maxThresholdPriceOfProfitability(buyPrice: number): number { - return Equation.thresholdPriceOfProfitability(buyPrice, config.trader.maxThresholdOfProfitability) - } + // a = amount invested, p1 = price when bought (with "a" amount), b = amount recovered, p2 = price when sold (give "b" amount) + // b = (1 - fees)^2 * a * (p2/p1) + // b > a <=> p2 > p1 * ((1 + (t / 100)) / ((1 - fees)^2)) + return ( + buyPrice * ((1 + threshold / 100) / Math.pow(multiplierFeesIncluded, 2)) + ) + } + + static maxThresholdPriceOfProfitability(buyPrice: number): number { + return Equation.thresholdPriceOfProfitability( + buyPrice, + config.trader.maxThresholdOfProfitability + ) + } } -export default Equation \ No newline at end of file +export default Equation diff --git a/src/vendor/chart/maths.ts b/src/vendor/chart/maths.ts index 436c144..6799063 100644 --- a/src/vendor/chart/maths.ts +++ b/src/vendor/chart/maths.ts @@ -1,30 +1,32 @@ export function floatSafeRemainder(val: number, step: number): number { - const valDecCount = (val.toString().split('.')[1] || '').length - const stepDecCount = (step.toString().split('.')[1] || '').length - const decCount = valDecCount > stepDecCount ? valDecCount : stepDecCount - const valInt = parseInt(val.toFixed(decCount).replace('.', '')) - const stepInt = parseInt(step.toFixed(decCount).replace('.', '')) + const valDecCount = (val.toString().split(".")[1] || "").length + const stepDecCount = (step.toString().split(".")[1] || "").length + const decCount = valDecCount > stepDecCount ? valDecCount : stepDecCount + const valInt = parseInt(val.toFixed(decCount).replace(".", "")) + const stepInt = parseInt(step.toFixed(decCount).replace(".", "")) - return (valInt % stepInt) / Math.pow(10, decCount) + return (valInt % stepInt) / Math.pow(10, decCount) } export function truncateLongDigits(number: number, digits: number = 8): number { - const quantityString = number.toString() - let normalizedQuantity = number + const quantityString = number.toString() + let normalizedQuantity = number - if (quantityString.includes('.')) { - let [integers, decimals] = quantityString.split('.') - let power = '0' + if (quantityString.includes(".")) { + let [integers, decimals] = quantityString.split(".") + let power = "0" - if (decimals.includes('e')) { - const decimalsWithPower = decimals.split('e') + if (decimals.includes("e")) { + const decimalsWithPower = decimals.split("e") - decimals = decimalsWithPower[0] - power = decimalsWithPower[1] - } - - normalizedQuantity = Number(`${integers}.${decimals.substring(0, digits)}e${power}`) + decimals = decimalsWithPower[0] + power = decimalsWithPower[1] } - return normalizedQuantity -} \ No newline at end of file + normalizedQuantity = Number( + `${integers}.${decimals.substring(0, digits)}e${power}` + ) + } + + return normalizedQuantity +} diff --git a/src/vendor/chart/point.ts b/src/vendor/chart/point.ts index db4a9ba..825a28b 100644 --- a/src/vendor/chart/point.ts +++ b/src/vendor/chart/point.ts @@ -1,11 +1,11 @@ class Point { - x: number - y: number + x: number + y: number - constructor(x: number, y: number) { - this.x = x - this.y = y - } + constructor(x: number, y: number) { + this.x = x + this.y = y + } } -export default Point \ No newline at end of file +export default Point diff --git a/src/vendor/chart/smoothing.ts b/src/vendor/chart/smoothing.ts index 23fb2fd..bfa841b 100644 --- a/src/vendor/chart/smoothing.ts +++ b/src/vendor/chart/smoothing.ts @@ -1,4 +1,4 @@ export enum Smoothing { - SAMPLE, - MOVING_AVERAGE -} \ No newline at end of file + SAMPLE, + MOVING_AVERAGE, +} diff --git a/src/vendor/chart/trend.enum.ts b/src/vendor/chart/trend.enum.ts index ab51628..132c375 100644 --- a/src/vendor/chart/trend.enum.ts +++ b/src/vendor/chart/trend.enum.ts @@ -1,5 +1,5 @@ export enum Trend { - UPWARD, - DOWNWARD, - FLAT -} \ No newline at end of file + UPWARD, + DOWNWARD, + FLAT, +} diff --git a/src/vendor/chart/worker-speed.ts b/src/vendor/chart/worker-speed.ts index 19e5a14..91e88fa 100644 --- a/src/vendor/chart/worker-speed.ts +++ b/src/vendor/chart/worker-speed.ts @@ -1,4 +1,4 @@ export enum WorkerSpeed { - NORMAL, - FAST -} \ No newline at end of file + NORMAL, + FAST, +} diff --git a/src/vendor/interfaces/currency.enum.ts b/src/vendor/interfaces/currency.enum.ts index 9579bc2..c57f224 100644 --- a/src/vendor/interfaces/currency.enum.ts +++ b/src/vendor/interfaces/currency.enum.ts @@ -1,386 +1,386 @@ export enum Currency { - // Bitcoin - BTC_EUR = 'BTC-EUR', - BTC_USD = 'BTC-USD', + // Bitcoin + BTC_EUR = "BTC-EUR", + BTC_USD = "BTC-USD", - // Bitcoin cash - BCH_EUR = 'BCH-EUR', - BCH_USD = 'BCH-USD', - BCH_BTC = 'BCH-BTC', + // Bitcoin cash + BCH_EUR = "BCH-EUR", + BCH_USD = "BCH-USD", + BCH_BTC = "BCH-BTC", - // Ethereum - ETH_EUR = 'ETH-EUR', - ETH_USD = 'ETH-USD', - ETH_BTC = 'ETH-BTC', + // Ethereum + ETH_EUR = "ETH-EUR", + ETH_USD = "ETH-USD", + ETH_BTC = "ETH-BTC", - // Litecoin - LTC_EUR = 'LTC-EUR', - LTC_USD = 'LTC-USD', - LTC_BTC = 'LTC-BTC', + // Litecoin + LTC_EUR = "LTC-EUR", + LTC_USD = "LTC-USD", + LTC_BTC = "LTC-BTC", - // Sample currencies - USD = 'USD', - EUR = 'EUR', - BTC = 'BTC', - LTC = 'LTC', - ETH = 'ETH', - BCH = 'BCH', - CMT = 'CMT', - BNB = 'BNB', - NEO = 'NEO', - QTUM = 'QTUM', - EOS = 'EOS', - SNT = 'SNT', - BNT = 'BNT', - BCC = 'BCC', - GAS = 'GAS', - USDT = 'USDT', - HSR = 'HSR', - OAX = 'OAX', - DNT = 'DNT', - MCO = 'MCO', - ICN = 'ICN', - WTC = 'WTC', - LRC = 'LRC', - YOYO = 'YOYO', - OMG = 'OMG', - ZRX = 'ZRX', - STRAT = 'STRAT', - SNGLS = 'SNGLS', - BQX = 'BQX', - KNC = 'KNC', - FUN = 'FUN', - SNM = 'SNM', - IOTA = 'IOTA', - LINK = 'LINK', - XVG = 'XVG', - CTR = 'CTR', - SALT = 'SALT', - MDA = 'MDA', - MTL = 'MTL', - SUB = 'SUB', - ETC = 'ETC', - MTH = 'MTH', - ENG = 'ENG', - ZEC = 'ZEC', - AST = 'AST', - DASH = 'DASH', - BTG = 'BTG', - EVX = 'EVX', - REQ = 'REQ', - VIB = 'VIB', - TRX = 'TRX', - POWR = 'POWR', - ARK = 'ARK', - XRP = 'XRP', - MOD = 'MOD', - ENJ = 'ENJ', - STORJ = 'STORJ', - VEN = 'VEN', - KMD = 'KMD', - NULS = 'NULS', - RCN = 'RCN', - RDN = 'RDN', - XMR = 'XMR', - DLT = 'DLT', - AMB = 'AMB', - BAT = 'BAT', - BCPT = 'BCPT', - ARN = 'ARN', - GVT = 'GVT', - CDT = 'CDT', - GXS = 'GXS', - POE = 'POE', - QSP = 'QSP', - BTS = 'BTS', - XZC = 'XZC', - LSK = 'LSK', - TNT = 'TNT', - FUEL = 'FUEL', - MANA = 'MANA', - BCD = 'BCD', - DGD = 'DGD', - ADX = 'ADX', - ADA = 'ADA', - PPT = 'PPT', - XLM = 'XLM', - CND = 'CND', - LEND = 'LEND', - WABI = 'WABI', - TNB = 'TNB', - WAVES = 'WAVES', - GTO = 'GTO', - ICX = 'ICX', - OST = 'OST', - ELF = 'ELF', - AION = 'AION', - NEBL = 'NEBL', - BRD = 'BRD', - EDO = 'EDO', - WINGS = 'WINGS', - NAV = 'NAV', - LUN = 'LUN', - TRIG = 'TRIG', - APPC = 'APPC', - VIBE = 'VIBE', - RLC = 'RLC', - INS = 'INS', - PIVX = 'PIVX', - IOST = 'IOST', - STEEM = 'STEEM', - CHAT = 'CHAT', - RPX = 'RPX', + // Sample currencies + USD = "USD", + EUR = "EUR", + BTC = "BTC", + LTC = "LTC", + ETH = "ETH", + BCH = "BCH", + CMT = "CMT", + BNB = "BNB", + NEO = "NEO", + QTUM = "QTUM", + EOS = "EOS", + SNT = "SNT", + BNT = "BNT", + BCC = "BCC", + GAS = "GAS", + USDT = "USDT", + HSR = "HSR", + OAX = "OAX", + DNT = "DNT", + MCO = "MCO", + ICN = "ICN", + WTC = "WTC", + LRC = "LRC", + YOYO = "YOYO", + OMG = "OMG", + ZRX = "ZRX", + STRAT = "STRAT", + SNGLS = "SNGLS", + BQX = "BQX", + KNC = "KNC", + FUN = "FUN", + SNM = "SNM", + IOTA = "IOTA", + LINK = "LINK", + XVG = "XVG", + CTR = "CTR", + SALT = "SALT", + MDA = "MDA", + MTL = "MTL", + SUB = "SUB", + ETC = "ETC", + MTH = "MTH", + ENG = "ENG", + ZEC = "ZEC", + AST = "AST", + DASH = "DASH", + BTG = "BTG", + EVX = "EVX", + REQ = "REQ", + VIB = "VIB", + TRX = "TRX", + POWR = "POWR", + ARK = "ARK", + XRP = "XRP", + MOD = "MOD", + ENJ = "ENJ", + STORJ = "STORJ", + VEN = "VEN", + KMD = "KMD", + NULS = "NULS", + RCN = "RCN", + RDN = "RDN", + XMR = "XMR", + DLT = "DLT", + AMB = "AMB", + BAT = "BAT", + BCPT = "BCPT", + ARN = "ARN", + GVT = "GVT", + CDT = "CDT", + GXS = "GXS", + POE = "POE", + QSP = "QSP", + BTS = "BTS", + XZC = "XZC", + LSK = "LSK", + TNT = "TNT", + FUEL = "FUEL", + MANA = "MANA", + BCD = "BCD", + DGD = "DGD", + ADX = "ADX", + ADA = "ADA", + PPT = "PPT", + XLM = "XLM", + CND = "CND", + LEND = "LEND", + WABI = "WABI", + TNB = "TNB", + WAVES = "WAVES", + GTO = "GTO", + ICX = "ICX", + OST = "OST", + ELF = "ELF", + AION = "AION", + NEBL = "NEBL", + BRD = "BRD", + EDO = "EDO", + WINGS = "WINGS", + NAV = "NAV", + LUN = "LUN", + TRIG = "TRIG", + APPC = "APPC", + VIBE = "VIBE", + RLC = "RLC", + INS = "INS", + PIVX = "PIVX", + IOST = "IOST", + STEEM = "STEEM", + CHAT = "CHAT", + RPX = "RPX", - // CURRENCY EXCHANGE - RPXBTC = 'RPXBTC', - CHATBTC = 'CHATBTC', - STEEMBTC = 'STEEMBTC', - STEEMETH = 'STEEMETH', - ETHBTC = 'ETHBTC', - LTCBTC = 'LTCBTC', - BNBBTC = 'BNBBTC', - NEOBTC = 'NEOBTC', - QTUMETH = 'QTUMETH', - EOSETH = 'EOSETH', - SNTETH = 'SNTETH', - BNTETH = 'BNTETH', - BCCBTC = 'BCCBTC', - GASBTC = 'GASBTC', - BNBETH = 'BNBETH', - BTCUSDT = 'BTCUSDT', - ETHUSDT = 'ETHUSDT', - HSRBTC = 'HSRBTC', - OAXETH = 'OAXETH', - DNTETH = 'DNTETH', - MCOETH = 'MCOETH', - ICNETH = 'ICNETH', - MCOBTC = 'MCOBTC', - WTCBTC = 'WTCBTC', - WTCETH = 'WTCETH', - LRCBTC = 'LRCBTC', - LRCETH = 'LRCETH', - QTUMBTC = 'QTUMBTC', - YOYOBTC = 'YOYOBTC', - OMGBTC = 'OMGBTC', - OMGETH = 'OMGETH', - ZRXBTC = 'ZRXBTC', - ZRXETH = 'ZRXETH', - STRATBTC = 'STRATBTC', - STRATETH = 'STRATETH', - SNGLSBTC = 'SNGLSBTC', - SNGLSETH = 'SNGLSETH', - BQXBTC = 'BQXBTC', - BQXETH = 'BQXETH', - KNCBTC = 'KNCBTC', - KNCETH = 'KNCETH', - FUNBTC = 'FUNBTC', - FUNETH = 'FUNETH', - SNMBTC = 'SNMBTC', - SNMETH = 'SNMETH', - NEOETH = 'NEOETH', - IOTABTC = 'IOTABTC', - IOTAETH = 'IOTAETH', - LINKBTC = 'LINKBTC', - LINKETH = 'LINKETH', - XVGBTC = 'XVGBTC', - XVGETH = 'XVGETH', - CTRBTC = 'CTRBTC', - CTRETH = 'CTRETH', - SALTBTC = 'SALTBTC', - SALTETH = 'SALTETH', - MDABTC = 'MDABTC', - MDAETH = 'MDAETH', - MTLBTC = 'MTLBTC', - MTLETH = 'MTLETH', - SUBBTC = 'SUBBTC', - SUBETH = 'SUBETH', - EOSBTC = 'EOSBTC', - SNTBTC = 'SNTBTC', - ETCETH = 'ETCETH', - ETCBTC = 'ETCBTC', - MTHBTC = 'MTHBTC', - MTHETH = 'MTHETH', - ENGBTC = 'ENGBTC', - ENGETH = 'ENGETH', - DNTBTC = 'DNTBTC', - ZECBTC = 'ZECBTC', - ZECETH = 'ZECETH', - BNTBTC = 'BNTBTC', - ASTBTC = 'ASTBTC', - ASTETH = 'ASTETH', - DASHBTC = 'DASHBTC', - DASHETH = 'DASHETH', - OAXBTC = 'OAXBTC', - ICNBTC = 'ICNBTC', - BTGBTC = 'BTGBTC', - BTGETH = 'BTGETH', - EVXBTC = 'EVXBTC', - EVXETH = 'EVXETH', - REQBTC = 'REQBTC', - REQETH = 'REQETH', - VIBBTC = 'VIBBTC', - VIBETH = 'VIBETH', - HSRETH = 'HSRETH', - TRXBTC = 'TRXBTC', - TRXETH = 'TRXETH', - POWRBTC = 'POWRBTC', - POWRETH = 'POWRETH', - ARKBTC = 'ARKBTC', - ARKETH = 'ARKETH', - YOYOETH = 'YOYOETH', - XRPBTC = 'XRPBTC', - XRPETH = 'XRPETH', - MODBTC = 'MODBTC', - MODETH = 'MODETH', - ENJBTC = 'ENJBTC', - ENJETH = 'ENJETH', - STORJBTC = 'STORJBTC', - STORJETH = 'STORJETH', - BNBUSDT = 'BNBUSDT', - VENBNB = 'VENBNB', - YOYOBNB = 'YOYOBNB', - POWRBNB = 'POWRBNB', - VENBTC = 'VENBTC', - VENETH = 'VENETH', - KMDBTC = 'KMDBTC', - KMDETH = 'KMDETH', - NULSBNB = 'NULSBNB', - RCNBTC = 'RCNBTC', - RCNETH = 'RCNETH', - RCNBNB = 'RCNBNB', - NULSBTC = 'NULSBTC', - NULSETH = 'NULSETH', - RDNBTC = 'RDNBTC', - RDNETH = 'RDNETH', - RDNBNB = 'RDNBNB', - XMRBTC = 'XMRBTC', - XMRETH = 'XMRETH', - DLTBNB = 'DLTBNB', - WTCBNB = 'WTCBNB', - DLTBTC = 'DLTBTC', - DLTETH = 'DLTETH', - AMBBTC = 'AMBBTC', - AMBETH = 'AMBETH', - AMBBNB = 'AMBBNB', - BCCETH = 'BCCETH', - BCCUSDT = 'BCCUSDT', - BCCBNB = 'BCCBNB', - BATBTC = 'BATBTC', - BATETH = 'BATETH', - BATBNB = 'BATBNB', - BCPTBTC = 'BCPTBTC', - BCPTETH = 'BCPTETH', - BCPTBNB = 'BCPTBNB', - ARNBTC = 'ARNBTC', - ARNETH = 'ARNETH', - GVTBTC = 'GVTBTC', - GVTETH = 'GVTETH', - CDTBTC = 'CDTBTC', - CDTETH = 'CDTETH', - GXSBTC = 'GXSBTC', - GXSETH = 'GXSETH', - NEOUSDT = 'NEOUSDT', - NEOBNB = 'NEOBNB', - POEBTC = 'POEBTC', - POEETH = 'POEETH', - QSPBTC = 'QSPBTC', - QSPETH = 'QSPETH', - QSPBNB = 'QSPBNB', - BTSBTC = 'BTSBTC', - BTSETH = 'BTSETH', - BTSBNB = 'BTSBNB', - XZCBTC = 'XZCBTC', - XZCETH = 'XZCETH', - XZCBNB = 'XZCBNB', - LSKBTC = 'LSKBTC', - LSKETH = 'LSKETH', - LSKBNB = 'LSKBNB', - TNTBTC = 'TNTBTC', - TNTETH = 'TNTETH', - FUELBTC = 'FUELBTC', - FUELETH = 'FUELETH', - MANABTC = 'MANABTC', - MANAETH = 'MANAETH', - BCDBTC = 'BCDBTC', - BCDETH = 'BCDETH', - DGDBTC = 'DGDBTC', - DGDETH = 'DGDETH', - IOTABNB = 'IOTABNB', - ADXBTC = 'ADXBTC', - ADXETH = 'ADXETH', - ADXBNB = 'ADXBNB', - ADABTC = 'ADABTC', - ADAETH = 'ADAETH', - PPTBTC = 'PPTBTC', - PPTETH = 'PPTETH', - CMTBTC = 'CMTBTC', - CMTETH = 'CMTETH', - CMTBNB = 'CMTBNB', - XLMBTC = 'XLMBTC', - XLMETH = 'XLMETH', - XLMBNB = 'XLMBNB', - CNDBTC = 'CNDBTC', - CNDETH = 'CNDETH', - CNDBNB = 'CNDBNB', - LENDBTC = 'LENDBTC', - LENDETH = 'LENDETH', - WABIBTC = 'WABIBTC', - WABIETH = 'WABIETH', - WABIBNB = 'WABIBNB', - LTCETH = 'LTCETH', - LTCUSDT = 'LTCUSDT', - LTCBNB = 'LTCBNB', - TNBBTC = 'TNBBTC', - TNBETH = 'TNBETH', - WAVESBTC = 'WAVESBTC', - WAVESETH = 'WAVESETH', - WAVESBNB = 'WAVESBNB', - GTOBTC = 'GTOBTC', - GTOETH = 'GTOETH', - GTOBNB = 'GTOBNB', - ICXBTC = 'ICXBTC', - ICXETH = 'ICXETH', - ICXBNB = 'ICXBNB', - OSTBTC = 'OSTBTC', - OSTETH = 'OSTETH', - OSTBNB = 'OSTBNB', - ELFBTC = 'ELFBTC', - ELFETH = 'ELFETH', - AIONBTC = 'AIONBTC', - AIONETH = 'AIONETH', - AIONBNB = 'AIONBNB', - NEBLBTC = 'NEBLBTC', - NEBLETH = 'NEBLETH', - NEBLBNB = 'NEBLBNB', - BRDBTC = 'BRDBTC', - BRDETH = 'BRDETH', - BRDBNB = 'BRDBNB', - MCOBNB = 'MCOBNB', - EDOBTC = 'EDOBTC', - EDOETH = 'EDOETH', - WINGSBTC = 'WINGSBTC', - WINGSETH = 'WINGSETH', - NAVBTC = 'NAVBTC', - NAVETH = 'NAVETH', - NAVBNB = 'NAVBNB', - LUNBTC = 'LUNBTC', - LUNETH = 'LUNETH', - TRIGBTC = 'TRIGBTC', - TRIGETH = 'TRIGETH', - TRIGBNB = 'TRIGBNB', - APPCBTC = 'APPCBTC', - APPCETH = 'APPCETH', - APPCBNB = 'APPCBNB', - VIBEBTC = 'VIBEBTC', - VIBEETH = 'VIBEETH', - RLCBTC = 'RLCBTC', - RLCETH = 'RLCETH', - RLCBNB = 'RLCBNB', - INSBTC = 'INSBTC', - INSETH = 'INSETH', - PIVXBTC = 'PIVXBTC', - PIVXETH = 'PIVXETH', - PIVXBNB = 'PIVXBNB', - IOSTBTC = 'IOSTBTC', - IOSTETH = 'IOSTETH' -} \ No newline at end of file + // CURRENCY EXCHANGE + RPXBTC = "RPXBTC", + CHATBTC = "CHATBTC", + STEEMBTC = "STEEMBTC", + STEEMETH = "STEEMETH", + ETHBTC = "ETHBTC", + LTCBTC = "LTCBTC", + BNBBTC = "BNBBTC", + NEOBTC = "NEOBTC", + QTUMETH = "QTUMETH", + EOSETH = "EOSETH", + SNTETH = "SNTETH", + BNTETH = "BNTETH", + BCCBTC = "BCCBTC", + GASBTC = "GASBTC", + BNBETH = "BNBETH", + BTCUSDT = "BTCUSDT", + ETHUSDT = "ETHUSDT", + HSRBTC = "HSRBTC", + OAXETH = "OAXETH", + DNTETH = "DNTETH", + MCOETH = "MCOETH", + ICNETH = "ICNETH", + MCOBTC = "MCOBTC", + WTCBTC = "WTCBTC", + WTCETH = "WTCETH", + LRCBTC = "LRCBTC", + LRCETH = "LRCETH", + QTUMBTC = "QTUMBTC", + YOYOBTC = "YOYOBTC", + OMGBTC = "OMGBTC", + OMGETH = "OMGETH", + ZRXBTC = "ZRXBTC", + ZRXETH = "ZRXETH", + STRATBTC = "STRATBTC", + STRATETH = "STRATETH", + SNGLSBTC = "SNGLSBTC", + SNGLSETH = "SNGLSETH", + BQXBTC = "BQXBTC", + BQXETH = "BQXETH", + KNCBTC = "KNCBTC", + KNCETH = "KNCETH", + FUNBTC = "FUNBTC", + FUNETH = "FUNETH", + SNMBTC = "SNMBTC", + SNMETH = "SNMETH", + NEOETH = "NEOETH", + IOTABTC = "IOTABTC", + IOTAETH = "IOTAETH", + LINKBTC = "LINKBTC", + LINKETH = "LINKETH", + XVGBTC = "XVGBTC", + XVGETH = "XVGETH", + CTRBTC = "CTRBTC", + CTRETH = "CTRETH", + SALTBTC = "SALTBTC", + SALTETH = "SALTETH", + MDABTC = "MDABTC", + MDAETH = "MDAETH", + MTLBTC = "MTLBTC", + MTLETH = "MTLETH", + SUBBTC = "SUBBTC", + SUBETH = "SUBETH", + EOSBTC = "EOSBTC", + SNTBTC = "SNTBTC", + ETCETH = "ETCETH", + ETCBTC = "ETCBTC", + MTHBTC = "MTHBTC", + MTHETH = "MTHETH", + ENGBTC = "ENGBTC", + ENGETH = "ENGETH", + DNTBTC = "DNTBTC", + ZECBTC = "ZECBTC", + ZECETH = "ZECETH", + BNTBTC = "BNTBTC", + ASTBTC = "ASTBTC", + ASTETH = "ASTETH", + DASHBTC = "DASHBTC", + DASHETH = "DASHETH", + OAXBTC = "OAXBTC", + ICNBTC = "ICNBTC", + BTGBTC = "BTGBTC", + BTGETH = "BTGETH", + EVXBTC = "EVXBTC", + EVXETH = "EVXETH", + REQBTC = "REQBTC", + REQETH = "REQETH", + VIBBTC = "VIBBTC", + VIBETH = "VIBETH", + HSRETH = "HSRETH", + TRXBTC = "TRXBTC", + TRXETH = "TRXETH", + POWRBTC = "POWRBTC", + POWRETH = "POWRETH", + ARKBTC = "ARKBTC", + ARKETH = "ARKETH", + YOYOETH = "YOYOETH", + XRPBTC = "XRPBTC", + XRPETH = "XRPETH", + MODBTC = "MODBTC", + MODETH = "MODETH", + ENJBTC = "ENJBTC", + ENJETH = "ENJETH", + STORJBTC = "STORJBTC", + STORJETH = "STORJETH", + BNBUSDT = "BNBUSDT", + VENBNB = "VENBNB", + YOYOBNB = "YOYOBNB", + POWRBNB = "POWRBNB", + VENBTC = "VENBTC", + VENETH = "VENETH", + KMDBTC = "KMDBTC", + KMDETH = "KMDETH", + NULSBNB = "NULSBNB", + RCNBTC = "RCNBTC", + RCNETH = "RCNETH", + RCNBNB = "RCNBNB", + NULSBTC = "NULSBTC", + NULSETH = "NULSETH", + RDNBTC = "RDNBTC", + RDNETH = "RDNETH", + RDNBNB = "RDNBNB", + XMRBTC = "XMRBTC", + XMRETH = "XMRETH", + DLTBNB = "DLTBNB", + WTCBNB = "WTCBNB", + DLTBTC = "DLTBTC", + DLTETH = "DLTETH", + AMBBTC = "AMBBTC", + AMBETH = "AMBETH", + AMBBNB = "AMBBNB", + BCCETH = "BCCETH", + BCCUSDT = "BCCUSDT", + BCCBNB = "BCCBNB", + BATBTC = "BATBTC", + BATETH = "BATETH", + BATBNB = "BATBNB", + BCPTBTC = "BCPTBTC", + BCPTETH = "BCPTETH", + BCPTBNB = "BCPTBNB", + ARNBTC = "ARNBTC", + ARNETH = "ARNETH", + GVTBTC = "GVTBTC", + GVTETH = "GVTETH", + CDTBTC = "CDTBTC", + CDTETH = "CDTETH", + GXSBTC = "GXSBTC", + GXSETH = "GXSETH", + NEOUSDT = "NEOUSDT", + NEOBNB = "NEOBNB", + POEBTC = "POEBTC", + POEETH = "POEETH", + QSPBTC = "QSPBTC", + QSPETH = "QSPETH", + QSPBNB = "QSPBNB", + BTSBTC = "BTSBTC", + BTSETH = "BTSETH", + BTSBNB = "BTSBNB", + XZCBTC = "XZCBTC", + XZCETH = "XZCETH", + XZCBNB = "XZCBNB", + LSKBTC = "LSKBTC", + LSKETH = "LSKETH", + LSKBNB = "LSKBNB", + TNTBTC = "TNTBTC", + TNTETH = "TNTETH", + FUELBTC = "FUELBTC", + FUELETH = "FUELETH", + MANABTC = "MANABTC", + MANAETH = "MANAETH", + BCDBTC = "BCDBTC", + BCDETH = "BCDETH", + DGDBTC = "DGDBTC", + DGDETH = "DGDETH", + IOTABNB = "IOTABNB", + ADXBTC = "ADXBTC", + ADXETH = "ADXETH", + ADXBNB = "ADXBNB", + ADABTC = "ADABTC", + ADAETH = "ADAETH", + PPTBTC = "PPTBTC", + PPTETH = "PPTETH", + CMTBTC = "CMTBTC", + CMTETH = "CMTETH", + CMTBNB = "CMTBNB", + XLMBTC = "XLMBTC", + XLMETH = "XLMETH", + XLMBNB = "XLMBNB", + CNDBTC = "CNDBTC", + CNDETH = "CNDETH", + CNDBNB = "CNDBNB", + LENDBTC = "LENDBTC", + LENDETH = "LENDETH", + WABIBTC = "WABIBTC", + WABIETH = "WABIETH", + WABIBNB = "WABIBNB", + LTCETH = "LTCETH", + LTCUSDT = "LTCUSDT", + LTCBNB = "LTCBNB", + TNBBTC = "TNBBTC", + TNBETH = "TNBETH", + WAVESBTC = "WAVESBTC", + WAVESETH = "WAVESETH", + WAVESBNB = "WAVESBNB", + GTOBTC = "GTOBTC", + GTOETH = "GTOETH", + GTOBNB = "GTOBNB", + ICXBTC = "ICXBTC", + ICXETH = "ICXETH", + ICXBNB = "ICXBNB", + OSTBTC = "OSTBTC", + OSTETH = "OSTETH", + OSTBNB = "OSTBNB", + ELFBTC = "ELFBTC", + ELFETH = "ELFETH", + AIONBTC = "AIONBTC", + AIONETH = "AIONETH", + AIONBNB = "AIONBNB", + NEBLBTC = "NEBLBTC", + NEBLETH = "NEBLETH", + NEBLBNB = "NEBLBNB", + BRDBTC = "BRDBTC", + BRDETH = "BRDETH", + BRDBNB = "BRDBNB", + MCOBNB = "MCOBNB", + EDOBTC = "EDOBTC", + EDOETH = "EDOETH", + WINGSBTC = "WINGSBTC", + WINGSETH = "WINGSETH", + NAVBTC = "NAVBTC", + NAVETH = "NAVETH", + NAVBNB = "NAVBNB", + LUNBTC = "LUNBTC", + LUNETH = "LUNETH", + TRIGBTC = "TRIGBTC", + TRIGETH = "TRIGETH", + TRIGBNB = "TRIGBNB", + APPCBTC = "APPCBTC", + APPCETH = "APPCETH", + APPCBNB = "APPCBNB", + VIBEBTC = "VIBEBTC", + VIBEETH = "VIBEETH", + RLCBTC = "RLCBTC", + RLCETH = "RLCETH", + RLCBNB = "RLCBNB", + INSBTC = "INSBTC", + INSETH = "INSETH", + PIVXBTC = "PIVXBTC", + PIVXETH = "PIVXETH", + PIVXBNB = "PIVXBNB", + IOSTBTC = "IOSTBTC", + IOSTETH = "IOSTETH", +} diff --git a/src/vendor/interfaces/market.ts b/src/vendor/interfaces/market.ts index e212daf..3d3bae0 100644 --- a/src/vendor/interfaces/market.ts +++ b/src/vendor/interfaces/market.ts @@ -1,25 +1,25 @@ -import { Currency } from "./currency.enum"; -import { Subject } from "rxjs/Subject"; -import { Accounts } from "../market/accounts"; -import { Orders } from "../market/orders"; -import { CurrencyInfo } from '../market/currency-info'; +import { Subject } from "rxjs" +import { Accounts } from "../market/accounts" +import { CurrencyInfo } from "../market/currency-info" +import { Orders } from "../market/orders" +import { Currency } from "./currency.enum" export default interface Market { - lastPrice: number - price: number - price$: Subject - currency: Currency - orders: Orders - accounts: Accounts - client: any - publicClient?: any - lastTicker: any - initialized: boolean - sandbox: boolean - currencyInfo?: CurrencyInfo - - init(): void - watchCurrencyPrice(): void - getCurrencyPrice(): Promise - ping?(): Promise -} \ No newline at end of file + lastPrice: number + price: number + price$: Subject + currency: Currency + orders: Orders + accounts: Accounts + client: any + publicClient?: any + lastTicker: any + initialized: boolean + sandbox: boolean + currencyInfo?: CurrencyInfo + + init(): Promise + watchCurrencyPrice(): void + getCurrencyPrice(): Promise + ping?(): Promise +} diff --git a/src/vendor/interfaces/order-status.enum.ts b/src/vendor/interfaces/order-status.enum.ts index 0e2da68..c255203 100644 --- a/src/vendor/interfaces/order-status.enum.ts +++ b/src/vendor/interfaces/order-status.enum.ts @@ -1,5 +1,5 @@ export enum OrderStatus { - PENDING, - CANCELED, - DONE -} \ No newline at end of file + PENDING, + CANCELED, + DONE, +} diff --git a/src/vendor/interfaces/order-type.enum.ts b/src/vendor/interfaces/order-type.enum.ts index 36fea77..f4b2735 100644 --- a/src/vendor/interfaces/order-type.enum.ts +++ b/src/vendor/interfaces/order-type.enum.ts @@ -1,6 +1,13 @@ +export enum OrderSide { + BUY = "BUY", + SELL = "SELL", + // @deprecated + CANCEL = "CANCEL", + // @deprecated + DONE = "DONE", +} + export enum OrderType { - BUY = 'buy', - SELL = 'sell', - CANCEL = 'cancel', - DONE = 'done' -} \ No newline at end of file + MARKET = "MARKET", + LIMIT = "LIMIT", +} diff --git a/src/vendor/interfaces/trader.ts b/src/vendor/interfaces/trader.ts index 28f0e58..16ab9a5 100644 --- a/src/vendor/interfaces/trader.ts +++ b/src/vendor/interfaces/trader.ts @@ -1,4 +1,4 @@ export default interface Trading { - trade(): void - stop(): void -} \ No newline at end of file + trade(): void + stop(): void +} diff --git a/src/vendor/logger/index.ts b/src/vendor/logger/index.ts index 048898c..c126fb5 100644 --- a/src/vendor/logger/index.ts +++ b/src/vendor/logger/index.ts @@ -1,23 +1,23 @@ -import { config } from '../../config'; +import { config } from "../../config" class Logger { - static debug(message) { - if (config.app.debug) { - console.log(message) - } + static debug(message) { + if (config.app.debug) { + console.log(message) } + } - static error(message) { - console.error(message) - } + static error(message) { + console.error(message) + } - static warn(message) { - console.warn(message) - } + static warn(message) { + console.warn(message) + } - static info(message) { - console.info(message) - } + static info(message) { + console.info(message) + } } export default Logger diff --git a/src/vendor/market/accounts.ts b/src/vendor/market/accounts.ts index 3d6eefe..d4e252f 100644 --- a/src/vendor/market/accounts.ts +++ b/src/vendor/market/accounts.ts @@ -1,36 +1,37 @@ -import { Currency } from "../interfaces/currency.enum"; +import { Currency } from "../interfaces/currency.enum" export interface Accounts { - // private allAccounts: any[] // FIXME: hard to maintain cache and reload when needed - allMarketAccounts: any[] + client: any - client: any + marketAccounts?(): Promise - marketAccounts?(): Promise + marketAccountByCurrency?(currency: string): Promise - marketAccountByCurrency?(currency: string): Promise + accounts?(): Promise - accounts?(): Promise + account?(id: string): Promise - account?(id: string): Promise + history?(accountId: string): Promise - history?(accountId: string): Promise + availableFunds(currency: string): Promise - availableFunds(currency: string): Promise + fundsOnHold?(currency: string): Promise - fundsOnHold?(currency: string): Promise + hasFundsOnHold?(currency: string): Promise - hasFundsOnHold?(currency: string): Promise + accountByCurrency?(currency: string): Promise - accountByCurrency?(currency: string): Promise + deposit?(amount: number, paymentMethod: any): Promise - deposit?(amount: number, paymentMethod: any): Promise + withdraw?(amount: number, currency: Currency, address: string): Promise - withdraw?(amount: number, currency: Currency, address: string): Promise + withdrawCrypto?( + amount: number, + currency: Currency, + address: string + ): Promise - withdrawCrypto?(amount: number, currency: Currency, address: string): Promise + paymentMethods?(): Promise - paymentMethods?(): Promise - - paymentMethodByCurrency?(currency: Currency): Promise -} \ No newline at end of file + paymentMethodByCurrency?(currency: Currency): Promise +} diff --git a/src/vendor/market/currency-info.ts b/src/vendor/market/currency-info.ts index 3f6574a..c3d9aad 100644 --- a/src/vendor/market/currency-info.ts +++ b/src/vendor/market/currency-info.ts @@ -1,24 +1,5 @@ -import { Currency } from '../interfaces/currency.enum'; +import { Symbol, SymbolFilter } from "binance-api-node" -export interface CurrencyInfo { - symbol: Currency - status: string - baseAsset: Currency - baseAssetPrecision: number - quoteAsset: Currency - quotePrecision: number - orderTypes: 'LIMIT' | 'LIMIT_MAKER' | 'MARKET' | 'STOP_LOSS_LIMIT' | 'TAKE_PROFIT_LIMIT' - icebergAllowed: boolean - filters: CurrencyFilter[] -} +export type CurrencyInfo = Symbol -export interface CurrencyFilter { - filterType: 'PRICE_FILTER' | 'LOT_SIZE' | 'MIN_NOTIONAL' - minPrice?: string - maxPrice?: string - tickSize?: string - minQty?: string - maxQty?: string - stepSize?: string - minNotional?: string -} \ No newline at end of file +export type CurrencyFilter = SymbolFilter diff --git a/src/vendor/market/order.ts b/src/vendor/market/order.ts index dcb6b2f..4af061b 100644 --- a/src/vendor/market/order.ts +++ b/src/vendor/market/order.ts @@ -1,26 +1,8 @@ -import { Currency } from '../interfaces/currency.enum'; +import { + OrderFill as BinanceOrderFill, + QueryOrderResult, +} from "binance-api-node" -export interface BaseOrderInfo { - id: string; - clientOrderId: string; - price: number; - symbol: Currency; - side: 'buy' | 'BUY' | 'sell' | 'SELL'; - type: 'limit' | 'LIMIT' | 'market' | 'MARKET' | 'stop' | 'STOP_LOSS' | 'STOP_LOSS_LIMIT'; - status: 'received' | 'open' | 'done' | 'pending' | 'FILLED'; - originQuantity: number; - executedQuantity: number; - transactionTime: number; - fills?: OrderFill[] -} +export type OrderResult = QueryOrderResult -export interface OrderResult extends BaseOrderInfo { - timeInForce: 'GTC' | 'GTT' | 'IOC' | 'FOK'; -} - -export interface OrderFill { - price: number - quantity: number - commission: number - commissionAsset: Currency -} \ No newline at end of file +export type OrderFill = BinanceOrderFill diff --git a/src/vendor/market/orders.ts b/src/vendor/market/orders.ts index 1981f0d..babfb38 100644 --- a/src/vendor/market/orders.ts +++ b/src/vendor/market/orders.ts @@ -1,38 +1,57 @@ -import { OrderType } from '../interfaces/order-type.enum'; -import { Currency } from '../interfaces/currency.enum'; -import { OrderResult } from './order'; +import { CancelOrderResult, Order } from "binance-api-node" +import { Currency } from "../interfaces/currency.enum" +import { OrderSide } from "../interfaces/order-type.enum" +import { OrderResult } from "./order" export interface Orders { - pending: OrderResult[] - done: OrderResult[] - canceled: OrderResult[] - lastOrder: OrderResult + pending: Order[] + done: Order[] + canceled: Order[] + lastOrder: Order - all(): Promise + all(): Promise - find?(id: string, status: OrderType): OrderResult + find?(id: string, status: OrderSide): Order - buyOrders(): OrderResult[] + buyOrders(): Order[] - sellOrders(): OrderResult[] + sellOrders(): Order[] - buyLimit(currency: Currency, quantity: number, price: number, allowTaker: boolean): Promise + buyLimit( + currency: Currency, + quantity: number, + price: number, + allowTaker: boolean + ): Promise - buyMarket(currency: Currency, funds: number, marketPrice?: number): Promise + buyMarket( + currency: Currency, + funds: number, + marketPrice?: number + ): Promise - buyStop(currency: Currency, price: number, funds: number): Promise + buyStop(currency: Currency, price: number, funds: number): Promise - sellLimit(currency: Currency, quantity: number, price: number, allowTaker: boolean): Promise + sellLimit( + currency: Currency, + quantity: number, + price: number, + allowTaker: boolean + ): Promise - sellMarket(currency: Currency, size: number, marketPrice?: number): Promise + sellMarket( + currency: Currency, + size: number, + marketPrice?: number + ): Promise - sellStop(currency: Currency, price: number, size: number): Promise - - normalizeQuantity?(quantity: number): number + sellStop(currency: Currency, price: number, size: number): Promise - getMinQuantity?(): number; + normalizeQuantity?(quantity: number): number - cancel(order: OrderResult): any + getMinQuantity?(): number + + cancel(order: Order): Promise } -export default Orders \ No newline at end of file +export default Orders diff --git a/src/vendor/slack/index.ts b/src/vendor/slack/index.ts index b25fd7f..e912151 100644 --- a/src/vendor/slack/index.ts +++ b/src/vendor/slack/index.ts @@ -1,36 +1,39 @@ -import * as SlackWebhook from 'slack-webhook'; -import Trader from '../trader/index'; +import * as SlackWebhook from "slack-webhook" +import Trader from "../trader/index" class Slack { - private trader: Trader - private webhook: SlackWebhook + private trader: Trader + private webhook: SlackWebhook - constructor(trader: Trader) { - this.webhook = new SlackWebhook('https://hooks.slack.com/services/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', { - defaults: { - username: 'Bot', - channel: '#trades', - icon_emoji: ':robot_face:' - } - }) - this.trader = trader - } + constructor(trader: Trader) { + this.webhook = new SlackWebhook( + "https://hooks.slack.com/services/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", + { + defaults: { + username: "Bot", + channel: "#trades", + icon_emoji: ":robot_face:", + }, + } + ) + this.trader = trader + } - buyMessage() { - this.webhook.send({ - text: `I bought ${this.trader.lastBuyTrade.quantity} ${this.trader.baseCurrency} at ${this.trader.lastBuyTrade.price} ${this.trader.quoteCurrency}`, - username: 'Theddy The Ruin', - icon_emoji: ':scream_cat:' - }) - } + buyMessage() { + this.webhook.send({ + text: `I bought ${this.trader.lastBuyTrade.quantity} ${this.trader.baseCurrency} at ${this.trader.lastBuyTrade.price} ${this.trader.quoteCurrency}`, + username: "Theddy The Ruin", + icon_emoji: ":scream_cat:", + }) + } - sellMessage() { - this.webhook.send({ - text: `I sold ${this.trader.lastSellTrade.quantity} ${this.trader.baseCurrency} at ${this.trader.lastSellTrade.price} ${this.trader.quoteCurrency} - Benefits: ${this.trader.lastSellTrade.benefits}%`, - username: 'Theddy The Ruin', - icon_emoji: ':scream_cat:' - }) - } + sellMessage() { + this.webhook.send({ + text: `I sold ${this.trader.lastSellTrade.quantity} ${this.trader.baseCurrency} at ${this.trader.lastSellTrade.price} ${this.trader.quoteCurrency} - Benefits: ${this.trader.lastSellTrade.benefits}%`, + username: "Theddy The Ruin", + icon_emoji: ":scream_cat:", + }) + } } -export default Slack \ No newline at end of file +export default Slack diff --git a/src/vendor/trader/data.ts b/src/vendor/trader/data.ts index 217613f..17bdba4 100644 --- a/src/vendor/trader/data.ts +++ b/src/vendor/trader/data.ts @@ -1,21 +1,21 @@ -import { ChartWork } from '../chart/chart-work'; -import { Currency } from '../interfaces/currency.enum'; -import { Trade } from './trade'; -import { TraderState } from './trader-state'; +import { ChartWork } from "../chart/chart-work" +import { Currency } from "../interfaces/currency.enum" +import { Trade } from "./trade" +import { TraderState } from "./trader-state" export interface DataStorage { - state: TraderState - works: ChartWork[] - worksSmoothed: ChartWork[] - trades: Trade[] - nextMinProfitablePrice: number - nextMaxProfitablePrice: number - nextPanicSellPrice: number - baseCurrency: Currency - baseCurrencyBalance: number - initialBaseCurrencyBalance: number - quoteCurrency: Currency - quoteCurrencyBalance: number - initialQuoteCurrencyBalance: number - startTime: Date -} \ No newline at end of file + state: TraderState + works: ChartWork[] + worksSmoothed: ChartWork[] + trades: Trade[] + nextMinProfitablePrice: number + nextMaxProfitablePrice: number + nextPanicSellPrice: number + baseCurrency: Currency + baseCurrencyBalance: number + initialBaseCurrencyBalance: number + quoteCurrency: Currency + quoteCurrencyBalance: number + initialQuoteCurrencyBalance: number + startTime: Date +} diff --git a/src/vendor/trader/index.ts b/src/vendor/trader/index.ts index 828ef1f..6af1775 100644 --- a/src/vendor/trader/index.ts +++ b/src/vendor/trader/index.ts @@ -1,556 +1,679 @@ -import ChartAnalyzer from '../chart/chart-analyzer'; -import ChartWorker from '../chart/chart-worker'; -import { config } from '../../config'; -import Equation from '../chart/equation'; -import Logger from '../logger/index'; -import Market from '../interfaces/market'; -import Trading from '../interfaces/trader'; -import { Accounts } from '../market/accounts'; -import { ChartWork } from '../chart/chart-work'; -import { Currency } from '../interfaces/currency.enum'; -import { Subscription } from 'rxjs/Subscription'; -import { Trade } from './trade'; -import { TraderState } from './trader-state'; -import { TradeType } from './trade-type'; -import { Trend } from '../chart/trend.enum'; -import { writeFile, readFile } from 'fs'; -import { OrderResult } from '../market/order'; -import { promisify } from 'util'; -import { DataStorage } from './data'; -import Slack from '../slack/index'; - +import { readFile, writeFile } from "fs" +import { Subscription } from "rxjs" +import { promisify } from "util" +import { config } from "../../config" +import ChartAnalyzer from "../chart/chart-analyzer" +import { ChartWork } from "../chart/chart-work" +import ChartWorker from "../chart/chart-worker" +import Equation from "../chart/equation" +import { Currency } from "../interfaces/currency.enum" +import Market from "../interfaces/market" +import Trading from "../interfaces/trader" +import Logger from "../logger/index" +import { Accounts } from "../market/accounts" +import Slack from "../slack/index" +import { DataStorage } from "./data" +import { Trade } from "./trade" +import { TradeType } from "./trade-type" +import { TraderState } from "./trader-state" class Trader implements Trading { - market: Market - accounts: Accounts - chartWorker: ChartWorker - workObserver: Subscription - state: TraderState - chartAnalyzer: ChartAnalyzer - quoteCurrency: Currency - quoteCurrencyBalance: number // €, $, £, etc. - initialQuoteCurrencyBalance: number - baseCurrency: Currency - baseCurrencyBalance: number // BTC, ETH, LTC, etc. - initialBaseCurrencyBalance: number - - trades: Trade[] - lastBuyTrade: Trade - lastSellTrade: Trade - - private works: ChartWork[] - private lastWork: ChartWork - private clearWorksAfterTrade: boolean - private slack: Slack - private startTime: Date - - constructor(market: Market) { - this.market = market - this.accounts = market.accounts - this.chartWorker = new ChartWorker(market) - this.works = [] - this.lastWork = null - this.trades = [] - this.lastBuyTrade = null - this.lastSellTrade = null - this.state = TraderState.WAITING_TO_BUY - this.chartAnalyzer = new ChartAnalyzer(this.chartWorker) - this.clearWorksAfterTrade = true - this.slack = new Slack(this) - - // Currencies - this.quoteCurrency = config.account.quoteCurrency - this.quoteCurrencyBalance = 0 - this.initialQuoteCurrencyBalance = null - this.baseCurrency = config.account.baseCurrency - this.baseCurrencyBalance = 0 - this.initialBaseCurrencyBalance = null + market: Market + accounts: Accounts + chartWorker: ChartWorker + workObserver: Subscription + state: TraderState + chartAnalyzer: ChartAnalyzer + quoteCurrency: Currency + quoteCurrencyBalance: number // €, $, £, etc. + initialQuoteCurrencyBalance: number + baseCurrency: Currency + baseCurrencyBalance: number // BTC, ETH, LTC, etc. + initialBaseCurrencyBalance: number + + trades: Trade[] + lastBuyTrade: Trade + lastSellTrade: Trade + + private works: ChartWork[] + private lastWork: ChartWork + private clearWorksAfterTrade: boolean + private slack: Slack + private startTime: Date + + constructor(market: Market) { + this.market = market + this.accounts = market.accounts + this.chartWorker = new ChartWorker(market) + this.works = [] + this.lastWork = null + this.trades = [] + this.lastBuyTrade = null + this.lastSellTrade = null + this.state = TraderState.WAITING_TO_BUY + this.chartAnalyzer = new ChartAnalyzer(this.chartWorker) + this.clearWorksAfterTrade = true + this.slack = new Slack(this) + + // Currencies + this.quoteCurrency = config.account.quoteCurrency + this.quoteCurrencyBalance = 0 + this.initialQuoteCurrencyBalance = null + this.baseCurrency = config.account.baseCurrency + this.baseCurrencyBalance = 0 + this.initialBaseCurrencyBalance = null + } + + async updateBalances() { + this.quoteCurrencyBalance = await this.accounts.availableFunds( + this.quoteCurrency + ) + this.baseCurrencyBalance = await this.accounts.availableFunds( + this.baseCurrency + ) + this.verifyBalances() + + if (null === this.initialBaseCurrencyBalance) { + this.initialBaseCurrencyBalance = this.baseCurrencyBalance } - async updateBalances() { - this.quoteCurrencyBalance = await this.accounts.availableFunds(this.quoteCurrency) - this.baseCurrencyBalance = await this.accounts.availableFunds(this.baseCurrency) - this.verifyBalances() - - if (null === this.initialBaseCurrencyBalance) { - this.initialBaseCurrencyBalance = this.baseCurrencyBalance - } - - if (null === this.initialQuoteCurrencyBalance) { - this.initialQuoteCurrencyBalance = this.quoteCurrencyBalance - } + if (null === this.initialQuoteCurrencyBalance) { + this.initialQuoteCurrencyBalance = this.quoteCurrencyBalance } - - private verifyBalances() { - if (this.quoteCurrencyBalance < config.trader.minQuantityQuoteCurrencyToUse) { - Logger.debug(`WARN: The ${this.quoteCurrency} balance (${this.quoteCurrencyBalance} ${this.quoteCurrency}) is under the min quantity desired to use (${config.trader.minQuantityQuoteCurrencyToUse} ${this.quoteCurrency})`) - } else if (this.quoteCurrencyBalance > config.trader.maxQuantityQuoteCurrencyToUse) { - Logger.debug(`The ${this.quoteCurrency} balance (${this.quoteCurrencyBalance} ${this.quoteCurrency}) is over the max quantity desired to use (${config.trader.maxQuantityQuoteCurrencyToUse} ${this.quoteCurrency})`) - Logger.debug('Using the max quantity as balance') - - this.quoteCurrencyBalance = config.trader.maxQuantityQuoteCurrencyToUse - } + } + + private verifyBalances() { + if ( + this.quoteCurrencyBalance < config.trader.minQuantityQuoteCurrencyToUse + ) { + Logger.debug( + `WARN: The ${this.quoteCurrency} balance (${this.quoteCurrencyBalance} ${this.quoteCurrency}) is under the min quantity desired to use (${config.trader.minQuantityQuoteCurrencyToUse} ${this.quoteCurrency})` + ) + } else if ( + this.quoteCurrencyBalance > config.trader.maxQuantityQuoteCurrencyToUse + ) { + Logger.debug( + `The ${this.quoteCurrency} balance (${this.quoteCurrencyBalance} ${this.quoteCurrency}) is over the max quantity desired to use (${config.trader.maxQuantityQuoteCurrencyToUse} ${this.quoteCurrency})` + ) + Logger.debug("Using the max quantity as balance") + + this.quoteCurrencyBalance = config.trader.maxQuantityQuoteCurrencyToUse } + } - async trade() { - if (!this.market.currency) { - Logger.error('Currency is not set, stopping trading.') - this.stop() - - return - } - - this.startTime = new Date() + async trade() { + if (!this.market.currency) { + Logger.error("Currency is not set, stopping trading.") + this.stop() - try { - await this.loadData() - await this.updateBalances() - - Logger.debug('\nBalances:') - Logger.debug(` ${this.quoteCurrency}: ${this.quoteCurrencyBalance}`) - Logger.debug(` ${this.baseCurrency}: ${this.baseCurrencyBalance}\n`) - } catch (error) { - Logger.error(`Fatal error occured while trying to retrieve account balances: ${JSON.stringify(error, null, 2)}`) - - return - } - - this.watchChartWorker() - this.chartWorker.startWorking() + return } - watchChartWorker() { - this.workObserver = this.chartWorker.work$.subscribe(async (work: ChartWork) => { - this.works = this.chartWorker.filterNoise(this.chartWorker.copyWorks()) - - const newLastWork = this.getLastWork() - - Logger.debug(`\n--------------- ${newLastWork.price} ${this.quoteCurrency} -----------------\n`) - - if (!this.worksAreEquals(newLastWork, this.lastWork)) { - this.lastWork = newLastWork - await this.analyzeWorks() - } else { - Logger.debug('Waiting a new point...') - } - - this.persistData() - - Logger.debug('\n') - }) + this.startTime = new Date() + + try { + await this.loadData() + await this.updateBalances() + + Logger.debug("\nBalances:") + Logger.debug(` ${this.quoteCurrency}: ${this.quoteCurrencyBalance}`) + Logger.debug(` ${this.baseCurrency}: ${this.baseCurrencyBalance}\n`) + } catch (error) { + Logger.error( + `Fatal error occured while trying to retrieve account balances: ${JSON.stringify( + error, + null, + 2 + )}` + ) + + return } - async analyzeWorks() { - Logger.debug('Analyzing chart...') - Logger.debug(`Time: ${this.lastWork.time}`) + this.watchChartWorker() + this.chartWorker.startWorking() + } - if (TraderState.WAITING_TO_BUY === this.state) { - await this.buyStrategies() - } else if (TraderState.WAITING_TO_SELL === this.state) { - await this.sellStrategies() - } else if (TraderState.WAITING_FOR_API_RESPONSE === this.state) { - Logger.debug('Trader tried to analyze next work before waiting api response for the last request. Please check your network latency.') - } else { - Logger.error(`Trader.state does not match any action: ${this.state}`) - this.stop() // No action to be done, trader is maybe crashed, need external intervention - } - } - - async buyStrategies() { - Logger.debug('Trader wants to buy.') + watchChartWorker() { + this.workObserver = this.chartWorker.work$.subscribe( + async (work: ChartWork) => { + this.works = this.chartWorker.filterNoise(this.chartWorker.copyWorks()) - /* - * Trader is waiting to buy - * we will try to know if we are in a hollow case or upward trend - */ - if (this.chartAnalyzer.detectHollow(this.works)/* || this.chartAnalyzer.isUpwardTrendConfirmed(this.lastWork, this.works)*/) { - const funds = this.fundsToUse() + const newLastWork = this.getLastWork() - Logger.debug(`Trader is buying at ${this.lastWork.price} ${this.quoteCurrency}`) + Logger.debug( + `\n--------------- ${newLastWork.price} ${this.quoteCurrency} -----------------\n` + ) - // We have sold, and the current price is below since the last price we sold so we can buy - await this.buy(funds) + if (!this.worksAreEquals(newLastWork, this.lastWork)) { + this.lastWork = newLastWork + await this.analyzeWorks() } else { - Logger.debug('Waiting for a buy signal...') + Logger.debug("Waiting a new point...") } - } - async sellStrategies() { - Logger.debug('Trader wants to sell.') + this.persistData() + + Logger.debug("\n") + } + ) + } + + async analyzeWorks() { + Logger.debug("Analyzing chart...") + Logger.debug(`Time: ${this.lastWork.time}`) + + if (TraderState.WAITING_TO_BUY === this.state) { + await this.buyStrategies() + } else if (TraderState.WAITING_TO_SELL === this.state) { + await this.sellStrategies() + } else if (TraderState.WAITING_FOR_API_RESPONSE === this.state) { + Logger.debug( + "Trader tried to analyze next work before waiting api response for the last request. Please check your network latency." + ) + } else { + Logger.error(`Trader.state does not match any action: ${this.state}`) + this.stop() // No action to be done, trader is maybe crashed, need external intervention + } + } + + async buyStrategies() { + Logger.debug("Trader wants to buy.") + + /* + * Trader is waiting to buy + * we will try to know if we are in a hollow case or upward trend + */ + if ( + this.chartAnalyzer.detectHollow( + this.works + ) /* || this.chartAnalyzer.isUpwardTrendConfirmed(this.lastWork, this.works)*/ + ) { + const funds = this.fundsToUse() + + Logger.debug( + `Trader is buying at ${this.lastWork.price} ${this.quoteCurrency}` + ) + + // We have sold, and the current price is below since the last price we sold so we can buy + await this.buy(funds) + } else { + Logger.debug("Waiting for a buy signal...") + } + } - let size - let priceToSell = this.lastWork.price + async sellStrategies() { + Logger.debug("Trader wants to sell.") - try { - size = this.market.orders.normalizeQuantity(this.sizeToUse()) - } catch (error) { - Logger.error(error) - this.stop() + let size + let priceToSell = this.lastWork.price - return - } + try { + size = this.market.orders.normalizeQuantity(this.sizeToUse()) + } catch (error) { + Logger.error(error) + this.stop() - if (config.trader.sellWhenPriceExceedsMaxThresholdOfProfitability && this.lastWork.price >= Equation.maxThresholdPriceOfProfitability(this.lastBuyTrade.price)) { - /* - * Option sellWhenPriceExceedsThresholdOfProfitability is activated - * So, we sell because de price exceeds the max threshold of profitability defined - */ - Logger.debug(`Max threshold of profitability reached (profitability: ${config.trader.maxThresholdOfProfitability}%)`) - Logger.debug(`Trader is selling at ${this.lastWork.price}`) - await this.sell(size) - } else if (config.trader.sellWhenPriceExceedsMinThresholdOfProfitability && Equation.isProfitable(this.lastBuyTrade.price, this.lastWork.price) && !Equation.isProfitable(this.lastBuyTrade.price, this.lastWork.lastPrice)) { - /* - * Options sellWhenPriceExceedsMinThresholdOfProfitability is activated - * So, we sell because de price exceeds the min threshold of profitability defined - */ - Logger.debug(`Min threshold of profitability reached (profitability: ${config.trader.minThresholdOfProfitability}%)`) - Logger.debug(`Trader is selling at ${this.lastWork.price}`) - - let partSizeToSell = size * (config.trader.quantityToSellWhenPriceExceedsMinThresholdOfProfitability / 100) - const minQuantity = this.market.orders.getMinQuantity() - - Logger.debug(`Quantity desired to sell: ${partSizeToSell} ${this.baseCurrency} (${config.trader.quantityToSellWhenPriceExceedsMinThresholdOfProfitability}%)`) - - try { - partSizeToSell = this.market.orders.normalizeQuantity(partSizeToSell) - this.clearWorksAfterTrade = false // We will want to sell if there is a bump after min threshold and max threshold not reached - - const quantityRemaining = this.market.orders.normalizeQuantity(size - partSizeToSell) - - if (quantityRemaining < minQuantity) { - // The remaining quantity is below the minQuantity, so we sell all the quantity - Logger.debug(`If we sell ${config.trader.quantityToSellWhenPriceExceedsMinThresholdOfProfitability}% of the quantity, the remaining quantity is below the minQuantity. Selling all the quantity`) - partSizeToSell = size - this.clearWorksAfterTrade = true - } - } catch (error) { - // partSizeToSell is below the minQuantity, we set it to it - Logger.debug(`${config.trader.quantityToSellWhenPriceExceedsMinThresholdOfProfitability}% of the quantity is below the minQuantity. Taking the minQuantity as quantity to sell`) - partSizeToSell = minQuantity - } - - Logger.debug(`Selling ${partSizeToSell} ${this.baseCurrency}`) - - const partial = partSizeToSell !== size // if we don't sell all the size, this means we only sell a part - - await this.sell(partSizeToSell, partial) - } else if (config.trader.useExitStrategyInCaseOfLosses && Equation.rateBetweenValues(this.lastBuyTrade.price, this.lastWork.price) <= -config.trader.sellWhenLossRateReaches) { - /* - * Option useExitStrategyInCaseOfLosses is activated - * So, we sell because the loss is below the limit we fixed - */ - Logger.debug('Threshold of loss rate reached') - Logger.debug(`Trader is selling at ${this.lastWork.price}`) - await this.sell(size) - } else if (this.chartAnalyzer.detectBump(this.works)) { - /* - * We found a bump, is the trader is profitable, he sells - */ - Logger.debug('Bump detected!') - - if (Equation.isProfitable(this.lastBuyTrade.price, this.lastWork.price)) { - Logger.debug(`Trader is selling at ${this.lastWork.price}`) - await this.sell(size) - } else { - Logger.debug('Not sold! Was not profitable') - - // Bump was not enough up in order to sell, but we clear works in order to avoid to loop through it later in analyzer - this.prepareForNewTrade() - } - } else if (!this.chartWorker.isInFastMode() && this.chartAnalyzer.detectProfitablePump(this.works, this.lastBuyTrade.price)) { - /* - * Fast mode - * Detect pump which can be profitable to sell in - * We accelerate the ticker interval until trader try to sell - */ - Logger.debug('Fast mode activated') - this.chartWorker.fastMode() - } else { - Logger.debug('Waiting for a sell signal...') - } + return } - fundsToUse(): number { - const funds = (config.trader.quantityOfQuoteCurrencyToUse / 100) * this.quoteCurrencyBalance - - if (funds > config.trader.maxQuantityQuoteCurrencyToUse) { - return config.trader.maxQuantityQuoteCurrencyToUse + if ( + config.trader.sellWhenPriceExceedsMaxThresholdOfProfitability && + this.lastWork.price >= + Equation.maxThresholdPriceOfProfitability(this.lastBuyTrade.price) + ) { + /* + * Option sellWhenPriceExceedsThresholdOfProfitability is activated + * So, we sell because de price exceeds the max threshold of profitability defined + */ + Logger.debug( + `Max threshold of profitability reached (profitability: ${config.trader.maxThresholdOfProfitability}%)` + ) + Logger.debug(`Trader is selling at ${this.lastWork.price}`) + await this.sell(size) + } else if ( + config.trader.sellWhenPriceExceedsMinThresholdOfProfitability && + Equation.isProfitable(this.lastBuyTrade.price, this.lastWork.price) && + !Equation.isProfitable(this.lastBuyTrade.price, this.lastWork.lastPrice) + ) { + /* + * Options sellWhenPriceExceedsMinThresholdOfProfitability is activated + * So, we sell because de price exceeds the min threshold of profitability defined + */ + Logger.debug( + `Min threshold of profitability reached (profitability: ${config.trader.minThresholdOfProfitability}%)` + ) + Logger.debug(`Trader is selling at ${this.lastWork.price}`) + + let partSizeToSell = + size * + (config.trader + .quantityToSellWhenPriceExceedsMinThresholdOfProfitability / + 100) + const minQuantity = this.market.orders.getMinQuantity() + + Logger.debug( + `Quantity desired to sell: ${partSizeToSell} ${this.baseCurrency} (${config.trader.quantityToSellWhenPriceExceedsMinThresholdOfProfitability}%)` + ) + + try { + partSizeToSell = this.market.orders.normalizeQuantity(partSizeToSell) + this.clearWorksAfterTrade = false // We will want to sell if there is a bump after min threshold and max threshold not reached + + const quantityRemaining = this.market.orders.normalizeQuantity( + size - partSizeToSell + ) + + if (quantityRemaining < minQuantity) { + // The remaining quantity is below the minQuantity, so we sell all the quantity + Logger.debug( + `If we sell ${config.trader.quantityToSellWhenPriceExceedsMinThresholdOfProfitability}% of the quantity, the remaining quantity is below the minQuantity. Selling all the quantity` + ) + partSizeToSell = size + this.clearWorksAfterTrade = true } + } catch (error) { + // partSizeToSell is below the minQuantity, we set it to it + Logger.debug( + `${config.trader.quantityToSellWhenPriceExceedsMinThresholdOfProfitability}% of the quantity is below the minQuantity. Taking the minQuantity as quantity to sell` + ) + partSizeToSell = minQuantity + } + + Logger.debug(`Selling ${partSizeToSell} ${this.baseCurrency}`) + + const partial = partSizeToSell !== size // if we don't sell all the size, this means we only sell a part + + await this.sell(partSizeToSell, partial) + } else if ( + config.trader.useExitStrategyInCaseOfLosses && + Equation.rateBetweenValues( + this.lastBuyTrade.price, + this.lastWork.price + ) <= -config.trader.sellWhenLossRateReaches + ) { + /* + * Option useExitStrategyInCaseOfLosses is activated + * So, we sell because the loss is below the limit we fixed + */ + Logger.debug("Threshold of loss rate reached") + Logger.debug(`Trader is selling at ${this.lastWork.price}`) + await this.sell(size) + } else if (this.chartAnalyzer.detectBump(this.works)) { + /* + * We found a bump, is the trader is profitable, he sells + */ + Logger.debug("Bump detected!") + + if (Equation.isProfitable(this.lastBuyTrade.price, this.lastWork.price)) { + Logger.debug(`Trader is selling at ${this.lastWork.price}`) + await this.sell(size) + } else { + Logger.debug("Not sold! Was not profitable") + + // Bump was not enough up in order to sell, but we clear works in order to avoid to loop through it later in analyzer + this.prepareForNewTrade() + } + } else if ( + !this.chartWorker.isInFastMode() && + this.chartAnalyzer.detectProfitablePump( + this.works, + this.lastBuyTrade.price + ) + ) { + /* + * Fast mode + * Detect pump which can be profitable to sell in + * We accelerate the ticker interval until trader try to sell + */ + Logger.debug("Fast mode activated") + this.chartWorker.fastMode() + } else { + Logger.debug("Waiting for a sell signal...") + } + } - if (funds < config.trader.minQuantityQuoteCurrencyToUse) { - if (config.trader.minQuantityQuoteCurrencyToUse > this.quoteCurrencyBalance) { - Logger.debug(`Trader has not enough funds (minQuantityQuoteCurrencyToUse is not respected: ${config.trader.minQuantityQuoteCurrencyToUse}, current balance: ${this.quoteCurrencyBalance})`) - this.stop() - } + fundsToUse(): number { + const funds = + (config.trader.quantityOfQuoteCurrencyToUse / 100) * + this.quoteCurrencyBalance - return config.trader.minQuantityQuoteCurrencyToUse - } - - return funds + if (funds > config.trader.maxQuantityQuoteCurrencyToUse) { + return config.trader.maxQuantityQuoteCurrencyToUse } - sizeToUse(): number { - return (config.trader.quantityOfBaseCurrencyToUse / 100) * this.baseCurrencyBalance + if (funds < config.trader.minQuantityQuoteCurrencyToUse) { + if ( + config.trader.minQuantityQuoteCurrencyToUse > this.quoteCurrencyBalance + ) { + Logger.debug( + `Trader has not enough funds (minQuantityQuoteCurrencyToUse is not respected: ${config.trader.minQuantityQuoteCurrencyToUse}, current balance: ${this.quoteCurrencyBalance})` + ) + this.stop() + } + + return config.trader.minQuantityQuoteCurrencyToUse } - prepareForNewTrade() { - if (this.clearWorksAfterTrade) { - this.chartWorker.prepareForNewWorks() - } else { - this.clearWorksAfterTrade = true // next time we come back to the default behaviour - } + return funds + } + + sizeToUse(): number { + return ( + (config.trader.quantityOfBaseCurrencyToUse / 100) * + this.baseCurrencyBalance + ) + } + + prepareForNewTrade() { + if (this.clearWorksAfterTrade) { + this.chartWorker.prepareForNewWorks() + } else { + this.clearWorksAfterTrade = true // next time we come back to the default behaviour } - - async buy(funds: number) { - try { - if (!Number.isFinite(funds)) { - throw new Error(`Cannot buy, funds are invalid: ${funds}`) - } - - Logger.debug(`Trying to buy with ${funds} ${this.quoteCurrency}`) - Logger.debug('Sending order to the market...') - - this.state = TraderState.WAITING_FOR_API_RESPONSE - - const lastWorkBackup = { ...this.lastWork } - - const order = await this.market.orders.buyMarket(this.market.currency, funds, lastWorkBackup.price) - const price = order.price || lastWorkBackup.price - const fundsUsed = price * order.executedQuantity - const fees = fundsUsed * config.market.orderFees - - if (config.api.sandbox) { - this.quoteCurrencyBalance -= fundsUsed - this.baseCurrencyBalance += order.executedQuantity - } else { - await this.updateBalances() - } - - Logger.debug(`Order formatted: ${JSON.stringify(order, null, 2)}`) - - if (lastWorkBackup.price !== price) { - Logger.debug(`WARN: prices have diverged when bot wanted to buy.`) - Logger.debug(`Bot buy price desired: ${lastWorkBackup.price}`) - Logger.debug(`Real order price: ${price} ${this.quoteCurrency}`) - } - - this.lastBuyTrade = { - price, - time: lastWorkBackup.time, - benefits: -fundsUsed, - fees, - type: TradeType.BUY, - quantity: order.executedQuantity - } - - this.actionsPostBuyTrade() - - Logger.debug(` + } + + async buy(funds: number) { + try { + if (!Number.isFinite(funds)) { + throw new Error(`Cannot buy, funds are invalid: ${funds}`) + } + + Logger.debug(`Trying to buy with ${funds} ${this.quoteCurrency}`) + Logger.debug("Sending order to the market...") + + this.state = TraderState.WAITING_FOR_API_RESPONSE + + const lastWorkBackup = { ...this.lastWork } + + const order = await this.market.orders.buyMarket( + this.market.currency, + funds, + lastWorkBackup.price + ) + const price = order.price || lastWorkBackup.price + const fundsUsed = price * order.executedQuantity + const fees = fundsUsed * config.market.orderFees + + if (config.api.sandbox) { + this.quoteCurrencyBalance -= fundsUsed + this.baseCurrencyBalance += order.executedQuantity + } else { + await this.updateBalances() + } + + Logger.debug(`Order formatted: ${JSON.stringify(order, null, 2)}`) + + if (lastWorkBackup.price !== price) { + Logger.debug(`WARN: prices have diverged when bot wanted to buy.`) + Logger.debug(`Bot buy price desired: ${lastWorkBackup.price}`) + Logger.debug(`Real order price: ${price} ${this.quoteCurrency}`) + } + + this.lastBuyTrade = { + price, + time: lastWorkBackup.time, + benefits: -fundsUsed, + fees, + type: TradeType.BUY, + quantity: order.executedQuantity, + } + + this.actionsPostBuyTrade() + + Logger.debug(` ____ ____ ____ ||B |||U |||Y || ||__|||__|||__|| |/__\\|/__\\|/__\\| `) - Logger.debug(`Last buy trade: ${JSON.stringify(this.lastBuyTrade, null, 2)}`) - Logger.debug(`Would be able to sell when the price will be above ${Equation.thresholdPriceOfProfitability(this.lastBuyTrade.price).toFixed(8)}${this.quoteCurrency}`) - Logger.debug(`Funds desired to invest: ${funds}${this.quoteCurrency}`) - Logger.debug(`Funds really invested: ${fundsUsed}${this.quoteCurrency}`) - } catch (error) { - Logger.error(`Error when trying to buy: ${JSON.stringify(error, null, 2)}`) - this.stop() - } + Logger.debug( + `Last buy trade: ${JSON.stringify(this.lastBuyTrade, null, 2)}` + ) + Logger.debug( + `Would be able to sell when the price will be above ${Equation.thresholdPriceOfProfitability( + this.lastBuyTrade.price + ).toFixed(8)}${this.quoteCurrency}` + ) + Logger.debug(`Funds desired to invest: ${funds}${this.quoteCurrency}`) + Logger.debug(`Funds really invested: ${fundsUsed}${this.quoteCurrency}`) + } catch (error) { + Logger.error( + `Error when trying to buy: ${JSON.stringify(error, null, 2)}` + ) + this.stop() } - - async sell(size: number, partial?: boolean) { - try { - if (!Number.isFinite(size)) { - throw new Error(`Cannot sell, funds are invalid: ${size}`) - } - - // do not check last trade type, because trader might wants to sell only a part on the quantity, and sell the rest later - - Logger.debug(`Trying to sell ${size} ${this.baseCurrency}`) - Logger.debug('Sending order to the market...') - - this.state = TraderState.WAITING_FOR_API_RESPONSE - - const lastWorkBackup = { ...this.lastWork } - - const order = await this.market.orders.sellMarket(this.market.currency, size, lastWorkBackup.price) - const price = order.price || lastWorkBackup.price - const fees = (price * order.executedQuantity) * config.market.orderFees - const quoteCurrencyQuantity = (price * order.executedQuantity) - fees - - if (config.api.sandbox) { - this.quoteCurrencyBalance += quoteCurrencyQuantity - this.baseCurrencyBalance -= order.executedQuantity - } else { - await this.updateBalances() - } - - Logger.debug(`Order formatted: ${JSON.stringify(order, null, 2)}`) - - if (lastWorkBackup.price !== price) { - Logger.debug(`WARN: prices have diverged when bot wanted to sell.`) - Logger.debug(`Bot sell price desired: ${lastWorkBackup.price}`) - Logger.debug(`Real order price: ${price} ${this.quoteCurrency}`) - } - - this.lastSellTrade = { - price, - time: lastWorkBackup.time, - benefits: Equation.rateBetweenValues(this.lastBuyTrade.price, price) - (2 * (config.market.orderFees * 100)), - fees, - type: partial ? TradeType.SELL_PARTIAL : TradeType.SELL, - quantity: order.executedQuantity - } - - this.actionsPostSellTrade() - - if (partial) { - this.state = TraderState.WAITING_TO_SELL // Trader sold only a part, he has to sell the rest - } - - Logger.debug(` + } + + async sell(size: number, partial?: boolean) { + try { + if (!Number.isFinite(size)) { + throw new Error(`Cannot sell, funds are invalid: ${size}`) + } + + // do not check last trade type, because trader might wants to sell only a part on the quantity, and sell the rest later + + Logger.debug(`Trying to sell ${size} ${this.baseCurrency}`) + Logger.debug("Sending order to the market...") + + this.state = TraderState.WAITING_FOR_API_RESPONSE + + const lastWorkBackup = { ...this.lastWork } + + const order = await this.market.orders.sellMarket( + this.market.currency, + size, + lastWorkBackup.price + ) + const price = order.price || lastWorkBackup.price + const fees = price * order.executedQuantity * config.market.orderFees + const quoteCurrencyQuantity = price * order.executedQuantity - fees + + if (config.api.sandbox) { + this.quoteCurrencyBalance += quoteCurrencyQuantity + this.baseCurrencyBalance -= order.executedQuantity + } else { + await this.updateBalances() + } + + Logger.debug(`Order formatted: ${JSON.stringify(order, null, 2)}`) + + if (lastWorkBackup.price !== price) { + Logger.debug(`WARN: prices have diverged when bot wanted to sell.`) + Logger.debug(`Bot sell price desired: ${lastWorkBackup.price}`) + Logger.debug(`Real order price: ${price} ${this.quoteCurrency}`) + } + + this.lastSellTrade = { + price, + time: lastWorkBackup.time, + benefits: + Equation.rateBetweenValues(this.lastBuyTrade.price, price) - + 2 * (config.market.orderFees * 100), + fees, + type: partial ? TradeType.SELL_PARTIAL : TradeType.SELL, + quantity: order.executedQuantity, + } + + this.actionsPostSellTrade() + + if (partial) { + this.state = TraderState.WAITING_TO_SELL // Trader sold only a part, he has to sell the rest + } + + Logger.debug(` ____ ____ ____ ____ ||S |||e |||l |||l || ||__|||__|||__|||__|| |/__\\|/__\\|/__\\|/__\\| `) - Logger.debug(`Last trade: ${JSON.stringify(this.lastSellTrade, null, 2)}`) - } catch (error) { - Logger.error(`Error when trying to sell: ${error}`) - this.stop() - } + Logger.debug(`Last trade: ${JSON.stringify(this.lastSellTrade, null, 2)}`) + } catch (error) { + Logger.error(`Error when trying to sell: ${error}`) + this.stop() } - - private actionsPostBuyTrade() { - this.trades.push({ ...this.lastBuyTrade }) - this.prepareForNewTrade() - this.state = TraderState.WAITING_TO_SELL - this.slack.buyMessage() - } - - private actionsPostSellTrade() { - this.trades.push({ ...this.lastSellTrade }) - this.prepareForNewTrade() - this.state = TraderState.WAITING_TO_BUY - this.slack.sellMessage() + } + + private actionsPostBuyTrade() { + this.trades.push({ ...this.lastBuyTrade }) + this.prepareForNewTrade() + this.state = TraderState.WAITING_TO_SELL + this.slack.buyMessage() + } + + private actionsPostSellTrade() { + this.trades.push({ ...this.lastSellTrade }) + this.prepareForNewTrade() + this.state = TraderState.WAITING_TO_BUY + this.slack.sellMessage() + } + + private getLastWork(): ChartWork { + if (this.works.length === 0) { + return null } - private getLastWork(): ChartWork { - if (this.works.length === 0) { - return null - } + const lastWork = { ...this.works[this.works.length - 1] } - const lastWork = { ...this.works[this.works.length - 1] } + return lastWork + } - return lastWork - } - - stop() { - Logger.warn('Trader has been stopped.') - this.killWatchers() - } + stop() { + Logger.warn("Trader has been stopped.") + this.killWatchers() + } - killWatchers() { - if (this.workObserver) { - this.workObserver.unsubscribe() - } + killWatchers() { + if (this.workObserver) { + this.workObserver.unsubscribe() } + } - private worksAreEquals(workA: ChartWork, workB: ChartWork): boolean { - if (!workA || !workB) { - return false - } - - return workA.time === workB.time + private worksAreEquals(workA: ChartWork, workB: ChartWork): boolean { + if (!workA || !workB) { + return false } - private async loadData() { - Logger.debug('Loading data from data.json...') + return workA.time === workB.time + } - try { - const read = promisify(readFile) + private async loadData() { + Logger.debug("Loading data from data.json...") - const dataString = await read('./data.json', { encoding: 'utf-8' }) + try { + const read = promisify(readFile) - if (dataString && dataString.length > 0) { - const data: DataStorage = JSON.parse(dataString) + const dataString = await read("./data.json", { encoding: "utf-8" }) - this.trades = data.trades - this.startTime = new Date(data.startTime) - this.initialBaseCurrencyBalance = data.initialBaseCurrencyBalance - this.initialQuoteCurrencyBalance = data.initialQuoteCurrencyBalance - - const lastTrade = this.trades.length > 0 ? this.trades[this.trades.length - 1] : null - const restartFromTime = lastTrade ? lastTrade.time : 0 + if (dataString && dataString.length > 0) { + const data: DataStorage = JSON.parse(dataString) - this.chartWorker.initFromWorks(data.works, restartFromTime) + this.trades = data.trades + this.startTime = new Date(data.startTime) + this.initialBaseCurrencyBalance = data.initialBaseCurrencyBalance + this.initialQuoteCurrencyBalance = data.initialQuoteCurrencyBalance - if (lastTrade) { - this.lastBuyTrade = this.findLastBuyTrade(this.trades) - this.lastSellTrade = this.findLastSellTrade(this.trades) + const lastTrade = + this.trades.length > 0 ? this.trades[this.trades.length - 1] : null + const restartFromTime = lastTrade ? lastTrade.time : 0 - if (TradeType.BUY === lastTrade.type || TradeType.SELL_PARTIAL === lastTrade.type) { - this.state = TraderState.WAITING_TO_SELL - } else { - this.state = TraderState.WAITING_TO_BUY - } + this.chartWorker.initFromWorks(data.works, restartFromTime) - Logger.debug(`Starting from a previous trade: ${JSON.stringify(lastTrade, null, 2)}`) - } + if (lastTrade) { + this.lastBuyTrade = this.findLastBuyTrade(this.trades) + this.lastSellTrade = this.findLastSellTrade(this.trades) - Logger.debug('Data loaded.') - } - } catch (error) { - Logger.debug('File data.json does not exist or contains invalid json') - } + if ( + TradeType.BUY === lastTrade.type || + TradeType.SELL_PARTIAL === lastTrade.type + ) { + this.state = TraderState.WAITING_TO_SELL + } else { + this.state = TraderState.WAITING_TO_BUY + } - if (!this.lastBuyTrade && !this.lastSellTrade) { - Logger.debug('\nNo old trades found, starting from scratch.\n') + Logger.debug( + `Starting from a previous trade: ${JSON.stringify( + lastTrade, + null, + 2 + )}` + ) } - } - private findLastBuyTrade(trades: Trade[]): Trade { - return trades.slice().reverse().find(trade => trade.type === TradeType.BUY) + Logger.debug("Data loaded.") + } + } catch (error) { + Logger.debug("File data.json does not exist or contains invalid json") } - private findLastSellTrade(trades: Trade[]): Trade { - return trades.slice().reverse().find(trade => trade.type === TradeType.SELL || trade.type === TradeType.SELL_PARTIAL) + if (!this.lastBuyTrade && !this.lastSellTrade) { + Logger.debug("\nNo old trades found, starting from scratch.\n") } - - private async persistData() { - try { - const write = promisify(writeFile) - - await write('./data.json', JSON.stringify(this.forgeData(), null, 2), { encoding: 'utf-8' }) - } catch (error) { - Logger.error('\nError when trying to persist data.\n') - Logger.error(error) - } + } + + private findLastBuyTrade(trades: Trade[]): Trade { + return trades + .slice() + .reverse() + .find((trade) => trade.type === TradeType.BUY) + } + + private findLastSellTrade(trades: Trade[]): Trade { + return trades + .slice() + .reverse() + .find( + (trade) => + trade.type === TradeType.SELL || trade.type === TradeType.SELL_PARTIAL + ) + } + + private async persistData() { + try { + const write = promisify(writeFile) + + await write("./data.json", JSON.stringify(this.forgeData(), null, 2), { + encoding: "utf-8", + }) + } catch (error) { + Logger.error("\nError when trying to persist data.\n") + Logger.error(error) } - - private forgeData(): DataStorage { - return { - state: this.state, - works: this.chartWorker.allWorks, - worksSmoothed: this.chartWorker.filterNoise(this.chartWorker.copyWorks(this.chartWorker.allWorks)), - trades: this.trades, - nextMinProfitablePrice: this.state === TraderState.WAITING_TO_SELL ? Equation.thresholdPriceOfProfitability(this.lastBuyTrade.price) : null, - nextMaxProfitablePrice: this.state === TraderState.WAITING_TO_SELL ? Equation.maxThresholdPriceOfProfitability(this.lastBuyTrade.price) : null, - nextPanicSellPrice: this.state === TraderState.WAITING_TO_SELL ? this.lastBuyTrade.price * (100 - config.trader.sellWhenLossRateReaches) : null, - baseCurrency: this.baseCurrency, - baseCurrencyBalance: this.baseCurrencyBalance, - initialBaseCurrencyBalance: this.initialBaseCurrencyBalance, - quoteCurrency: this.quoteCurrency, - quoteCurrencyBalance: this.quoteCurrencyBalance, - initialQuoteCurrencyBalance: this.initialQuoteCurrencyBalance, - startTime: this.startTime - } + } + + private forgeData(): DataStorage { + return { + state: this.state, + works: this.chartWorker.allWorks, + worksSmoothed: this.chartWorker.filterNoise( + this.chartWorker.copyWorks(this.chartWorker.allWorks) + ), + trades: this.trades, + nextMinProfitablePrice: + this.state === TraderState.WAITING_TO_SELL + ? Equation.thresholdPriceOfProfitability(this.lastBuyTrade.price) + : null, + nextMaxProfitablePrice: + this.state === TraderState.WAITING_TO_SELL + ? Equation.maxThresholdPriceOfProfitability(this.lastBuyTrade.price) + : null, + nextPanicSellPrice: + this.state === TraderState.WAITING_TO_SELL + ? this.lastBuyTrade.price * + (100 - config.trader.sellWhenLossRateReaches) + : null, + baseCurrency: this.baseCurrency, + baseCurrencyBalance: this.baseCurrencyBalance, + initialBaseCurrencyBalance: this.initialBaseCurrencyBalance, + quoteCurrency: this.quoteCurrency, + quoteCurrencyBalance: this.quoteCurrencyBalance, + initialQuoteCurrencyBalance: this.initialQuoteCurrencyBalance, + startTime: this.startTime, } + } } -export default Trader \ No newline at end of file +export default Trader diff --git a/src/vendor/trader/trade-type.ts b/src/vendor/trader/trade-type.ts index 8878486..291c7ee 100644 --- a/src/vendor/trader/trade-type.ts +++ b/src/vendor/trader/trade-type.ts @@ -1,5 +1,5 @@ export enum TradeType { - SELL, - SELL_PARTIAL, - BUY -} \ No newline at end of file + SELL, + SELL_PARTIAL, + BUY, +} diff --git a/src/vendor/trader/trade.ts b/src/vendor/trader/trade.ts index d364aa3..a62d01d 100644 --- a/src/vendor/trader/trade.ts +++ b/src/vendor/trader/trade.ts @@ -1,10 +1,10 @@ -import { TradeType } from './trade-type'; +import { TradeType } from "./trade-type" export interface Trade { - price: number - quantity: number - time: number - benefits: number - fees: number - type: TradeType -} \ No newline at end of file + price: number + quantity: number + time: number + benefits: number + fees: number + type: TradeType +} diff --git a/src/vendor/trader/trader-state.ts b/src/vendor/trader/trader-state.ts index 31c2a38..6e8e0aa 100644 --- a/src/vendor/trader/trader-state.ts +++ b/src/vendor/trader/trader-state.ts @@ -1,5 +1,5 @@ export enum TraderState { - WAITING_TO_SELL, - WAITING_TO_BUY, - WAITING_FOR_API_RESPONSE -} \ No newline at end of file + WAITING_TO_SELL, + WAITING_TO_BUY, + WAITING_FOR_API_RESPONSE, +} From 6ef64d2513fef55bf9c72c5571e73799854e80a8 Mon Sep 17 00:00:00 2001 From: Julien Sergent Date: Fri, 2 Apr 2021 00:15:47 +0200 Subject: [PATCH 2/2] fix(app): makes it work again --- README.md | 8 +- index.html | 17 +- package-lock.json | 4006 ++++++++++++++++++++++-- package.json | 3 +- src/config/config.binance.ts | 6 +- src/config/config.gdax.ts | 64 - src/config/index.ts | 7 +- src/config/platform.ts | 1 - src/index.ts | 7 +- src/markets/gdax/accounts.ts | 131 - src/markets/gdax/index.ts | 111 - src/markets/gdax/orders.ts | 250 -- src/vendor/interfaces/currency.enum.ts | 1465 ++++++++- src/vendor/trader/index.ts | 29 +- 14 files changed, 5220 insertions(+), 885 deletions(-) delete mode 100644 src/config/config.gdax.ts delete mode 100644 src/markets/gdax/accounts.ts delete mode 100644 src/markets/gdax/index.ts delete mode 100644 src/markets/gdax/orders.ts diff --git a/README.md b/README.md index 11f563b..b6b4d09 100644 --- a/README.md +++ b/README.md @@ -8,16 +8,13 @@ cd theddy npm install ``` -Create your API keys on the platform (binance, gdax, etc.) and export them as environment vars. +Create your API keys on the platform (binance, etc.) and export them as environment vars. For exemple, on Linux, add to your ~/.bashrc the following lines: ```bash export BINANCE_API_KEY= export BINANCE_API_SECRET= export BINANCE_API_PASSPHRASE= -export GDAX_API_KEY= -export GDAX_API_SECRET= -export GDAX_API_PASSPHRASE= ``` ## Getting started @@ -57,9 +54,6 @@ Then add the following lines to the .env file: BINANCE_API_KEY=xxxxxx BINANCE_API_SECRET=xxxxx BINANCE_API_PASSPHRASE=xxxxx -GDAX_API_KEY=xxxx -GDAX_API_SECRET=xxxxx -GDAX_API_PASSPHRASE=xxxxx ``` ### Build diff --git a/index.html b/index.html index c819e1d..85b4f36 100644 --- a/index.html +++ b/index.html @@ -18,8 +18,6 @@ } #myChart { - width: 99% !important; - max-height: 700px !important; margin: 0; padding: 0; } @@ -261,7 +259,18 @@

Next price of panic sell

} function drawChart() { - const context = document.querySelector("#myChart").getContext('2d') + const chart = document.querySelector("#myChart") + const context = chart.getContext('2d') + const scale = window.devicePixelRatio + const width = window.innerWidth; + const height = 700; + + chart.style.width = `${width}px`; + chart.style.height = `${height}px`; + chart.width = Math.floor(width * scale); + chart.height = Math.floor(height * scale); + context.scale(scale, scale); + const newChart = new Chart(context, { type: 'scatter', data: { @@ -461,4 +470,4 @@

Next price of panic sell

- \ No newline at end of file + diff --git a/package-lock.json b/package-lock.json index b184bbb..4798837 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,3760 @@ { "name": "bot", "version": "0.3.7", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "bot", + "version": "0.3.7", + "license": "MIT", + "dependencies": { + "binance-api-node": "^0.10.35", + "delay": "^5.0.0", + "lite-server": "^2.6.1", + "node-binance-api": "^0.12.5", + "nodemon": "^2.0.7", + "rxjs": "^6.6.7", + "slack-webhook": "^1.0.0", + "typescript": "^4.2.3" + }, + "devDependencies": { + "@types/node": "^14.14.37", + "@types/rx": "^4.1.2", + "prettier": "^2.2.1", + "tsc-watch": "^4.2.9" + } + }, + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@types/node": { + "version": "14.14.37", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz", + "integrity": "sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==", + "dev": true + }, + "node_modules/@types/rx": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@types/rx/-/rx-4.1.2.tgz", + "integrity": "sha512-1r8ZaT26Nigq7o4UBGl+aXB2UMFUIdLPP/8bLIP0x3d0pZL46ybKKjhWKaJQWIkLl5QCLD0nK3qTOO1QkwdFaA==", + "dev": true, + "dependencies": { + "@types/rx-core": "*", + "@types/rx-core-binding": "*", + "@types/rx-lite": "*", + "@types/rx-lite-aggregates": "*", + "@types/rx-lite-async": "*", + "@types/rx-lite-backpressure": "*", + "@types/rx-lite-coincidence": "*", + "@types/rx-lite-experimental": "*", + "@types/rx-lite-joinpatterns": "*", + "@types/rx-lite-testing": "*", + "@types/rx-lite-time": "*", + "@types/rx-lite-virtualtime": "*" + } + }, + "node_modules/@types/rx-core": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/rx-core/-/rx-core-4.0.3.tgz", + "integrity": "sha1-CzNUsSOM7b4rdPYybxOdvHpZHWA=", + "dev": true + }, + "node_modules/@types/rx-core-binding": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/rx-core-binding/-/rx-core-binding-4.0.4.tgz", + "integrity": "sha512-5pkfxnC4w810LqBPUwP5bg7SFR/USwhMSaAeZQQbEHeBp57pjKXRlXmqpMrLJB4y1oglR/c2502853uN0I+DAQ==", + "dev": true, + "dependencies": { + "@types/rx-core": "*" + } + }, + "node_modules/@types/rx-lite": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/rx-lite/-/rx-lite-4.0.6.tgz", + "integrity": "sha512-oYiDrFIcor9zDm0VDUca1UbROiMYBxMLMaM6qzz4ADAfOmA9r1dYEcAFH+2fsPI5BCCjPvV9pWC3X3flbrvs7w==", + "dev": true, + "dependencies": { + "@types/rx-core": "*", + "@types/rx-core-binding": "*" + } + }, + "node_modules/@types/rx-lite-aggregates": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/rx-lite-aggregates/-/rx-lite-aggregates-4.0.3.tgz", + "integrity": "sha512-MAGDAHy8cRatm94FDduhJF+iNS5//jrZ/PIfm+QYw9OCeDgbymFHChM8YVIvN2zArwsRftKgE33QfRWvQk4DPg==", + "dev": true, + "dependencies": { + "@types/rx-lite": "*" + } + }, + "node_modules/@types/rx-lite-async": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/rx-lite-async/-/rx-lite-async-4.0.2.tgz", + "integrity": "sha512-vTEv5o8l6702ZwfAM5aOeVDfUwBSDOs+ARoGmWAKQ6LOInQ8J4/zjM7ov12fuTpktUKdMQjkeCp07Vd73mPkxw==", + "dev": true, + "dependencies": { + "@types/rx-lite": "*" + } + }, + "node_modules/@types/rx-lite-backpressure": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/rx-lite-backpressure/-/rx-lite-backpressure-4.0.3.tgz", + "integrity": "sha512-Y6aIeQCtNban5XSAF4B8dffhIKu6aAy/TXFlScHzSxh6ivfQBQw6UjxyEJxIOt3IT49YkS+siuayM2H/Q0cmgA==", + "dev": true, + "dependencies": { + "@types/rx-lite": "*" + } + }, + "node_modules/@types/rx-lite-coincidence": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/rx-lite-coincidence/-/rx-lite-coincidence-4.0.3.tgz", + "integrity": "sha512-1VNJqzE9gALUyMGypDXZZXzR0Tt7LC9DdAZQ3Ou/Q0MubNU35agVUNXKGHKpNTba+fr8GdIdkC26bRDqtCQBeQ==", + "dev": true, + "dependencies": { + "@types/rx-lite": "*" + } + }, + "node_modules/@types/rx-lite-experimental": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/rx-lite-experimental/-/rx-lite-experimental-4.0.1.tgz", + "integrity": "sha1-xTL1y98/LBXaFt7Ykw0bKYQCPL0=", + "dev": true, + "dependencies": { + "@types/rx-lite": "*" + } + }, + "node_modules/@types/rx-lite-joinpatterns": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/rx-lite-joinpatterns/-/rx-lite-joinpatterns-4.0.1.tgz", + "integrity": "sha1-9w/jcFGKhDLykVjMkv+1a05K/D4=", + "dev": true, + "dependencies": { + "@types/rx-lite": "*" + } + }, + "node_modules/@types/rx-lite-testing": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/rx-lite-testing/-/rx-lite-testing-4.0.1.tgz", + "integrity": "sha1-IbGdEfTf1v/vWp0WSOnIh5v+Iek=", + "dev": true, + "dependencies": { + "@types/rx-lite-virtualtime": "*" + } + }, + "node_modules/@types/rx-lite-time": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/rx-lite-time/-/rx-lite-time-4.0.3.tgz", + "integrity": "sha512-ukO5sPKDRwCGWRZRqPlaAU0SKVxmWwSjiOrLhoQDoWxZWg6vyB9XLEZViKOzIO6LnTIQBlk4UylYV0rnhJLxQw==", + "dev": true, + "dependencies": { + "@types/rx-lite": "*" + } + }, + "node_modules/@types/rx-lite-virtualtime": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/rx-lite-virtualtime/-/rx-lite-virtualtime-4.0.3.tgz", + "integrity": "sha512-3uC6sGmjpOKatZSVHI2xB1+dedgml669ZRvqxy+WqmGJDVusOdyxcKfyzjW0P3/GrCiN4nmRkLVMhPwHCc5QLg==", + "dev": true, + "dependencies": { + "@types/rx-lite": "*" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "dependencies": { + "mime-db": "1.46.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dependencies": { + "string-width": "^3.0.0" + } + }, + "node_modules/ansi-align/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "node_modules/ansi-align/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-align/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "node_modules/asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "node_modules/async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + }, + "node_modules/async-each-series": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/async-each-series/-/async-each-series-0.1.1.tgz", + "integrity": "sha1-dhfBkXQB/Yykooqtzj266Yr+tDI=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "dependencies": { + "follow-redirects": "^1.10.0" + } + }, + "node_modules/backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/base64-arraybuffer": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", + "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=" + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "optional": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==", + "engines": { + "node": "*" + } + }, + "node_modules/binance-api-node": { + "version": "0.10.35", + "resolved": "https://registry.npmjs.org/binance-api-node/-/binance-api-node-0.10.35.tgz", + "integrity": "sha512-+HR9NJAkb7qmLT5tfsJgQjU3FM5U7Sozbx1A0XxyHSyTwy1A85N9rzy/c4vCobZvSASVov9c3BzMltFIf0piDA==", + "dependencies": { + "isomorphic-fetch": "^2.2.1", + "isomorphic-ws": "^4.0.1", + "lodash.zipobject": "^4.1.3", + "reconnecting-websocket": "^4.2.0", + "ws": "^7.2.0" + }, + "engines": { + "yarn": ">= 1.0.0" + } + }, + "node_modules/binance-api-node/node_modules/ws": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==", + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" + }, + "node_modules/boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-sync": { + "version": "2.26.14", + "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-2.26.14.tgz", + "integrity": "sha512-3TtpsheGolJT6UFtM2CZWEcGJmI4ZEvoCKiKE2bvcDnPxRkhQT4nIGVtfiyPcoHKXGM0LwMOZmYJNWfiNfVXWA==", + "dependencies": { + "browser-sync-client": "^2.26.14", + "browser-sync-ui": "^2.26.14", + "bs-recipes": "1.3.4", + "bs-snippet-injector": "^2.0.1", + "chokidar": "^3.5.1", + "connect": "3.6.6", + "connect-history-api-fallback": "^1", + "dev-ip": "^1.0.1", + "easy-extender": "^2.3.4", + "eazy-logger": "3.1.0", + "etag": "^1.8.1", + "fresh": "^0.5.2", + "fs-extra": "3.0.1", + "http-proxy": "^1.18.1", + "immutable": "^3", + "localtunnel": "^2.0.1", + "micromatch": "^4.0.2", + "opn": "5.3.0", + "portscanner": "2.1.1", + "qs": "6.2.3", + "raw-body": "^2.3.2", + "resp-modifier": "6.0.2", + "rx": "4.1.0", + "send": "0.16.2", + "serve-index": "1.9.1", + "serve-static": "1.13.2", + "server-destroy": "1.0.1", + "socket.io": "2.4.0", + "ua-parser-js": "^0.7.18", + "yargs": "^15.4.1" + }, + "bin": { + "browser-sync": "dist/bin.js" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/browser-sync-client": { + "version": "2.26.14", + "resolved": "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-2.26.14.tgz", + "integrity": "sha512-be0m1MchmKv/26r/yyyolxXcBi052aYrmaQep5nm8YNMjFcEyzv0ZoOKn/c3WEXNlEB/KeXWaw70fAOJ+/F1zQ==", + "dependencies": { + "etag": "1.8.1", + "fresh": "0.5.2", + "mitt": "^1.1.3", + "rxjs": "^5.5.6" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/browser-sync-client/node_modules/rxjs": { + "version": "5.5.12", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", + "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", + "dependencies": { + "symbol-observable": "1.0.1" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/browser-sync-ui": { + "version": "2.26.14", + "resolved": "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-2.26.14.tgz", + "integrity": "sha512-6oT1sboM4KVNnWCCJDMGbRIeTBw97toMFQ+srImvwQ6J5t9KMgizaIX8HcKLiemsUMSJkgGM9RVKIpq2UblgOA==", + "dependencies": { + "async-each-series": "0.1.1", + "connect-history-api-fallback": "^1", + "immutable": "^3", + "server-destroy": "1.0.1", + "socket.io-client": "^2.4.0", + "stream-throttle": "^0.1.3" + } + }, + "node_modules/browser-sync/node_modules/qs": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", + "integrity": "sha1-HPyyXBCpsrSDBT/zn138kjOQjP4=", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/bs-recipes": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz", + "integrity": "sha1-DS1NSKcYyMBEdp/cT4lZLci2lYU=" + }, + "node_modules/bs-snippet-injector": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bs-snippet-injector/-/bs-snippet-injector-2.0.1.tgz", + "integrity": "sha1-YbU5PxH1JVntEgaTEANDtu2wTdU=" + }, + "node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chalk/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chalk/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.1" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dependencies": { + "mimic-response": "^1.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "node_modules/component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/connect": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", + "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.0", + "parseurl": "~1.3.2", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/connect-logger": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/connect-logger/-/connect-logger-0.0.1.tgz", + "integrity": "sha1-TZmZeKHSC7RgjnzUNNdBZSJVF0s=", + "dependencies": { + "moment": "*" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dashdash/node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "node_modules/delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/dev-ip": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dev-ip/-/dev-ip-1.0.1.tgz", + "integrity": "sha1-p2o+0YVb56ASu4rBbLgPPADcKPA=", + "bin": { + "dev-ip": "lib/dev-ip.js" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, + "node_modules/easy-extender": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/easy-extender/-/easy-extender-2.3.4.tgz", + "integrity": "sha512-8cAwm6md1YTiPpOvDULYJL4ZS6WfM5/cTeVVh4JsvyYZAoqlRVUpHL9Gr5Fy7HA6xcSZicUia3DeAgO3Us8E+Q==", + "dependencies": { + "lodash": "^4.17.10" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/eazy-logger": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eazy-logger/-/eazy-logger-3.1.0.tgz", + "integrity": "sha512-/snsn2JqBtUSSstEl4R0RKjkisGHAhvYj89i7r3ytNUKW12y178KDZwXLXIgwDqLW6E/VRMT9qfld7wvFae8bQ==", + "dependencies": { + "tfunk": "^4.0.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "optional": true, + "dependencies": { + "jsbn": "~0.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/engine.io": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.5.0.tgz", + "integrity": "sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "debug": "~4.1.0", + "engine.io-parser": "~2.2.0", + "ws": "~7.4.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/engine.io-client": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.1.tgz", + "integrity": "sha512-oVu9kBkGbcggulyVF0kz6BV3ganqUeqXvD79WOFKa+11oK692w1NyFkuEj4xrkFRpZhn92QOqTk4RQq5LiBXbQ==", + "dependencies": { + "component-emitter": "~1.3.0", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.2.0", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "ws": "~7.4.2", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + } + }, + "node_modules/engine.io-client/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/engine.io-client/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==", + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/engine.io-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz", + "integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==", + "dependencies": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.4", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/engine.io/node_modules/ws": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==", + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "dev": true, + "dependencies": { + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", + "pause-stream": "0.0.11", + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/follow-redirects": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz", + "integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "engines": { + "node": "*" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", + "dev": true + }, + "node_modules/fs-extra": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", + "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^3.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/getpass/node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "dependencies": { + "ini": "1.3.7" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "dependencies": { + "isarray": "2.0.1" + } + }, + "node_modules/has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "node_modules/http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz", + "integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==", + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=" + }, + "node_modules/immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==" + }, + "node_modules/ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "dependencies": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-like": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-number-like/-/is-number-like-1.0.8.tgz", + "integrity": "sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA==", + "dependencies": { + "lodash.isfinite": "^3.3.2" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + }, + "node_modules/isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "dependencies": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==" + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + }, + "node_modules/json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "node_modules/jsonfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", + "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", + "dependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "node_modules/jsprim/node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" + }, + "node_modules/lite-server": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/lite-server/-/lite-server-2.6.1.tgz", + "integrity": "sha512-d3oyB/C8AU4EwYQHlLxcu6vTQDnCaLb81v1KKNYABmFS5oeJ11A+YxlqtpbTclID1AFddJfcB5klf0q98vYIMw==", + "dependencies": { + "browser-sync": "^2.26.13", + "connect-history-api-fallback": "^1.6.0", + "connect-logger": "^0.0.1", + "lodash": "^4.17.20", + "minimist": "^1.2.5" + }, + "bin": { + "lite-server": "bin/lite-server" + } + }, + "node_modules/localtunnel": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-2.0.1.tgz", + "integrity": "sha512-LiaI5wZdz0xFkIQpXbNI62ZnNn8IMsVhwxHmhA+h4vj8R9JG/07bQHWwQlyy7b95/5fVOCHJfIHv+a5XnkvaJA==", + "dependencies": { + "axios": "0.21.1", + "debug": "4.3.1", + "openurl": "1.1.1", + "yargs": "16.2.0" + }, + "bin": { + "lt": "bin/lt.js" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/localtunnel/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/localtunnel/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/localtunnel/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.isfinite": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", + "integrity": "sha1-+4m2WpqAKBgz8LdHizpRBPiY67M=" + }, + "node_modules/lodash.zipobject": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lodash.zipobject/-/lodash.zipobject-4.1.3.tgz", + "integrity": "sha1-s5n1q6j/YqdG9peb8gshT5ZNvvg=" + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "bin": { + "mime": "cli.js" + } + }, + "node_modules/mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "dependencies": { + "mime-db": "~1.30.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "node_modules/mitt": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-1.2.0.tgz", + "integrity": "sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw==" + }, + "node_modules/moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-binance-api": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/node-binance-api/-/node-binance-api-0.12.5.tgz", + "integrity": "sha512-tapf/OCGaMiHrfvOgPu67osXwq03jFq+WtKgDB0XR6uRvSnOf+fMWMsnbyioHcJSXpd3sdcyR5VkjPGZmkUuHw==", + "dependencies": { + "async": "^3.1.0", + "https-proxy-agent": "^3.0.1", + "json-bigint": "^1.0.0", + "request": "^2.88.0", + "socks-proxy-agent": "^4.0.2", + "string-hash": "^1.1.3", + "url": "^0.11.0", + "ws": "^7.2.0" + } + }, + "node_modules/node-binance-api/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "node_modules/node-binance-api/node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/node-binance-api/node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "engines": { + "node": "*" + } + }, + "node_modules/node-binance-api/node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "node_modules/node-binance-api/node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/node-binance-api/node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/node-binance-api/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/node-binance-api/node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "engines": { + "node": ">=4" + } + }, + "node_modules/node-binance-api/node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/node-binance-api/node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/node-binance-api/node_modules/mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-binance-api/node_modules/mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "dependencies": { + "mime-db": "1.46.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-binance-api/node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/node-binance-api/node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "node_modules/node-binance-api/node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/node-binance-api/node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/node-binance-api/node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/node-binance-api/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "node_modules/node-binance-api/node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/node-binance-api/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/node-binance-api/node_modules/ws": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==", + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/node-cleanup": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz", + "integrity": "sha1-esGavSl+Caf3KnFUXZUbUX5N3iw=", + "dev": true + }, + "node_modules/node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "dependencies": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, + "node_modules/nodemon": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.7.tgz", + "integrity": "sha512-XHzK69Awgnec9UzHr1kc8EomQh4sjTQ8oRf8TsGrSmHDx9/UmiGG9E/mM3BuTfNeFwdNBvrqQq/RHL0xIeyFOA==", + "hasInstallScript": true, + "dependencies": { + "chokidar": "^3.2.2", + "debug": "^3.2.6", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.7", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.3", + "update-notifier": "^4.1.0" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/openurl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.1.tgz", + "integrity": "sha1-OHW0sO96UsFW8NtB1GCduw+Us4c=" + }, + "node_modules/opn": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", + "integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==", + "dependencies": { + "is-wsl": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dependencies": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/parseqs": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" + }, + "node_modules/parseuri": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "dev": true, + "dependencies": { + "through": "~2.3" + } + }, + "node_modules/picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "engines": { + "node": ">=8.6" + } + }, + "node_modules/portscanner": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.1.1.tgz", + "integrity": "sha1-6rtAnk3iSVD1oqUW01rnaTQ/u5Y=", + "dependencies": { + "async": "1.5.2", + "is-number-like": "^1.0.3" + }, + "engines": { + "node": ">=0.4", + "npm": ">=1.0.0" + } + }, + "node_modules/portscanner/node_modules/async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "engines": { + "node": ">=4" + } + }, + "node_modules/prettier": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ps-tree": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz", + "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==", + "dev": true, + "dependencies": { + "event-stream": "=3.3.4" + }, + "bin": { + "ps-tree": "bin/ps-tree.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", + "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.3", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reconnecting-websocket": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz", + "integrity": "sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==" + }, + "node_modules/registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "node_modules/resp-modifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/resp-modifier/-/resp-modifier-6.0.2.tgz", + "integrity": "sha1-sSTeXE+6/LpUH0j/pzlw9KpFa08=", + "dependencies": { + "debug": "^2.2.0", + "minimatch": "^3.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/resp-modifier/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/resp-modifier/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=" + }, + "node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semver-diff/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/send/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/send/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/send/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/send/node_modules/statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0=" + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "node_modules/slack-webhook": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slack-webhook/-/slack-webhook-1.0.0.tgz", + "integrity": "sha1-8K0bc/J4oU6KsUG5VV9BWdVgXzg=" + }, + "node_modules/smart-buffer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", + "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socket.io": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.4.0.tgz", + "integrity": "sha512-9UPJ1UTvKayuQfVv2IQ3k7tCQC/fboDyIK62i99dAQIyHKaBsNdTpwHLgKJ6guRWxRtC9H+138UwpaGuQO9uWQ==", + "dependencies": { + "debug": "~4.1.0", + "engine.io": "~3.5.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.4.0", + "socket.io-parser": "~3.4.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", + "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==" + }, + "node_modules/socket.io-client": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.4.0.tgz", + "integrity": "sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==", + "dependencies": { + "backo2": "1.0.2", + "component-bind": "1.0.0", + "component-emitter": "~1.3.0", + "debug": "~3.1.0", + "engine.io-client": "~3.5.0", + "has-binary2": "~1.0.2", + "indexof": "0.0.1", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "socket.io-parser": "~3.3.0", + "to-array": "0.1.4" + } + }, + "node_modules/socket.io-client/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/socket.io-client/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/socket.io-parser": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.2.tgz", + "integrity": "sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==", + "dependencies": { + "component-emitter": "~1.3.0", + "debug": "~3.1.0", + "isarray": "2.0.1" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/socket.io/node_modules/component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/socket.io/node_modules/socket.io-parser": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz", + "integrity": "sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==", + "dependencies": { + "component-emitter": "1.2.1", + "debug": "~4.1.0", + "isarray": "2.0.1" + } + }, + "node_modules/socks": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", + "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", + "dependencies": { + "ip": "1.1.5", + "smart-buffer": "^4.1.0" + }, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", + "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", + "dependencies": { + "agent-base": "~4.2.1", + "socks": "~2.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "dev": true, + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "dashdash": "^1.12.0", + "getpass": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + }, + "optionalDependencies": { + "bcrypt-pbkdf": "^1.0.0", + "ecc-jsbn": "~0.1.1", + "jsbn": "~0.1.0", + "tweetnacl": "~0.14.0" + } + }, + "node_modules/sshpk/node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stream-combiner": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "dev": true, + "dependencies": { + "duplexer": "~0.1.1" + } + }, + "node_modules/stream-throttle": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/stream-throttle/-/stream-throttle-0.1.3.tgz", + "integrity": "sha1-rdV8jXzHOoFjDTHNVdOWHPr7qcM=", + "dependencies": { + "commander": "^2.2.0", + "limiter": "^1.0.5" + }, + "bin": { + "throttleproxy": "bin/throttleproxy.js" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/string-argv": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.1.2.tgz", + "integrity": "sha512-mBqPGEOMNJKXRo7z0keX0wlAhbBAjilUdPW13nN0PecVryZxdHIeM7TqbsSUA7VYuS00HGC6mojP7DlQzfa9ZA==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=" + }, + "node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/symbol-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tfunk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tfunk/-/tfunk-4.0.0.tgz", + "integrity": "sha512-eJQ0dGfDIzWNiFNYFVjJ+Ezl/GmwHaFTBTjrtqNPW0S7cuVDBrZrmzUz6VkMeCR4DZFqhd4YtLwsw3i2wYHswQ==", + "dependencies": { + "chalk": "^1.1.3", + "dlv": "^1.1.3" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "node_modules/to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsc-watch": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/tsc-watch/-/tsc-watch-4.2.9.tgz", + "integrity": "sha512-DlTaoDs74+KUpyWr7dCGhuscAUKCz6CiFduBN7R9RbLJSSN1moWdwoCLASE7+zLgGvV5AwXfYDiEMAsPGaO+Vw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "node-cleanup": "^2.1.2", + "ps-tree": "^1.2.0", + "string-argv": "^0.1.1", + "strip-ansi": "^6.0.0" + }, + "bin": { + "tsc-watch": "index.js" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.26", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.26.tgz", + "integrity": "sha512-VwIvGlFNmpKbjzRt51jpbbFTrKIEgGHxIwA8Y69K1Bqc6bTIV7TaGGABOkghSFQWsLmcRB4drGvpfv9z2szqoQ==", + "engines": { + "node": "*" + } + }, + "node_modules/undefsafe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", + "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", + "dependencies": { + "debug": "^2.2.0" + } + }, + "node_modules/undefsafe/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/undefsafe/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "dependencies": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uri-js/node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", + "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.7", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", + "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/yargs/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==" + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + }, "dependencies": { "@sindresorhus/is": { "version": "0.14.0", @@ -191,15 +3943,6 @@ "es6-promisify": "^5.0.0" } }, - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "requires": { - "co": "^4.6.0", - "json-stable-stringify": "^1.0.1" - } - }, "ansi-align": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", @@ -272,11 +4015,6 @@ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" }, - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" - }, "async": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", @@ -292,16 +4030,6 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" - }, - "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" - }, "axios": { "version": "0.21.1", "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", @@ -350,9 +4078,9 @@ "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" }, "binance-api-node": { - "version": "0.10.34", - "resolved": "https://registry.npmjs.org/binance-api-node/-/binance-api-node-0.10.34.tgz", - "integrity": "sha512-iThCps2Kl5Hdr3g9dLrIGIKIRW7fiaCpY7cFavAkorRpv1GM+YPhPNPLJzt69BRQvUmxv1+3QMbyKlzg8jvWEg==", + "version": "0.10.35", + "resolved": "https://registry.npmjs.org/binance-api-node/-/binance-api-node-0.10.35.tgz", + "integrity": "sha512-+HR9NJAkb7qmLT5tfsJgQjU3FM5U7Sozbx1A0XxyHSyTwy1A85N9rzy/c4vCobZvSASVov9c3BzMltFIf0piDA==", "requires": { "isomorphic-fetch": "^2.2.1", "isomorphic-ws": "^4.0.1", @@ -373,24 +4101,11 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, - "bintrees": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", - "integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=" - }, "blob": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "requires": { - "hoek": "2.x.x" - } - }, "boxen": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", @@ -657,11 +4372,6 @@ "mimic-response": "^1.0.0" } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" - }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -675,14 +4385,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "combined-stream": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", - "requires": { - "delayed-stream": "~1.0.0" - } - }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -781,14 +4483,6 @@ "which": "^2.0.1" } }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "requires": { - "boom": "2.x.x" - } - }, "crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -1091,11 +4785,6 @@ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" - }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -1167,16 +4856,6 @@ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.12" - } - }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -1204,17 +4883,6 @@ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "optional": true }, - "gdax": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/gdax/-/gdax-0.5.1.tgz", - "integrity": "sha1-iKDtKdvsw0jFysA8VZjUyAkHJjI=", - "requires": { - "bintrees": "1.0.1", - "num": "0.3.0", - "request": "2.81.0", - "ws": "3.0.0" - } - }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -1282,20 +4950,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" }, - "har-schema": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", - "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=" - }, - "har-validator": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", - "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", - "requires": { - "ajv": "^4.9.1", - "har-schema": "^1.0.5" - } - }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", @@ -1334,22 +4988,6 @@ "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==" }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" - }, "http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -1384,16 +5022,6 @@ "requires-port": "^1.0.0" } }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "requires": { - "assert-plus": "^0.2.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, "https-proxy-agent": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz", @@ -1446,11 +5074,6 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==" }, - "int": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/int/-/int-0.2.0.tgz", - "integrity": "sha1-WJ8FsDuNjAjJGMiIR4TLYqlO9H4=" - }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -1606,14 +5229,6 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "requires": { - "jsonify": "~0.0.0" - } - }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -1627,11 +5242,6 @@ "graceful-fs": "^4.1.6" } }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -2071,19 +5681,6 @@ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==" }, - "num": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/num/-/num-0.3.0.tgz", - "integrity": "sha1-qC4qmx/FL7qzEzWM35KQXm8D8oc=", - "requires": { - "int": "0.2.0" - } - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" - }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -2192,11 +5789,6 @@ "through": "~2.3" } }, - "performance-now": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", - "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" - }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", @@ -2257,11 +5849,6 @@ "once": "^1.3.1" } }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - }, "pupa": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", @@ -2270,11 +5857,6 @@ "escape-goat": "^2.0.0" } }, - "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" - }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", @@ -2336,35 +5918,6 @@ "rc": "^1.2.8" } }, - "request": { - "version": "2.81.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", - "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", - "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~4.2.1", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "oauth-sign": "~0.8.1", - "performance-now": "^0.2.0", - "qs": "~6.4.0", - "safe-buffer": "^5.0.1", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.0.0" - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2627,14 +6180,6 @@ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==" }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "requires": { - "hoek": "2.x.x" - } - }, "socket.io": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.4.0.tgz", @@ -2839,11 +6384,6 @@ "strip-ansi": "^6.0.0" } }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" - }, "strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", @@ -2918,14 +6458,6 @@ "nopt": "~1.0.10" } }, - "tough-cookie": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", - "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", - "requires": { - "punycode": "^1.4.1" - } - }, "tsc-watch": { "version": "4.2.9", "resolved": "https://registry.npmjs.org/tsc-watch/-/tsc-watch-4.2.9.tgz", @@ -2981,11 +6513,6 @@ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.26.tgz", "integrity": "sha512-VwIvGlFNmpKbjzRt51jpbbFTrKIEgGHxIwA8Y69K1Bqc6bTIV7TaGGABOkghSFQWsLmcRB4drGvpfv9z2szqoQ==" }, - "ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" - }, "undefsafe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", @@ -3123,11 +6650,6 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, - "uuid": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", - "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" - }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -3208,22 +6730,6 @@ "typedarray-to-buffer": "^3.1.5" } }, - "ws": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.0.0.tgz", - "integrity": "sha1-mN2wAFbIOQy3Ued4h4hJf5kQO2w=", - "requires": { - "safe-buffer": "~5.0.1", - "ultron": "~1.1.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz", - "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=" - } - } - }, "xdg-basedir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", diff --git a/package.json b/package.json index 8482e11..b39d49a 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,8 @@ "author": "", "license": "MIT", "dependencies": { - "binance-api-node": "^0.10.34", + "binance-api-node": "^0.10.35", "delay": "^5.0.0", - "gdax": "^0.5.1", "lite-server": "^2.6.1", "node-binance-api": "^0.12.5", "nodemon": "^2.0.7", diff --git a/src/config/config.binance.ts b/src/config/config.binance.ts index b7d9fb7..f5d85ef 100644 --- a/src/config/config.binance.ts +++ b/src/config/config.binance.ts @@ -36,7 +36,7 @@ const binanceConfig: Config = { sellWhenLossRateReaches: 1, // in % }, market: { - currency: (process.env.MARKET_CURRENCY ?? Currency.BTC_EUR) as Currency, + currency: (process.env.MARKET_CURRENCY ?? Currency.BTCEUR) as Currency, orderFees: 0.0003, // <=> 0.1% }, account: { @@ -44,10 +44,10 @@ const binanceConfig: Config = { baseCurrency: (process.env.BASE_CURRENCY ?? Currency.BTC) as Currency, // BTC, ETH, LTC, ... }, chart: { - tickerInterval: 1000 * 30, // ms + tickerInterval: 1000 * 2, // ms reductionOfTheTickerIntervalOnSpeedMode: 0.5, // <=> we reduce by 50% the ticker interval - minPriceDifferenceToApproveNewPoint: 0.1, // in %. <=> 0.1% + minPriceDifferenceToApproveNewPoint: 0, // in %. <=> 0.1% smoothing: Smoothing.MOVING_AVERAGE, // Pump & dump diff --git a/src/config/config.gdax.ts b/src/config/config.gdax.ts deleted file mode 100644 index d6dfa29..0000000 --- a/src/config/config.gdax.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Config } from "../typings" -import { Currency } from "../vendor/interfaces/currency.enum" -import { Smoothing } from "../vendor/chart/smoothing" -import { Platform } from "./platform" - -const gdaxConfig: Config = { - app: { - debug: true, - platform: Platform.GDAX, - }, - network: { - retryIntervalWhenConnectionIsLost: 5000, // ms - }, - api: { - uri: "https://api.gdax.com", - websocketURI: "wss://ws-feed.gdax.com", - sandboxWebsocketURI: "wss://ws-feed-public.sandbox.gdax.com", - sandboxURI: "https://api-public.sandbox.gdax.com", - sandbox: false, - }, - trader: { - // Quantities strategy - quantityOfBaseCurrencyToUse: 100, // in % (BTC, ETH, LTC, ...) - - quantityOfQuoteCurrencyToUse: 100, // in % (€, $) - maxQuantityQuoteCurrencyToUse: 0.0022, // 100€, 100 BTC (max quantity) - minQuantityQuoteCurrencyToUse: 0.001, // 50€, 50 BTC - - // Probitability strategy & exit strategies - sellWhenPriceExceedsMaxThresholdOfProfitability: true, - sellWhenPriceExceedsMinThresholdOfProfitability: true, - quantityToSellWhenPriceExceedsMinThresholdOfProfitability: 30, // in % - maxThresholdOfProfitability: 2, // in % - minThresholdOfProfitability: 0.5, // in %. How many % profitability wanted when selling - useExitStrategyInCaseOfLosses: true, - sellWhenLossRateReaches: 10, // in % - }, - market: { - currency: Currency.BTC_EUR, - orderFees: 0.001, // <=> 0.1% - }, - account: { - quoteCurrency: Currency.EUR, // €, $, BTC - baseCurrency: Currency.BTC, // BTC, ETH, LTC, ... - }, - chart: { - tickerInterval: 1000 * 15, // ms - reductionOfTheTickerIntervalOnSpeedMode: 0.5, // <=> we reduce by 50% the ticker interval - - minPriceDifferenceToApproveNewPoint: 0.07, // <=> 0.1% - smoothing: Smoothing.SAMPLE, - - // Pump & dump - thresholdRateToApproveInversion: 1, // in % - thresholdMaxRateToApproveInversion: 2, // in % - numberOfUpPointsToValidatePump: 3, - numberOfDownPointsToValidateDump: 3, - validatePumpWhenBigPumpIsDetected: true, - ignoreBigPumpWhenBuying: true, - validateDumpWhenBigDumpIsDetected: false, - }, -} - -export default gdaxConfig diff --git a/src/config/index.ts b/src/config/index.ts index e851e08..0c1ae21 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -1,13 +1,8 @@ import { Config } from "../typings" import binanceConfig from "./config.binance" -import gdaxConfig from "./config.gdax" import { Platform } from "./platform" const platform = process.env.PLATFORM ?? Platform.BINANCE export const config: Config = - platform === Platform.BINANCE - ? binanceConfig - : platform === Platform.GDAX - ? gdaxConfig - : null + platform === Platform.BINANCE ? binanceConfig : null diff --git a/src/config/platform.ts b/src/config/platform.ts index ee36550..6ac2689 100644 --- a/src/config/platform.ts +++ b/src/config/platform.ts @@ -1,4 +1,3 @@ export enum Platform { - GDAX = "gdax", BINANCE = "binance", } diff --git a/src/index.ts b/src/index.ts index effd596..c63327a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,7 @@ import { config } from "./config" import { Platform } from "./config/platform" import BinanceMarket from "./markets/binance" -import GdaxMarket from "./markets/gdax" import "./rxjs.extensions" -import Market from "./vendor/interfaces/market" import Trader from "./vendor/trader/index" async function start() { @@ -12,10 +10,7 @@ async function start() { throw new Error(`Invalid market platform: ${config.app.platform}`) } - const market: Market = - config.app.platform === Platform.BINANCE - ? new BinanceMarket() - : new GdaxMarket() + const market = new BinanceMarket() await market.init() diff --git a/src/markets/gdax/accounts.ts b/src/markets/gdax/accounts.ts deleted file mode 100644 index e455ec2..0000000 --- a/src/markets/gdax/accounts.ts +++ /dev/null @@ -1,131 +0,0 @@ -import * as Gdax from "gdax" -import { Account, CoinbaseAccount } from "gdax" -import { Currency } from "../../vendor/interfaces/currency.enum" -import { Accounts } from "../../vendor/market/accounts" - -class GdaxAccounts implements Accounts { - allMarketAccounts: any[] - - client: Gdax.AuthenticatedClient - - constructor(client: Gdax.AuthenticatedClient) { - this.client = client - } - - async marketAccounts(): Promise { - if (!Array.isArray(this.allMarketAccounts)) { - this.allMarketAccounts = await this.client.getCoinbaseAccounts() - } - - return this.allMarketAccounts - } - - async marketAccountByCurrency(currency: string): Promise { - const marketAccounts = await this.marketAccounts() - const marketAccountsFound = marketAccounts.filter( - (account) => account.currency === currency - ) - - if (marketAccountsFound.length === 0) { - return null - } - - return marketAccountsFound[0] - } - - accounts(): Promise { - return this.client.getAccounts() - // FIXME: need to be more flexible and permets cache reload - // if (!Array.isArray(this.allAccounts)) { - // this.allAccounts = await this.client.getAccounts() - // } - - // return this.allAccounts - } - - account(id: string): Promise { - return this.client.getAccount(id) - } - - history(accountId: string): Promise { - return this.client.getAccountHistory(accountId) - } - - async availableFunds(currency: Currency): Promise { - const account = await this.accountByCurrency(currency) - - return parseFloat(account.available) - } - - async fundsOnHold(currency: Currency): Promise { - const account = await this.accountByCurrency(currency) - - return parseInt(account.holds) - } - - async hasFundsOnHold(currency: Currency): Promise { - const fundsOnHold = await this.fundsOnHold(currency) - - return fundsOnHold > 0 - } - - async accountByCurrency(currency: Currency): Promise { - const accounts = await this.accounts() - const accountsFound = accounts.filter( - (account) => account.currency === currency - ) - - if (accountsFound.length === 0) { - return null - } - - return accountsFound[0] - } - - deposit(amount: number, paymentMethod: any): Promise { - return this.client.deposit({ - amount, - currency: paymentMethod.currency, - payment_method_id: paymentMethod.id, - }) - } - - withdraw(amount: number, currency: Currency, address: string): Promise { - return this.client.withdrawCrypto({ - amount, - currency, - coinbase_account_id: address, - }) - } - - withdrawCrypto( - amount: number, - currency: Currency, - address: string - ): Promise { - return this.client.withdrawCrypto({ - amount, - currency, - crypto_address: address, - }) - } - - paymentMethods(): Promise { - return (this.client).getPaymentMethods() - } - - async paymentMethodByCurrency(currency: Currency): Promise { - const paymentMethods = await this.paymentMethods() - const paymentMethodsFound = paymentMethods.filter( - (method) => method.currency === currency - ) - - if (paymentMethods.length === 0) { - return null - } - - return paymentMethods[0] - } -} - -export default GdaxAccounts diff --git a/src/markets/gdax/index.ts b/src/markets/gdax/index.ts deleted file mode 100644 index 1db9eeb..0000000 --- a/src/markets/gdax/index.ts +++ /dev/null @@ -1,111 +0,0 @@ -import * as Gdax from "gdax" -import { Subject } from "rxjs" -import { config } from "../../config" -import { Currency } from "../../vendor/interfaces/currency.enum" -import Market from "../../vendor/interfaces/market" -import Logger from "../../vendor/logger/index" -import { Accounts } from "../../vendor/market/accounts" -import Orders from "../../vendor/market/orders" -import GdaxAccounts from "./accounts" -import GdaxOrders from "./orders" - -class GdaxMarket implements Market { - currency: Currency - orders: Orders - accounts: Accounts - publicClient: Gdax.PublicClient - client: Gdax.AuthenticatedClient - socket: Gdax.WebsocketClient - channels: string[] - price$: Subject - lastPrice: number - price: number - sandbox: boolean - lastTicker: Gdax.ProductTicker - initialized: boolean - - constructor(channels: string[] = ["ticker"]) { - this.currency = config.market.currency - this.channels = channels - this.sandbox = config.api.sandbox - this.price$ = new Subject() - } - - async init() { - const restURI = this.sandbox ? config.api.sandboxURI : config.api.uri - const websocketURI = this.sandbox - ? config.api.sandboxWebsocketURI - : config.api.websocketURI - const websocketAuth = this.sandbox - ? null - : { - key: process.env.GDAX_API_KEY, - secret: process.env.GDAX_API_SECRET, - passphrase: process.env.GDAX_API_PASSPHRASE, - } - - this.publicClient = new Gdax.PublicClient(restURI) - this.client = new Gdax.AuthenticatedClient( - process.env.GDAX_API_KEY, - process.env.GDAX_API_SECRET, - process.env.GDAX_API_PASSPHRASE, - restURI - ) - this.socket = new Gdax.WebsocketClient( - [this.currency], - websocketURI, - websocketAuth, - { channels: this.channels } - ) - this.orders = new GdaxOrders(this.client, this.publicClient) - this.accounts = new GdaxAccounts(this.client) - - this.listenSocketErrors() - this.initialized = true - } - - async ping() { - // TODO: implement ping test here - return true - } - - watchCurrencyPrice() { - if (!this.initialized) { - throw new Error( - "GdaxMarket #watchCurrencyPrice() cannot be used without being initialized" - ) - } - - this.socket.on("message", (data: any) => { - if (data && "ticker" === data.type) { - if (Number.isFinite(this.price)) { - this.lastPrice = this.price - } - - this.price = parseFloat(data.price) - this.price$.next(this.price) - } - }) - } - - async getCurrencyPrice() { - if (!this.initialized) { - throw new Error( - "GdaxMarket #getCurrencyPrice() cannot be used without being initialized" - ) - } - - this.lastTicker = await this.publicClient.getProductTicker(this.currency) - - return parseFloat(this.lastTicker.price) - } - - private listenSocketErrors() { - this.socket.on("error", (error) => { - Logger.error("A socket error occured") - Logger.error(error) - }) - } -} - -export default GdaxMarket diff --git a/src/markets/gdax/orders.ts b/src/markets/gdax/orders.ts deleted file mode 100644 index d184e40..0000000 --- a/src/markets/gdax/orders.ts +++ /dev/null @@ -1,250 +0,0 @@ -import * as Gdax from "gdax" -import { Currency } from "../../vendor/interfaces/currency.enum" -import { OrderSide } from "../../vendor/interfaces/order-type.enum" -import { OrderResult } from "../../vendor/market/order" -import { Orders } from "../../vendor/market/orders" - -class GdaxOrders implements Orders { - pending: OrderResult[] = [] - done: OrderResult[] = [] - canceled: OrderResult[] = [] - lastOrder: OrderResult - - constructor( - private client: Gdax.AuthenticatedClient, - private publicClient: Gdax.PublicClient - ) {} - - async all(): Promise { - const orders: OrderResult[] = await this.client.getOrders() - - return orders - } - - find(id: string, status: OrderSide): OrderResult { - let ordersToSearch = [] - - if (OrderSide.BUY === status || OrderSide.SELL === status) { - ordersToSearch = this.pending.slice() - } else if (OrderSide.CANCEL === status) { - ordersToSearch = this.canceled.slice() - } else { - ordersToSearch = this.done - } - - return ordersToSearch.reduce((order) => { - if (order.id === id) { - return order - } - - return null - }, null) - } - - buyOrders(): OrderResult[] { - return this.pending.filter((order) => order.side === OrderSide.BUY) - } - - sellOrders(): OrderResult[] { - return this.pending.filter((order) => order.side === OrderSide.SELL) - } - - async buyLimit( - currency: Currency, - quantity: number, - price: number, - allowTaker = false - ): Promise { - const response = await this.client.buy({ - type: "limit", - side: "buy", - price: price.toFixed(2), - size: this.normalizeNumber(quantity), - product_id: currency, - post_only: !allowTaker, - }) - - if (response && (response).message) { - throw Error( - `Error when trying to buy with a limit order: ${JSON.stringify( - response, - null, - 2 - )}` - ) - } - - this.lastOrder = this.forgeOrderResult(response) - this.pending.push(this.lastOrder) - - return this.lastOrder - } - - async buyMarket(currency: Currency, funds: number) { - const response = await this.client.buy({ - type: "market", - side: "buy", - size: null, - funds: this.normalizeNumber(funds), - product_id: currency, - }) - - if (response && (response).message) { - throw Error( - `Error when trying to buy with a market order: ${JSON.stringify( - response, - null, - 2 - )}` - ) - } - - this.lastOrder = this.forgeOrderResult(response) - this.done.push({ ...this.lastOrder }) - - return this.lastOrder - } - - async buyStop(currency: Currency, price: number, funds: number = null) { - const response = await this.client.buy({ - type: "stop", - side: "buy", - size: null, - funds: this.normalizeNumber(funds), - product_id: currency, - }) - - if (response && (response).message) { - throw Error( - `Error when trying to buy with a stop order: ${JSON.stringify( - response, - null, - 2 - )}` - ) - } - - this.lastOrder = this.forgeOrderResult(response) - this.pending.push(this.lastOrder) - - return this.lastOrder - } - - async sellLimit( - currency: Currency, - quantity: number, - price: number, - allowTaker = false - ) { - const response = await this.client.sell({ - type: "limit", - side: "sell", - price: price.toFixed(2), - size: this.normalizeNumber(quantity), - product_id: currency, - post_only: !allowTaker, - }) - - if (response && (response).message) { - throw Error( - `Error when trying to sell with a limit order: ${JSON.stringify( - response, - null, - 2 - )}` - ) - } - - this.lastOrder = this.forgeOrderResult(response) - this.pending.push(this.lastOrder) - - return this.lastOrder - } - - async sellMarket(currency: Currency, size: number) { - const response = await this.client.sell({ - type: "market", - side: "sell", - size: this.normalizeNumber(size), - funds: undefined, // undefined is important here, null value returns 400 from API, and funds is needed by typings - product_id: currency, - }) - - if (response && (response).message) { - throw Error( - `Error when trying to sell with a market order: ${JSON.stringify( - response, - null, - 2 - )}` - ) - } - - this.lastOrder = this.forgeOrderResult(response) - this.done.push({ ...this.lastOrder }) - - return this.lastOrder - } - - async sellStop(currency: Currency, price: number, size: number) { - const response = await this.client.sell({ - type: "stop", - side: "sell", - size: this.normalizeNumber(size), - funds: undefined, // undefined is important here, null value returns 400 from API, and funds is needed by typings - product_id: currency, - }) - - if (response && (response).message) { - throw Error( - `Error when trying to sell with a stop order: ${JSON.stringify( - response, - null, - 2 - )}` - ) - } - - this.lastOrder = this.forgeOrderResult(response) - this.pending.push(this.lastOrder) - - return this.lastOrder - } - - cancel(order: OrderResult) { - this.pending = this.pending.filter((current) => current.id !== order.id) - this.canceled.push(order) - - return this.client.cancelOrder(order.id) - } - - normalizeNumber(price: number): string { - const priceString = price.toString() - - if (priceString.includes(".")) { - const [integers, decimals] = priceString.split(".") - - return `${integers}.${decimals.substring(0, 8)}` - } - - return priceString - } - - private forgeOrderResult(order: any): OrderResult { - return { - id: order.id, - symbol: order.product_id, - clientOrderId: null, - transactionTime: new Date(order.created_at).getTime(), - price: parseFloat(order.price), - originQuantity: parseFloat(order.size), - executedQuantity: parseFloat(order.filled_size), - status: order.status, - timeInForce: order.time_in_force, - type: order.type, - side: order.side, - } - } -} - -export default GdaxOrders diff --git a/src/vendor/interfaces/currency.enum.ts b/src/vendor/interfaces/currency.enum.ts index c57f224..b4afd5f 100644 --- a/src/vendor/interfaces/currency.enum.ts +++ b/src/vendor/interfaces/currency.enum.ts @@ -1,31 +1,17 @@ export enum Currency { - // Bitcoin - BTC_EUR = "BTC-EUR", - BTC_USD = "BTC-USD", - - // Bitcoin cash - BCH_EUR = "BCH-EUR", - BCH_USD = "BCH-USD", - BCH_BTC = "BCH-BTC", - - // Ethereum - ETH_EUR = "ETH-EUR", - ETH_USD = "ETH-USD", - ETH_BTC = "ETH-BTC", - - // Litecoin - LTC_EUR = "LTC-EUR", - LTC_USD = "LTC-USD", - LTC_BTC = "LTC-BTC", - - // Sample currencies - USD = "USD", - EUR = "EUR", - BTC = "BTC", - LTC = "LTC", + // Assets + NGN = "NGN", + RUB = "RUB", + TRY = "TRY", + ZAR = "ZAR", + IDRT = "IDRT", + UAH = "UAH", + BIDR = "BIDR", + BRL = "BRL", + BVND = "BVND", + VAI = "VAI", ETH = "ETH", - BCH = "BCH", - CMT = "CMT", + LTC = "LTC", BNB = "BNB", NEO = "NEO", QTUM = "QTUM", @@ -34,7 +20,7 @@ export enum Currency { BNT = "BNT", BCC = "BCC", GAS = "GAS", - USDT = "USDT", + BTC = "BTC", HSR = "HSR", OAX = "OAX", DNT = "DNT", @@ -54,7 +40,6 @@ export enum Currency { IOTA = "IOTA", LINK = "LINK", XVG = "XVG", - CTR = "CTR", SALT = "SALT", MDA = "MDA", MTL = "MTL", @@ -103,6 +88,7 @@ export enum Currency { ADX = "ADX", ADA = "ADA", PPT = "PPT", + CMT = "CMT", XLM = "XLM", CND = "CND", LEND = "LEND", @@ -127,15 +113,296 @@ export enum Currency { INS = "INS", PIVX = "PIVX", IOST = "IOST", - STEEM = "STEEM", CHAT = "CHAT", + STEEM = "STEEM", + NANO = "NANO", + VIA = "VIA", + BLZ = "BLZ", + AE = "AE", RPX = "RPX", + NCASH = "NCASH", + POA = "POA", + ZIL = "ZIL", + ONT = "ONT", + STORM = "STORM", + XEM = "XEM", + WAN = "WAN", + WPR = "WPR", + QLC = "QLC", + SYS = "SYS", + GRS = "GRS", + CLOAK = "CLOAK", + GNT = "GNT", + LOOM = "LOOM", + BCN = "BCN", + REP = "REP", + TUSD = "TUSD", + ZEN = "ZEN", + SKY = "SKY", + CVC = "CVC", + THETA = "THETA", + IOTX = "IOTX", + QKC = "QKC", + AGI = "AGI", + NXS = "NXS", + DATA = "DATA", + SC = "SC", + NPXS = "NPXS", + KEY = "KEY", + NAS = "NAS", + MFT = "MFT", + DENT = "DENT", + ARDR = "ARDR", + HOT = "HOT", + VET = "VET", + DOCK = "DOCK", + POLY = "POLY", + PHX = "PHX", + HC = "HC", + GO = "GO", + PAX = "PAX", + RVN = "RVN", + DCR = "DCR", + USDC = "USDC", + MITH = "MITH", + BCHABC = "BCHABC", + BCHSV = "BCHSV", + REN = "REN", + BTT = "BTT", + USDS = "USDS", + ONG = "ONG", + FET = "FET", + CELR = "CELR", + MATIC = "MATIC", + ATOM = "ATOM", + PHB = "PHB", + TFUEL = "TFUEL", + ONE = "ONE", + FTM = "FTM", + BTCB = "BTCB", + ALGO = "ALGO", + USDSB = "USDSB", + ERD = "ERD", + DOGE = "DOGE", + DUSK = "DUSK", + BGBP = "BGBP", + ANKR = "ANKR", + WIN = "WIN", + COS = "COS", + TUSDB = "TUSDB", + COCOS = "COCOS", + TOMO = "TOMO", + PERL = "PERL", + CHZ = "CHZ", + BAND = "BAND", + BUSD = "BUSD", + BEAM = "BEAM", + XTZ = "XTZ", + HBAR = "HBAR", + NKN = "NKN", + STX = "STX", + KAVA = "KAVA", + ARPA = "ARPA", + CTXC = "CTXC", + BCH = "BCH", + TROY = "TROY", + VITE = "VITE", + FTT = "FTT", + USDT = "USDT", + EUR = "EUR", + OGN = "OGN", + DREP = "DREP", + BULL = "BULL", + BEAR = "BEAR", + ETHBULL = "ETHBULL", + ETHBEAR = "ETHBEAR", + TCT = "TCT", + WRX = "WRX", + LTO = "LTO", + EOSBULL = "EOSBULL", + EOSBEAR = "EOSBEAR", + XRPBULL = "XRPBULL", + XRPBEAR = "XRPBEAR", + MBL = "MBL", + COTI = "COTI", + BNBBULL = "BNBBULL", + BNBBEAR = "BNBBEAR", + STPT = "STPT", + SOL = "SOL", + CTSI = "CTSI", + HIVE = "HIVE", + CHR = "CHR", + BTCUP = "BTCUP", + BTCDOWN = "BTCDOWN", + MDT = "MDT", + STMX = "STMX", + IQ = "IQ", + PNT = "PNT", + GBP = "GBP", + DGB = "DGB", + COMP = "COMP", + BKRW = "BKRW", + SXP = "SXP", + SNX = "SNX", + ETHUP = "ETHUP", + ETHDOWN = "ETHDOWN", + ADAUP = "ADAUP", + ADADOWN = "ADADOWN", + LINKUP = "LINKUP", + LINKDOWN = "LINKDOWN", + VTHO = "VTHO", + IRIS = "IRIS", + MKR = "MKR", + DAI = "DAI", + RUNE = "RUNE", + AUD = "AUD", + FIO = "FIO", + BNBUP = "BNBUP", + BNBDOWN = "BNBDOWN", + XTZUP = "XTZUP", + XTZDOWN = "XTZDOWN", + AVA = "AVA", + BAL = "BAL", + YFI = "YFI", + JST = "JST", + SRM = "SRM", + ANT = "ANT", + CRV = "CRV", + SAND = "SAND", + OCEAN = "OCEAN", + NMR = "NMR", + DOT = "DOT", + LUNA = "LUNA", + IDEX = "IDEX", + RSR = "RSR", + PAXG = "PAXG", + WNXM = "WNXM", + TRB = "TRB", + BZRX = "BZRX", + WBTC = "WBTC", + SUSHI = "SUSHI", + YFII = "YFII", + KSM = "KSM", + EGLD = "EGLD", + DIA = "DIA", + UMA = "UMA", + EOSUP = "EOSUP", + EOSDOWN = "EOSDOWN", + TRXUP = "TRXUP", + TRXDOWN = "TRXDOWN", + XRPUP = "XRPUP", + XRPDOWN = "XRPDOWN", + DOTUP = "DOTUP", + DOTDOWN = "DOTDOWN", + BEL = "BEL", + WING = "WING", + SWRV = "SWRV", + LTCUP = "LTCUP", + LTCDOWN = "LTCDOWN", + CREAM = "CREAM", + UNI = "UNI", + NBS = "NBS", + OXT = "OXT", + SUN = "SUN", + AVAX = "AVAX", + HNT = "HNT", + BAKE = "BAKE", + BURGER = "BURGER", + FLM = "FLM", + SCRT = "SCRT", + CAKE = "CAKE", + SPARTA = "SPARTA", + UNIUP = "UNIUP", + UNIDOWN = "UNIDOWN", + ORN = "ORN", + UTK = "UTK", + XVS = "XVS", + ALPHA = "ALPHA", + VIDT = "VIDT", + AAVE = "AAVE", + NEAR = "NEAR", + SXPUP = "SXPUP", + SXPDOWN = "SXPDOWN", + FIL = "FIL", + FILUP = "FILUP", + FILDOWN = "FILDOWN", + YFIUP = "YFIUP", + YFIDOWN = "YFIDOWN", + INJ = "INJ", + AERGO = "AERGO", + EASY = "EASY", + AUDIO = "AUDIO", + CTK = "CTK", + BCHUP = "BCHUP", + BCHDOWN = "BCHDOWN", + BOT = "BOT", + AKRO = "AKRO", + KP3R = "KP3R", + AXS = "AXS", + HARD = "HARD", + SLP = "SLP", + CVP = "CVP", + STRAX = "STRAX", + FOR = "FOR", + UNFI = "UNFI", + FRONT = "FRONT", + BCHA = "BCHA", + ROSE = "ROSE", + HEGIC = "HEGIC", + AAVEUP = "AAVEUP", + AAVEDOWN = "AAVEDOWN", + PROM = "PROM", + SKL = "SKL", + SUSD = "SUSD", + COVER = "COVER", + GLM = "GLM", + GHST = "GHST", + SUSHIUP = "SUSHIUP", + SUSHIDOWN = "SUSHIDOWN", + XLMUP = "XLMUP", + XLMDOWN = "XLMDOWN", + DF = "DF", + GRT = "GRT", + JUV = "JUV", + PSG = "PSG", + "1INCH" = "1INCH", + REEF = "REEF", + OG = "OG", + ATM = "ATM", + ASR = "ASR", + CELO = "CELO", + RIF = "RIF", + BTCST = "BTCST", + TRU = "TRU", + DEXE = "DEXE", + CKB = "CKB", + TWT = "TWT", + FIRO = "FIRO", + BETH = "BETH", + PROS = "PROS", + LIT = "LIT", + SFP = "SFP", + FXS = "FXS", + DODO = "DODO", + UFT = "UFT", + ACM = "ACM", + AUCTION = "AUCTION", + PHA = "PHA", + TVK = "TVK", + BADGER = "BADGER", + FIS = "FIS", + OM = "OM", + POND = "POND", + DEGO = "DEGO", + ALICE = "ALICE", + BIFI = "BIFI", + LINA = "LINA", + PERP = "PERP", + RAMP = "RAMP", + SUPER = "SUPER", + CFX = "CFX", - // CURRENCY EXCHANGE - RPXBTC = "RPXBTC", - CHATBTC = "CHATBTC", - STEEMBTC = "STEEMBTC", - STEEMETH = "STEEMETH", + // Symbols ETHBTC = "ETHBTC", LTCBTC = "LTCBTC", BNBBTC = "BNBBTC", @@ -184,8 +451,6 @@ export enum Currency { LINKETH = "LINKETH", XVGBTC = "XVGBTC", XVGETH = "XVGETH", - CTRBTC = "CTRBTC", - CTRETH = "CTRETH", SALTBTC = "SALTBTC", SALTETH = "SALTETH", MDABTC = "MDABTC", @@ -383,4 +648,1132 @@ export enum Currency { PIVXBNB = "PIVXBNB", IOSTBTC = "IOSTBTC", IOSTETH = "IOSTETH", + CHATBTC = "CHATBTC", + CHATETH = "CHATETH", + STEEMBTC = "STEEMBTC", + STEEMETH = "STEEMETH", + STEEMBNB = "STEEMBNB", + NANOBTC = "NANOBTC", + NANOETH = "NANOETH", + NANOBNB = "NANOBNB", + VIABTC = "VIABTC", + VIAETH = "VIAETH", + VIABNB = "VIABNB", + BLZBTC = "BLZBTC", + BLZETH = "BLZETH", + BLZBNB = "BLZBNB", + AEBTC = "AEBTC", + AEETH = "AEETH", + AEBNB = "AEBNB", + RPXBTC = "RPXBTC", + RPXETH = "RPXETH", + RPXBNB = "RPXBNB", + NCASHBTC = "NCASHBTC", + NCASHETH = "NCASHETH", + NCASHBNB = "NCASHBNB", + POABTC = "POABTC", + POAETH = "POAETH", + POABNB = "POABNB", + ZILBTC = "ZILBTC", + ZILETH = "ZILETH", + ZILBNB = "ZILBNB", + ONTBTC = "ONTBTC", + ONTETH = "ONTETH", + ONTBNB = "ONTBNB", + STORMBTC = "STORMBTC", + STORMETH = "STORMETH", + STORMBNB = "STORMBNB", + QTUMBNB = "QTUMBNB", + QTUMUSDT = "QTUMUSDT", + XEMBTC = "XEMBTC", + XEMETH = "XEMETH", + XEMBNB = "XEMBNB", + WANBTC = "WANBTC", + WANETH = "WANETH", + WANBNB = "WANBNB", + WPRBTC = "WPRBTC", + WPRETH = "WPRETH", + QLCBTC = "QLCBTC", + QLCETH = "QLCETH", + SYSBTC = "SYSBTC", + SYSETH = "SYSETH", + SYSBNB = "SYSBNB", + QLCBNB = "QLCBNB", + GRSBTC = "GRSBTC", + GRSETH = "GRSETH", + ADAUSDT = "ADAUSDT", + ADABNB = "ADABNB", + CLOAKBTC = "CLOAKBTC", + CLOAKETH = "CLOAKETH", + GNTBTC = "GNTBTC", + GNTETH = "GNTETH", + GNTBNB = "GNTBNB", + LOOMBTC = "LOOMBTC", + LOOMETH = "LOOMETH", + LOOMBNB = "LOOMBNB", + XRPUSDT = "XRPUSDT", + BCNBTC = "BCNBTC", + BCNETH = "BCNETH", + BCNBNB = "BCNBNB", + REPBTC = "REPBTC", + REPETH = "REPETH", + REPBNB = "REPBNB", + BTCTUSD = "BTCTUSD", + TUSDBTC = "TUSDBTC", + ETHTUSD = "ETHTUSD", + TUSDETH = "TUSDETH", + TUSDBNB = "TUSDBNB", + ZENBTC = "ZENBTC", + ZENETH = "ZENETH", + ZENBNB = "ZENBNB", + SKYBTC = "SKYBTC", + SKYETH = "SKYETH", + SKYBNB = "SKYBNB", + EOSUSDT = "EOSUSDT", + EOSBNB = "EOSBNB", + CVCBTC = "CVCBTC", + CVCETH = "CVCETH", + CVCBNB = "CVCBNB", + THETABTC = "THETABTC", + THETAETH = "THETAETH", + THETABNB = "THETABNB", + XRPBNB = "XRPBNB", + TUSDUSDT = "TUSDUSDT", + IOTAUSDT = "IOTAUSDT", + XLMUSDT = "XLMUSDT", + IOTXBTC = "IOTXBTC", + IOTXETH = "IOTXETH", + QKCBTC = "QKCBTC", + QKCETH = "QKCETH", + AGIBTC = "AGIBTC", + AGIETH = "AGIETH", + AGIBNB = "AGIBNB", + NXSBTC = "NXSBTC", + NXSETH = "NXSETH", + NXSBNB = "NXSBNB", + ENJBNB = "ENJBNB", + DATABTC = "DATABTC", + DATAETH = "DATAETH", + ONTUSDT = "ONTUSDT", + TRXBNB = "TRXBNB", + TRXUSDT = "TRXUSDT", + ETCUSDT = "ETCUSDT", + ETCBNB = "ETCBNB", + ICXUSDT = "ICXUSDT", + SCBTC = "SCBTC", + SCETH = "SCETH", + SCBNB = "SCBNB", + NPXSBTC = "NPXSBTC", + NPXSETH = "NPXSETH", + VENUSDT = "VENUSDT", + KEYBTC = "KEYBTC", + KEYETH = "KEYETH", + NASBTC = "NASBTC", + NASETH = "NASETH", + NASBNB = "NASBNB", + MFTBTC = "MFTBTC", + MFTETH = "MFTETH", + MFTBNB = "MFTBNB", + DENTBTC = "DENTBTC", + DENTETH = "DENTETH", + ARDRBTC = "ARDRBTC", + ARDRETH = "ARDRETH", + ARDRBNB = "ARDRBNB", + NULSUSDT = "NULSUSDT", + HOTBTC = "HOTBTC", + HOTETH = "HOTETH", + VETBTC = "VETBTC", + VETETH = "VETETH", + VETUSDT = "VETUSDT", + VETBNB = "VETBNB", + DOCKBTC = "DOCKBTC", + DOCKETH = "DOCKETH", + POLYBTC = "POLYBTC", + POLYBNB = "POLYBNB", + PHXBTC = "PHXBTC", + PHXETH = "PHXETH", + PHXBNB = "PHXBNB", + HCBTC = "HCBTC", + HCETH = "HCETH", + GOBTC = "GOBTC", + GOBNB = "GOBNB", + PAXBTC = "PAXBTC", + PAXBNB = "PAXBNB", + PAXUSDT = "PAXUSDT", + PAXETH = "PAXETH", + RVNBTC = "RVNBTC", + RVNBNB = "RVNBNB", + DCRBTC = "DCRBTC", + DCRBNB = "DCRBNB", + USDCBNB = "USDCBNB", + MITHBTC = "MITHBTC", + MITHBNB = "MITHBNB", + BCHABCBTC = "BCHABCBTC", + BCHSVBTC = "BCHSVBTC", + BCHABCUSDT = "BCHABCUSDT", + BCHSVUSDT = "BCHSVUSDT", + BNBPAX = "BNBPAX", + BTCPAX = "BTCPAX", + ETHPAX = "ETHPAX", + XRPPAX = "XRPPAX", + EOSPAX = "EOSPAX", + XLMPAX = "XLMPAX", + RENBTC = "RENBTC", + RENBNB = "RENBNB", + BNBTUSD = "BNBTUSD", + XRPTUSD = "XRPTUSD", + EOSTUSD = "EOSTUSD", + XLMTUSD = "XLMTUSD", + BNBUSDC = "BNBUSDC", + BTCUSDC = "BTCUSDC", + ETHUSDC = "ETHUSDC", + XRPUSDC = "XRPUSDC", + EOSUSDC = "EOSUSDC", + XLMUSDC = "XLMUSDC", + USDCUSDT = "USDCUSDT", + ADATUSD = "ADATUSD", + TRXTUSD = "TRXTUSD", + NEOTUSD = "NEOTUSD", + TRXXRP = "TRXXRP", + XZCXRP = "XZCXRP", + PAXTUSD = "PAXTUSD", + USDCTUSD = "USDCTUSD", + USDCPAX = "USDCPAX", + LINKUSDT = "LINKUSDT", + LINKTUSD = "LINKTUSD", + LINKPAX = "LINKPAX", + LINKUSDC = "LINKUSDC", + WAVESUSDT = "WAVESUSDT", + WAVESTUSD = "WAVESTUSD", + WAVESPAX = "WAVESPAX", + WAVESUSDC = "WAVESUSDC", + BCHABCTUSD = "BCHABCTUSD", + BCHABCPAX = "BCHABCPAX", + BCHABCUSDC = "BCHABCUSDC", + BCHSVTUSD = "BCHSVTUSD", + BCHSVPAX = "BCHSVPAX", + BCHSVUSDC = "BCHSVUSDC", + LTCTUSD = "LTCTUSD", + LTCPAX = "LTCPAX", + LTCUSDC = "LTCUSDC", + TRXPAX = "TRXPAX", + TRXUSDC = "TRXUSDC", + BTTBTC = "BTTBTC", + BTTBNB = "BTTBNB", + BTTUSDT = "BTTUSDT", + BNBUSDS = "BNBUSDS", + BTCUSDS = "BTCUSDS", + USDSUSDT = "USDSUSDT", + USDSPAX = "USDSPAX", + USDSTUSD = "USDSTUSD", + USDSUSDC = "USDSUSDC", + BTTPAX = "BTTPAX", + BTTTUSD = "BTTTUSD", + BTTUSDC = "BTTUSDC", + ONGBNB = "ONGBNB", + ONGBTC = "ONGBTC", + ONGUSDT = "ONGUSDT", + HOTBNB = "HOTBNB", + HOTUSDT = "HOTUSDT", + ZILUSDT = "ZILUSDT", + ZRXBNB = "ZRXBNB", + ZRXUSDT = "ZRXUSDT", + FETBNB = "FETBNB", + FETBTC = "FETBTC", + FETUSDT = "FETUSDT", + BATUSDT = "BATUSDT", + XMRBNB = "XMRBNB", + XMRUSDT = "XMRUSDT", + ZECBNB = "ZECBNB", + ZECUSDT = "ZECUSDT", + ZECPAX = "ZECPAX", + ZECTUSD = "ZECTUSD", + ZECUSDC = "ZECUSDC", + IOSTBNB = "IOSTBNB", + IOSTUSDT = "IOSTUSDT", + CELRBNB = "CELRBNB", + CELRBTC = "CELRBTC", + CELRUSDT = "CELRUSDT", + ADAPAX = "ADAPAX", + ADAUSDC = "ADAUSDC", + NEOPAX = "NEOPAX", + NEOUSDC = "NEOUSDC", + DASHBNB = "DASHBNB", + DASHUSDT = "DASHUSDT", + NANOUSDT = "NANOUSDT", + OMGBNB = "OMGBNB", + OMGUSDT = "OMGUSDT", + THETAUSDT = "THETAUSDT", + ENJUSDT = "ENJUSDT", + MITHUSDT = "MITHUSDT", + MATICBNB = "MATICBNB", + MATICBTC = "MATICBTC", + MATICUSDT = "MATICUSDT", + ATOMBNB = "ATOMBNB", + ATOMBTC = "ATOMBTC", + ATOMUSDT = "ATOMUSDT", + ATOMUSDC = "ATOMUSDC", + ATOMPAX = "ATOMPAX", + ATOMTUSD = "ATOMTUSD", + ETCUSDC = "ETCUSDC", + ETCPAX = "ETCPAX", + ETCTUSD = "ETCTUSD", + BATUSDC = "BATUSDC", + BATPAX = "BATPAX", + BATTUSD = "BATTUSD", + PHBBNB = "PHBBNB", + PHBBTC = "PHBBTC", + PHBUSDC = "PHBUSDC", + PHBTUSD = "PHBTUSD", + PHBPAX = "PHBPAX", + TFUELBNB = "TFUELBNB", + TFUELBTC = "TFUELBTC", + TFUELUSDT = "TFUELUSDT", + TFUELUSDC = "TFUELUSDC", + TFUELTUSD = "TFUELTUSD", + TFUELPAX = "TFUELPAX", + ONEBNB = "ONEBNB", + ONEBTC = "ONEBTC", + ONEUSDT = "ONEUSDT", + ONETUSD = "ONETUSD", + ONEPAX = "ONEPAX", + ONEUSDC = "ONEUSDC", + FTMBNB = "FTMBNB", + FTMBTC = "FTMBTC", + FTMUSDT = "FTMUSDT", + FTMTUSD = "FTMTUSD", + FTMPAX = "FTMPAX", + FTMUSDC = "FTMUSDC", + BTCBBTC = "BTCBBTC", + BCPTTUSD = "BCPTTUSD", + BCPTPAX = "BCPTPAX", + BCPTUSDC = "BCPTUSDC", + ALGOBNB = "ALGOBNB", + ALGOBTC = "ALGOBTC", + ALGOUSDT = "ALGOUSDT", + ALGOTUSD = "ALGOTUSD", + ALGOPAX = "ALGOPAX", + ALGOUSDC = "ALGOUSDC", + USDSBUSDT = "USDSBUSDT", + USDSBUSDS = "USDSBUSDS", + GTOUSDT = "GTOUSDT", + GTOPAX = "GTOPAX", + GTOTUSD = "GTOTUSD", + GTOUSDC = "GTOUSDC", + ERDBNB = "ERDBNB", + ERDBTC = "ERDBTC", + ERDUSDT = "ERDUSDT", + ERDPAX = "ERDPAX", + ERDUSDC = "ERDUSDC", + DOGEBNB = "DOGEBNB", + DOGEBTC = "DOGEBTC", + DOGEUSDT = "DOGEUSDT", + DOGEPAX = "DOGEPAX", + DOGEUSDC = "DOGEUSDC", + DUSKBNB = "DUSKBNB", + DUSKBTC = "DUSKBTC", + DUSKUSDT = "DUSKUSDT", + DUSKUSDC = "DUSKUSDC", + DUSKPAX = "DUSKPAX", + BGBPUSDC = "BGBPUSDC", + ANKRBNB = "ANKRBNB", + ANKRBTC = "ANKRBTC", + ANKRUSDT = "ANKRUSDT", + ANKRTUSD = "ANKRTUSD", + ANKRPAX = "ANKRPAX", + ANKRUSDC = "ANKRUSDC", + ONTPAX = "ONTPAX", + ONTUSDC = "ONTUSDC", + WINBNB = "WINBNB", + WINBTC = "WINBTC", + WINUSDT = "WINUSDT", + WINUSDC = "WINUSDC", + COSBNB = "COSBNB", + COSBTC = "COSBTC", + COSUSDT = "COSUSDT", + TUSDBTUSD = "TUSDBTUSD", + NPXSUSDT = "NPXSUSDT", + NPXSUSDC = "NPXSUSDC", + COCOSBNB = "COCOSBNB", + COCOSBTC = "COCOSBTC", + COCOSUSDT = "COCOSUSDT", + MTLUSDT = "MTLUSDT", + TOMOBNB = "TOMOBNB", + TOMOBTC = "TOMOBTC", + TOMOUSDT = "TOMOUSDT", + TOMOUSDC = "TOMOUSDC", + PERLBNB = "PERLBNB", + PERLBTC = "PERLBTC", + PERLUSDC = "PERLUSDC", + PERLUSDT = "PERLUSDT", + DENTUSDT = "DENTUSDT", + MFTUSDT = "MFTUSDT", + KEYUSDT = "KEYUSDT", + STORMUSDT = "STORMUSDT", + DOCKUSDT = "DOCKUSDT", + WANUSDT = "WANUSDT", + FUNUSDT = "FUNUSDT", + CVCUSDT = "CVCUSDT", + BTTTRX = "BTTTRX", + WINTRX = "WINTRX", + CHZBNB = "CHZBNB", + CHZBTC = "CHZBTC", + CHZUSDT = "CHZUSDT", + BANDBNB = "BANDBNB", + BANDBTC = "BANDBTC", + BANDUSDT = "BANDUSDT", + BNBBUSD = "BNBBUSD", + BTCBUSD = "BTCBUSD", + BUSDUSDT = "BUSDUSDT", + BEAMBNB = "BEAMBNB", + BEAMBTC = "BEAMBTC", + BEAMUSDT = "BEAMUSDT", + XTZBNB = "XTZBNB", + XTZBTC = "XTZBTC", + XTZUSDT = "XTZUSDT", + RENUSDT = "RENUSDT", + RVNUSDT = "RVNUSDT", + HCUSDT = "HCUSDT", + HBARBNB = "HBARBNB", + HBARBTC = "HBARBTC", + HBARUSDT = "HBARUSDT", + NKNBNB = "NKNBNB", + NKNBTC = "NKNBTC", + NKNUSDT = "NKNUSDT", + XRPBUSD = "XRPBUSD", + ETHBUSD = "ETHBUSD", + BCHABCBUSD = "BCHABCBUSD", + LTCBUSD = "LTCBUSD", + LINKBUSD = "LINKBUSD", + ETCBUSD = "ETCBUSD", + STXBNB = "STXBNB", + STXBTC = "STXBTC", + STXUSDT = "STXUSDT", + KAVABNB = "KAVABNB", + KAVABTC = "KAVABTC", + KAVAUSDT = "KAVAUSDT", + BUSDNGN = "BUSDNGN", + BNBNGN = "BNBNGN", + BTCNGN = "BTCNGN", + ARPABNB = "ARPABNB", + ARPABTC = "ARPABTC", + ARPAUSDT = "ARPAUSDT", + TRXBUSD = "TRXBUSD", + EOSBUSD = "EOSBUSD", + IOTXUSDT = "IOTXUSDT", + RLCUSDT = "RLCUSDT", + MCOUSDT = "MCOUSDT", + XLMBUSD = "XLMBUSD", + ADABUSD = "ADABUSD", + CTXCBNB = "CTXCBNB", + CTXCBTC = "CTXCBTC", + CTXCUSDT = "CTXCUSDT", + BCHBNB = "BCHBNB", + BCHBTC = "BCHBTC", + BCHUSDT = "BCHUSDT", + BCHUSDC = "BCHUSDC", + BCHTUSD = "BCHTUSD", + BCHPAX = "BCHPAX", + BCHBUSD = "BCHBUSD", + BTCRUB = "BTCRUB", + ETHRUB = "ETHRUB", + XRPRUB = "XRPRUB", + BNBRUB = "BNBRUB", + TROYBNB = "TROYBNB", + TROYBTC = "TROYBTC", + TROYUSDT = "TROYUSDT", + BUSDRUB = "BUSDRUB", + QTUMBUSD = "QTUMBUSD", + VETBUSD = "VETBUSD", + VITEBNB = "VITEBNB", + VITEBTC = "VITEBTC", + VITEUSDT = "VITEUSDT", + FTTBNB = "FTTBNB", + FTTBTC = "FTTBTC", + FTTUSDT = "FTTUSDT", + BTCTRY = "BTCTRY", + BNBTRY = "BNBTRY", + BUSDTRY = "BUSDTRY", + ETHTRY = "ETHTRY", + XRPTRY = "XRPTRY", + USDTTRY = "USDTTRY", + USDTRUB = "USDTRUB", + BTCEUR = "BTCEUR", + ETHEUR = "ETHEUR", + BNBEUR = "BNBEUR", + XRPEUR = "XRPEUR", + EURBUSD = "EURBUSD", + EURUSDT = "EURUSDT", + OGNBNB = "OGNBNB", + OGNBTC = "OGNBTC", + OGNUSDT = "OGNUSDT", + DREPBNB = "DREPBNB", + DREPBTC = "DREPBTC", + DREPUSDT = "DREPUSDT", + BULLUSDT = "BULLUSDT", + BULLBUSD = "BULLBUSD", + BEARUSDT = "BEARUSDT", + BEARBUSD = "BEARBUSD", + ETHBULLUSDT = "ETHBULLUSDT", + ETHBULLBUSD = "ETHBULLBUSD", + ETHBEARUSDT = "ETHBEARUSDT", + ETHBEARBUSD = "ETHBEARBUSD", + TCTBNB = "TCTBNB", + TCTBTC = "TCTBTC", + TCTUSDT = "TCTUSDT", + WRXBNB = "WRXBNB", + WRXBTC = "WRXBTC", + WRXUSDT = "WRXUSDT", + ICXBUSD = "ICXBUSD", + BTSUSDT = "BTSUSDT", + BTSBUSD = "BTSBUSD", + LSKUSDT = "LSKUSDT", + BNTUSDT = "BNTUSDT", + BNTBUSD = "BNTBUSD", + LTOBNB = "LTOBNB", + LTOBTC = "LTOBTC", + LTOUSDT = "LTOUSDT", + ATOMBUSD = "ATOMBUSD", + DASHBUSD = "DASHBUSD", + NEOBUSD = "NEOBUSD", + WAVESBUSD = "WAVESBUSD", + XTZBUSD = "XTZBUSD", + EOSBULLUSDT = "EOSBULLUSDT", + EOSBULLBUSD = "EOSBULLBUSD", + EOSBEARUSDT = "EOSBEARUSDT", + EOSBEARBUSD = "EOSBEARBUSD", + XRPBULLUSDT = "XRPBULLUSDT", + XRPBULLBUSD = "XRPBULLBUSD", + XRPBEARUSDT = "XRPBEARUSDT", + XRPBEARBUSD = "XRPBEARBUSD", + BATBUSD = "BATBUSD", + ENJBUSD = "ENJBUSD", + NANOBUSD = "NANOBUSD", + ONTBUSD = "ONTBUSD", + RVNBUSD = "RVNBUSD", + STRATBUSD = "STRATBUSD", + STRATBNB = "STRATBNB", + STRATUSDT = "STRATUSDT", + AIONBUSD = "AIONBUSD", + AIONUSDT = "AIONUSDT", + MBLBNB = "MBLBNB", + MBLBTC = "MBLBTC", + MBLUSDT = "MBLUSDT", + COTIBNB = "COTIBNB", + COTIBTC = "COTIBTC", + COTIUSDT = "COTIUSDT", + ALGOBUSD = "ALGOBUSD", + BTTBUSD = "BTTBUSD", + TOMOBUSD = "TOMOBUSD", + XMRBUSD = "XMRBUSD", + ZECBUSD = "ZECBUSD", + BNBBULLUSDT = "BNBBULLUSDT", + BNBBULLBUSD = "BNBBULLBUSD", + BNBBEARUSDT = "BNBBEARUSDT", + BNBBEARBUSD = "BNBBEARBUSD", + STPTBNB = "STPTBNB", + STPTBTC = "STPTBTC", + STPTUSDT = "STPTUSDT", + BTCZAR = "BTCZAR", + ETHZAR = "ETHZAR", + BNBZAR = "BNBZAR", + USDTZAR = "USDTZAR", + BUSDZAR = "BUSDZAR", + BTCBKRW = "BTCBKRW", + ETHBKRW = "ETHBKRW", + BNBBKRW = "BNBBKRW", + WTCUSDT = "WTCUSDT", + DATABUSD = "DATABUSD", + DATAUSDT = "DATAUSDT", + XZCUSDT = "XZCUSDT", + SOLBNB = "SOLBNB", + SOLBTC = "SOLBTC", + SOLUSDT = "SOLUSDT", + SOLBUSD = "SOLBUSD", + BTCIDRT = "BTCIDRT", + BNBIDRT = "BNBIDRT", + USDTIDRT = "USDTIDRT", + BUSDIDRT = "BUSDIDRT", + CTSIBTC = "CTSIBTC", + CTSIUSDT = "CTSIUSDT", + CTSIBNB = "CTSIBNB", + CTSIBUSD = "CTSIBUSD", + HIVEBNB = "HIVEBNB", + HIVEBTC = "HIVEBTC", + HIVEUSDT = "HIVEUSDT", + CHRBNB = "CHRBNB", + CHRBTC = "CHRBTC", + CHRUSDT = "CHRUSDT", + BTCUPUSDT = "BTCUPUSDT", + BTCDOWNUSDT = "BTCDOWNUSDT", + GXSUSDT = "GXSUSDT", + ARDRUSDT = "ARDRUSDT", + ERDBUSD = "ERDBUSD", + LENDUSDT = "LENDUSDT", + HBARBUSD = "HBARBUSD", + MATICBUSD = "MATICBUSD", + WRXBUSD = "WRXBUSD", + ZILBUSD = "ZILBUSD", + MDTBNB = "MDTBNB", + MDTBTC = "MDTBTC", + MDTUSDT = "MDTUSDT", + STMXBNB = "STMXBNB", + STMXBTC = "STMXBTC", + STMXETH = "STMXETH", + STMXUSDT = "STMXUSDT", + KNCBUSD = "KNCBUSD", + KNCUSDT = "KNCUSDT", + REPBUSD = "REPBUSD", + REPUSDT = "REPUSDT", + LRCBUSD = "LRCBUSD", + LRCUSDT = "LRCUSDT", + IQBNB = "IQBNB", + IQBUSD = "IQBUSD", + PNTBTC = "PNTBTC", + PNTUSDT = "PNTUSDT", + BTCGBP = "BTCGBP", + ETHGBP = "ETHGBP", + XRPGBP = "XRPGBP", + BNBGBP = "BNBGBP", + GBPBUSD = "GBPBUSD", + DGBBNB = "DGBBNB", + DGBBTC = "DGBBTC", + DGBBUSD = "DGBBUSD", + BTCUAH = "BTCUAH", + USDTUAH = "USDTUAH", + COMPBTC = "COMPBTC", + COMPBNB = "COMPBNB", + COMPBUSD = "COMPBUSD", + COMPUSDT = "COMPUSDT", + BTCBIDR = "BTCBIDR", + ETHBIDR = "ETHBIDR", + BNBBIDR = "BNBBIDR", + BUSDBIDR = "BUSDBIDR", + USDTBIDR = "USDTBIDR", + BKRWUSDT = "BKRWUSDT", + BKRWBUSD = "BKRWBUSD", + SCUSDT = "SCUSDT", + ZENUSDT = "ZENUSDT", + SXPBTC = "SXPBTC", + SXPBNB = "SXPBNB", + SXPBUSD = "SXPBUSD", + SNXBTC = "SNXBTC", + SNXBNB = "SNXBNB", + SNXBUSD = "SNXBUSD", + SNXUSDT = "SNXUSDT", + ETHUPUSDT = "ETHUPUSDT", + ETHDOWNUSDT = "ETHDOWNUSDT", + ADAUPUSDT = "ADAUPUSDT", + ADADOWNUSDT = "ADADOWNUSDT", + LINKUPUSDT = "LINKUPUSDT", + LINKDOWNUSDT = "LINKDOWNUSDT", + VTHOBNB = "VTHOBNB", + VTHOBUSD = "VTHOBUSD", + VTHOUSDT = "VTHOUSDT", + DCRBUSD = "DCRBUSD", + DGBUSDT = "DGBUSDT", + GBPUSDT = "GBPUSDT", + STORJBUSD = "STORJBUSD", + SXPUSDT = "SXPUSDT", + IRISBNB = "IRISBNB", + IRISBTC = "IRISBTC", + IRISBUSD = "IRISBUSD", + MKRBNB = "MKRBNB", + MKRBTC = "MKRBTC", + MKRUSDT = "MKRUSDT", + MKRBUSD = "MKRBUSD", + DAIBNB = "DAIBNB", + DAIBTC = "DAIBTC", + DAIUSDT = "DAIUSDT", + DAIBUSD = "DAIBUSD", + RUNEBNB = "RUNEBNB", + RUNEBTC = "RUNEBTC", + RUNEBUSD = "RUNEBUSD", + MANABUSD = "MANABUSD", + DOGEBUSD = "DOGEBUSD", + LENDBUSD = "LENDBUSD", + ZRXBUSD = "ZRXBUSD", + DCRUSDT = "DCRUSDT", + STORJUSDT = "STORJUSDT", + XRPBKRW = "XRPBKRW", + ADABKRW = "ADABKRW", + BTCAUD = "BTCAUD", + ETHAUD = "ETHAUD", + AUDBUSD = "AUDBUSD", + FIOBNB = "FIOBNB", + FIOBTC = "FIOBTC", + FIOBUSD = "FIOBUSD", + BNBUPUSDT = "BNBUPUSDT", + BNBDOWNUSDT = "BNBDOWNUSDT", + XTZUPUSDT = "XTZUPUSDT", + XTZDOWNUSDT = "XTZDOWNUSDT", + AVABNB = "AVABNB", + AVABTC = "AVABTC", + AVABUSD = "AVABUSD", + USDTBKRW = "USDTBKRW", + BUSDBKRW = "BUSDBKRW", + IOTABUSD = "IOTABUSD", + MANAUSDT = "MANAUSDT", + XRPAUD = "XRPAUD", + BNBAUD = "BNBAUD", + AUDUSDT = "AUDUSDT", + BALBNB = "BALBNB", + BALBTC = "BALBTC", + BALBUSD = "BALBUSD", + YFIBNB = "YFIBNB", + YFIBTC = "YFIBTC", + YFIBUSD = "YFIBUSD", + YFIUSDT = "YFIUSDT", + BLZBUSD = "BLZBUSD", + KMDBUSD = "KMDBUSD", + BALUSDT = "BALUSDT", + BLZUSDT = "BLZUSDT", + IRISUSDT = "IRISUSDT", + KMDUSDT = "KMDUSDT", + BTCDAI = "BTCDAI", + ETHDAI = "ETHDAI", + BNBDAI = "BNBDAI", + USDTDAI = "USDTDAI", + BUSDDAI = "BUSDDAI", + JSTBNB = "JSTBNB", + JSTBTC = "JSTBTC", + JSTBUSD = "JSTBUSD", + JSTUSDT = "JSTUSDT", + SRMBNB = "SRMBNB", + SRMBTC = "SRMBTC", + SRMBUSD = "SRMBUSD", + SRMUSDT = "SRMUSDT", + ANTBNB = "ANTBNB", + ANTBTC = "ANTBTC", + ANTBUSD = "ANTBUSD", + ANTUSDT = "ANTUSDT", + CRVBNB = "CRVBNB", + CRVBTC = "CRVBTC", + CRVBUSD = "CRVBUSD", + CRVUSDT = "CRVUSDT", + SANDBNB = "SANDBNB", + SANDBTC = "SANDBTC", + SANDUSDT = "SANDUSDT", + SANDBUSD = "SANDBUSD", + OCEANBNB = "OCEANBNB", + OCEANBTC = "OCEANBTC", + OCEANBUSD = "OCEANBUSD", + OCEANUSDT = "OCEANUSDT", + NMRBNB = "NMRBNB", + NMRBTC = "NMRBTC", + NMRBUSD = "NMRBUSD", + NMRUSDT = "NMRUSDT", + DOTBNB = "DOTBNB", + DOTBTC = "DOTBTC", + DOTBUSD = "DOTBUSD", + DOTUSDT = "DOTUSDT", + LUNABNB = "LUNABNB", + LUNABTC = "LUNABTC", + LUNABUSD = "LUNABUSD", + LUNAUSDT = "LUNAUSDT", + IDEXBTC = "IDEXBTC", + IDEXBUSD = "IDEXBUSD", + RSRBNB = "RSRBNB", + RSRBTC = "RSRBTC", + RSRBUSD = "RSRBUSD", + RSRUSDT = "RSRUSDT", + PAXGBNB = "PAXGBNB", + PAXGBTC = "PAXGBTC", + PAXGBUSD = "PAXGBUSD", + PAXGUSDT = "PAXGUSDT", + WNXMBNB = "WNXMBNB", + WNXMBTC = "WNXMBTC", + WNXMBUSD = "WNXMBUSD", + WNXMUSDT = "WNXMUSDT", + TRBBNB = "TRBBNB", + TRBBTC = "TRBBTC", + TRBBUSD = "TRBBUSD", + TRBUSDT = "TRBUSDT", + ETHNGN = "ETHNGN", + DOTBIDR = "DOTBIDR", + LINKAUD = "LINKAUD", + SXPAUD = "SXPAUD", + BZRXBNB = "BZRXBNB", + BZRXBTC = "BZRXBTC", + BZRXBUSD = "BZRXBUSD", + BZRXUSDT = "BZRXUSDT", + WBTCBTC = "WBTCBTC", + WBTCETH = "WBTCETH", + SUSHIBNB = "SUSHIBNB", + SUSHIBTC = "SUSHIBTC", + SUSHIBUSD = "SUSHIBUSD", + SUSHIUSDT = "SUSHIUSDT", + YFIIBNB = "YFIIBNB", + YFIIBTC = "YFIIBTC", + YFIIBUSD = "YFIIBUSD", + YFIIUSDT = "YFIIUSDT", + KSMBNB = "KSMBNB", + KSMBTC = "KSMBTC", + KSMBUSD = "KSMBUSD", + KSMUSDT = "KSMUSDT", + EGLDBNB = "EGLDBNB", + EGLDBTC = "EGLDBTC", + EGLDBUSD = "EGLDBUSD", + EGLDUSDT = "EGLDUSDT", + DIABNB = "DIABNB", + DIABTC = "DIABTC", + DIABUSD = "DIABUSD", + DIAUSDT = "DIAUSDT", + RUNEUSDT = "RUNEUSDT", + FIOUSDT = "FIOUSDT", + UMABTC = "UMABTC", + UMAUSDT = "UMAUSDT", + EOSUPUSDT = "EOSUPUSDT", + EOSDOWNUSDT = "EOSDOWNUSDT", + TRXUPUSDT = "TRXUPUSDT", + TRXDOWNUSDT = "TRXDOWNUSDT", + XRPUPUSDT = "XRPUPUSDT", + XRPDOWNUSDT = "XRPDOWNUSDT", + DOTUPUSDT = "DOTUPUSDT", + DOTDOWNUSDT = "DOTDOWNUSDT", + SRMBIDR = "SRMBIDR", + ONEBIDR = "ONEBIDR", + LINKTRY = "LINKTRY", + USDTNGN = "USDTNGN", + BELBNB = "BELBNB", + BELBTC = "BELBTC", + BELBUSD = "BELBUSD", + BELUSDT = "BELUSDT", + WINGBNB = "WINGBNB", + WINGBTC = "WINGBTC", + SWRVBNB = "SWRVBNB", + SWRVBUSD = "SWRVBUSD", + WINGBUSD = "WINGBUSD", + WINGUSDT = "WINGUSDT", + LTCUPUSDT = "LTCUPUSDT", + LTCDOWNUSDT = "LTCDOWNUSDT", + LENDBKRW = "LENDBKRW", + SXPEUR = "SXPEUR", + CREAMBNB = "CREAMBNB", + CREAMBUSD = "CREAMBUSD", + UNIBNB = "UNIBNB", + UNIBTC = "UNIBTC", + UNIBUSD = "UNIBUSD", + UNIUSDT = "UNIUSDT", + NBSBTC = "NBSBTC", + NBSUSDT = "NBSUSDT", + OXTBTC = "OXTBTC", + OXTUSDT = "OXTUSDT", + SUNBTC = "SUNBTC", + SUNUSDT = "SUNUSDT", + AVAXBNB = "AVAXBNB", + AVAXBTC = "AVAXBTC", + AVAXBUSD = "AVAXBUSD", + AVAXUSDT = "AVAXUSDT", + HNTBTC = "HNTBTC", + HNTUSDT = "HNTUSDT", + BAKEBNB = "BAKEBNB", + BURGERBNB = "BURGERBNB", + SXPBIDR = "SXPBIDR", + LINKBKRW = "LINKBKRW", + FLMBNB = "FLMBNB", + FLMBTC = "FLMBTC", + FLMBUSD = "FLMBUSD", + FLMUSDT = "FLMUSDT", + SCRTBTC = "SCRTBTC", + SCRTETH = "SCRTETH", + CAKEBNB = "CAKEBNB", + CAKEBUSD = "CAKEBUSD", + SPARTABNB = "SPARTABNB", + UNIUPUSDT = "UNIUPUSDT", + UNIDOWNUSDT = "UNIDOWNUSDT", + ORNBTC = "ORNBTC", + ORNUSDT = "ORNUSDT", + TRXNGN = "TRXNGN", + SXPTRY = "SXPTRY", + UTKBTC = "UTKBTC", + UTKUSDT = "UTKUSDT", + XVSBNB = "XVSBNB", + XVSBTC = "XVSBTC", + XVSBUSD = "XVSBUSD", + XVSUSDT = "XVSUSDT", + ALPHABNB = "ALPHABNB", + ALPHABTC = "ALPHABTC", + ALPHABUSD = "ALPHABUSD", + ALPHAUSDT = "ALPHAUSDT", + VIDTBTC = "VIDTBTC", + VIDTBUSD = "VIDTBUSD", + AAVEBNB = "AAVEBNB", + BTCBRL = "BTCBRL", + USDTBRL = "USDTBRL", + AAVEBTC = "AAVEBTC", + AAVEETH = "AAVEETH", + AAVEBUSD = "AAVEBUSD", + AAVEUSDT = "AAVEUSDT", + AAVEBKRW = "AAVEBKRW", + NEARBNB = "NEARBNB", + NEARBTC = "NEARBTC", + NEARBUSD = "NEARBUSD", + NEARUSDT = "NEARUSDT", + SXPUPUSDT = "SXPUPUSDT", + SXPDOWNUSDT = "SXPDOWNUSDT", + DOTBKRW = "DOTBKRW", + SXPGBP = "SXPGBP", + FILBNB = "FILBNB", + FILBTC = "FILBTC", + FILBUSD = "FILBUSD", + FILUSDT = "FILUSDT", + FILUPUSDT = "FILUPUSDT", + FILDOWNUSDT = "FILDOWNUSDT", + YFIUPUSDT = "YFIUPUSDT", + YFIDOWNUSDT = "YFIDOWNUSDT", + INJBNB = "INJBNB", + INJBTC = "INJBTC", + INJBUSD = "INJBUSD", + INJUSDT = "INJUSDT", + AERGOBTC = "AERGOBTC", + AERGOBUSD = "AERGOBUSD", + LINKEUR = "LINKEUR", + ONEBUSD = "ONEBUSD", + EASYETH = "EASYETH", + AUDIOBTC = "AUDIOBTC", + AUDIOBUSD = "AUDIOBUSD", + AUDIOUSDT = "AUDIOUSDT", + CTKBNB = "CTKBNB", + CTKBTC = "CTKBTC", + CTKBUSD = "CTKBUSD", + CTKUSDT = "CTKUSDT", + BCHUPUSDT = "BCHUPUSDT", + BCHDOWNUSDT = "BCHDOWNUSDT", + BOTBTC = "BOTBTC", + BOTBUSD = "BOTBUSD", + ETHBRL = "ETHBRL", + DOTEUR = "DOTEUR", + AKROBTC = "AKROBTC", + AKROUSDT = "AKROUSDT", + KP3RBNB = "KP3RBNB", + KP3RBUSD = "KP3RBUSD", + AXSBNB = "AXSBNB", + AXSBTC = "AXSBTC", + AXSBUSD = "AXSBUSD", + AXSUSDT = "AXSUSDT", + HARDBNB = "HARDBNB", + HARDBTC = "HARDBTC", + HARDBUSD = "HARDBUSD", + HARDUSDT = "HARDUSDT", + BNBBRL = "BNBBRL", + LTCEUR = "LTCEUR", + RENBTCBTC = "RENBTCBTC", + RENBTCETH = "RENBTCETH", + DNTBUSD = "DNTBUSD", + DNTUSDT = "DNTUSDT", + SLPETH = "SLPETH", + ADAEUR = "ADAEUR", + LTCNGN = "LTCNGN", + CVPETH = "CVPETH", + CVPBUSD = "CVPBUSD", + STRAXBTC = "STRAXBTC", + STRAXETH = "STRAXETH", + STRAXBUSD = "STRAXBUSD", + STRAXUSDT = "STRAXUSDT", + FORBTC = "FORBTC", + FORBUSD = "FORBUSD", + UNFIBNB = "UNFIBNB", + UNFIBTC = "UNFIBTC", + UNFIBUSD = "UNFIBUSD", + UNFIUSDT = "UNFIUSDT", + FRONTETH = "FRONTETH", + FRONTBUSD = "FRONTBUSD", + BCHABUSD = "BCHABUSD", + ROSEBTC = "ROSEBTC", + ROSEBUSD = "ROSEBUSD", + ROSEUSDT = "ROSEUSDT", + AVAXTRY = "AVAXTRY", + BUSDBRL = "BUSDBRL", + AVAUSDT = "AVAUSDT", + SYSBUSD = "SYSBUSD", + XEMUSDT = "XEMUSDT", + HEGICETH = "HEGICETH", + HEGICBUSD = "HEGICBUSD", + AAVEUPUSDT = "AAVEUPUSDT", + AAVEDOWNUSDT = "AAVEDOWNUSDT", + PROMBNB = "PROMBNB", + PROMBUSD = "PROMBUSD", + XRPBRL = "XRPBRL", + XRPNGN = "XRPNGN", + SKLBTC = "SKLBTC", + SKLBUSD = "SKLBUSD", + SKLUSDT = "SKLUSDT", + BCHEUR = "BCHEUR", + YFIEUR = "YFIEUR", + ZILBIDR = "ZILBIDR", + SUSDBTC = "SUSDBTC", + SUSDETH = "SUSDETH", + SUSDUSDT = "SUSDUSDT", + COVERETH = "COVERETH", + COVERBUSD = "COVERBUSD", + GLMBTC = "GLMBTC", + GLMETH = "GLMETH", + GHSTETH = "GHSTETH", + GHSTBUSD = "GHSTBUSD", + SUSHIUPUSDT = "SUSHIUPUSDT", + SUSHIDOWNUSDT = "SUSHIDOWNUSDT", + XLMUPUSDT = "XLMUPUSDT", + XLMDOWNUSDT = "XLMDOWNUSDT", + LINKBRL = "LINKBRL", + LINKNGN = "LINKNGN", + LTCRUB = "LTCRUB", + TRXTRY = "TRXTRY", + XLMEUR = "XLMEUR", + DFETH = "DFETH", + DFBUSD = "DFBUSD", + GRTBTC = "GRTBTC", + GRTETH = "GRTETH", + GRTUSDT = "GRTUSDT", + JUVBTC = "JUVBTC", + JUVBUSD = "JUVBUSD", + JUVUSDT = "JUVUSDT", + PSGBTC = "PSGBTC", + PSGBUSD = "PSGBUSD", + PSGUSDT = "PSGUSDT", + BUSDBVND = "BUSDBVND", + USDTBVND = "USDTBVND", + "1INCHBTC" = "1INCHBTC", + "1INCHUSDT" = "1INCHUSDT", + REEFBTC = "REEFBTC", + REEFUSDT = "REEFUSDT", + OGBTC = "OGBTC", + OGUSDT = "OGUSDT", + ATMBTC = "ATMBTC", + ATMUSDT = "ATMUSDT", + ASRBTC = "ASRBTC", + ASRUSDT = "ASRUSDT", + CELOBTC = "CELOBTC", + CELOUSDT = "CELOUSDT", + RIFBTC = "RIFBTC", + RIFUSDT = "RIFUSDT", + CHZTRY = "CHZTRY", + XLMTRY = "XLMTRY", + LINKGBP = "LINKGBP", + GRTEUR = "GRTEUR", + BTCSTBTC = "BTCSTBTC", + BTCSTBUSD = "BTCSTBUSD", + BTCSTUSDT = "BTCSTUSDT", + TRUBTC = "TRUBTC", + TRUBUSD = "TRUBUSD", + TRUUSDT = "TRUUSDT", + DEXEETH = "DEXEETH", + DEXEBUSD = "DEXEBUSD", + EOSEUR = "EOSEUR", + LTCBRL = "LTCBRL", + USDCBUSD = "USDCBUSD", + TUSDBUSD = "TUSDBUSD", + PAXBUSD = "PAXBUSD", + CKBBTC = "CKBBTC", + CKBBUSD = "CKBBUSD", + CKBUSDT = "CKBUSDT", + TWTBTC = "TWTBTC", + TWTBUSD = "TWTBUSD", + TWTUSDT = "TWTUSDT", + FIROBTC = "FIROBTC", + FIROETH = "FIROETH", + FIROUSDT = "FIROUSDT", + BETHETH = "BETHETH", + DOGEEUR = "DOGEEUR", + DOGETRY = "DOGETRY", + DOGEAUD = "DOGEAUD", + DOGEBRL = "DOGEBRL", + DOTNGN = "DOTNGN", + PROSETH = "PROSETH", + LITBTC = "LITBTC", + LITBUSD = "LITBUSD", + LITUSDT = "LITUSDT", + BTCVAI = "BTCVAI", + BUSDVAI = "BUSDVAI", + SFPBTC = "SFPBTC", + SFPBUSD = "SFPBUSD", + SFPUSDT = "SFPUSDT", + DOGEGBP = "DOGEGBP", + DOTTRY = "DOTTRY", + FXSBTC = "FXSBTC", + FXSBUSD = "FXSBUSD", + DODOBTC = "DODOBTC", + DODOBUSD = "DODOBUSD", + DODOUSDT = "DODOUSDT", + FRONTBTC = "FRONTBTC", + EASYBTC = "EASYBTC", + CAKEBTC = "CAKEBTC", + CAKEUSDT = "CAKEUSDT", + BAKEBUSD = "BAKEBUSD", + UFTETH = "UFTETH", + UFTBUSD = "UFTBUSD", + "1INCHBUSD" = "1INCHBUSD", + BANDBUSD = "BANDBUSD", + GRTBUSD = "GRTBUSD", + IOSTBUSD = "IOSTBUSD", + OMGBUSD = "OMGBUSD", + REEFBUSD = "REEFBUSD", + ACMBTC = "ACMBTC", + ACMBUSD = "ACMBUSD", + ACMUSDT = "ACMUSDT", + AUCTIONBTC = "AUCTIONBTC", + AUCTIONBUSD = "AUCTIONBUSD", + PHABTC = "PHABTC", + PHABUSD = "PHABUSD", + DOTGBP = "DOTGBP", + ADATRY = "ADATRY", + ADABRL = "ADABRL", + ADAGBP = "ADAGBP", + TVKBTC = "TVKBTC", + TVKBUSD = "TVKBUSD", + BADGERBTC = "BADGERBTC", + BADGERBUSD = "BADGERBUSD", + BADGERUSDT = "BADGERUSDT", + FISBTC = "FISBTC", + FISBUSD = "FISBUSD", + FISUSDT = "FISUSDT", + DOTBRL = "DOTBRL", + ADAAUD = "ADAAUD", + HOTTRY = "HOTTRY", + EGLDEUR = "EGLDEUR", + OMBTC = "OMBTC", + OMBUSD = "OMBUSD", + OMUSDT = "OMUSDT", + PONDBTC = "PONDBTC", + PONDBUSD = "PONDBUSD", + PONDUSDT = "PONDUSDT", + DEGOBTC = "DEGOBTC", + DEGOBUSD = "DEGOBUSD", + DEGOUSDT = "DEGOUSDT", + AVAXEUR = "AVAXEUR", + BTTTRY = "BTTTRY", + CHZBRL = "CHZBRL", + UNIEUR = "UNIEUR", + ALICEBTC = "ALICEBTC", + ALICEBUSD = "ALICEBUSD", + ALICEUSDT = "ALICEUSDT", + CHZBUSD = "CHZBUSD", + CHZEUR = "CHZEUR", + CHZGBP = "CHZGBP", + BIFIBNB = "BIFIBNB", + BIFIBUSD = "BIFIBUSD", + LINABTC = "LINABTC", + LINABUSD = "LINABUSD", + LINAUSDT = "LINAUSDT", + ADARUB = "ADARUB", + ENJBRL = "ENJBRL", + ENJEUR = "ENJEUR", + MATICEUR = "MATICEUR", + NEOTRY = "NEOTRY", + PERPBTC = "PERPBTC", + PERPBUSD = "PERPBUSD", + PERPUSDT = "PERPUSDT", + RAMPBTC = "RAMPBTC", + RAMPBUSD = "RAMPBUSD", + RAMPUSDT = "RAMPUSDT", + SUPERBTC = "SUPERBTC", + SUPERBUSD = "SUPERBUSD", + SUPERUSDT = "SUPERUSDT", + CFXBTC = "CFXBTC", + CFXBUSD = "CFXBUSD", + CFXUSDT = "CFXUSDT", + ENJGBP = "ENJGBP", + EOSTRY = "EOSTRY", + LTCGBP = "LTCGBP", + LUNAEUR = "LUNAEUR", } diff --git a/src/vendor/trader/index.ts b/src/vendor/trader/index.ts index 6af1775..5ab524a 100644 --- a/src/vendor/trader/index.ts +++ b/src/vendor/trader/index.ts @@ -391,32 +391,32 @@ class Trader implements Trading { funds, lastWorkBackup.price ) - const price = order.price || lastWorkBackup.price - const fundsUsed = price * order.executedQuantity + const price = order.price ?? lastWorkBackup.price.toString() + const fundsUsed = parseFloat(price) * parseFloat(order.executedQty) const fees = fundsUsed * config.market.orderFees if (config.api.sandbox) { this.quoteCurrencyBalance -= fundsUsed - this.baseCurrencyBalance += order.executedQuantity + this.baseCurrencyBalance += parseFloat(order.executedQty) } else { await this.updateBalances() } Logger.debug(`Order formatted: ${JSON.stringify(order, null, 2)}`) - if (lastWorkBackup.price !== price) { + if (lastWorkBackup.price.toString() !== price) { Logger.debug(`WARN: prices have diverged when bot wanted to buy.`) Logger.debug(`Bot buy price desired: ${lastWorkBackup.price}`) Logger.debug(`Real order price: ${price} ${this.quoteCurrency}`) } this.lastBuyTrade = { - price, + price: parseFloat(price), time: lastWorkBackup.time, benefits: -fundsUsed, fees, type: TradeType.BUY, - quantity: order.executedQuantity, + quantity: parseFloat(order.executedQty), } this.actionsPostBuyTrade() @@ -434,10 +434,10 @@ class Trader implements Trading { Logger.debug( `Would be able to sell when the price will be above ${Equation.thresholdPriceOfProfitability( this.lastBuyTrade.price - ).toFixed(8)}${this.quoteCurrency}` + ).toFixed(8)} ${this.quoteCurrency}` ) - Logger.debug(`Funds desired to invest: ${funds}${this.quoteCurrency}`) - Logger.debug(`Funds really invested: ${fundsUsed}${this.quoteCurrency}`) + Logger.debug(`Funds desired to invest: ${funds} ${this.quoteCurrency}`) + Logger.debug(`Funds really invested: ${fundsUsed} ${this.quoteCurrency}`) } catch (error) { Logger.error( `Error when trying to buy: ${JSON.stringify(error, null, 2)}` @@ -466,13 +466,14 @@ class Trader implements Trading { size, lastWorkBackup.price ) - const price = order.price || lastWorkBackup.price - const fees = price * order.executedQuantity * config.market.orderFees - const quoteCurrencyQuantity = price * order.executedQuantity - fees + const price = order.price ? parseFloat(order.price) : lastWorkBackup.price + const quantity = parseFloat(order.executedQty) + const fees = price * quantity * config.market.orderFees + const quoteCurrencyQuantity = price * quantity - fees if (config.api.sandbox) { this.quoteCurrencyBalance += quoteCurrencyQuantity - this.baseCurrencyBalance -= order.executedQuantity + this.baseCurrencyBalance -= quantity } else { await this.updateBalances() } @@ -493,7 +494,7 @@ class Trader implements Trading { 2 * (config.market.orderFees * 100), fees, type: partial ? TradeType.SELL_PARTIAL : TradeType.SELL, - quantity: order.executedQuantity, + quantity, } this.actionsPostSellTrade()