From 6914ae5b25b6d5147f4ab073ef022b9db73a6a25 Mon Sep 17 00:00:00 2001 From: rosendo <42633099+rosendolu@users.noreply.github.com> Date: Sat, 13 Jul 2024 17:03:14 +0800 Subject: [PATCH] refactor: source directory; --- .vscode/settings.json | 2 +- app/common/utils.js | 64 ---- ecosystem.config.js | 2 +- nodemon.json | 2 +- package-lock.json | 591 +++++++++++++++++++++++++++++- package.json | 10 +- app/index.js => src/app.js | 6 +- {app => src}/common/constant.js | 0 {app => src}/common/env.js | 0 {app => src}/common/jsonStream.js | 2 +- {app => src}/common/logger.js | 37 +- src/common/useCompose.js | 25 ++ src/common/utils.js | 149 ++++++++ src/controller/binance.js | 0 src/middleware/binance.js | 94 +++++ {app => src}/middleware/file.js | 2 +- {app => src}/middleware/http.js | 2 +- {app => src}/middleware/index.js | 2 +- {app => src}/middleware/user.js | 2 +- {app => src}/router/file.route.js | 0 {app => src}/router/http.route.js | 0 {app => src}/router/index.js | 6 +- {app => src}/router/root.route.js | 0 {app => src}/router/test.route.js | 0 {app => src}/router/user.route.js | 0 src/schedule/binance.schedule.js | 47 +++ src/schedule/index.js | 17 + src/service/binance.js | 83 +++++ src/service/mail.js | 0 src/service/mongo.js | 0 tsconfig.json | 2 +- 31 files changed, 1044 insertions(+), 103 deletions(-) delete mode 100644 app/common/utils.js rename app/index.js => src/app.js (87%) rename {app => src}/common/constant.js (100%) rename {app => src}/common/env.js (100%) rename {app => src}/common/jsonStream.js (97%) rename {app => src}/common/logger.js (57%) create mode 100644 src/common/useCompose.js create mode 100644 src/common/utils.js create mode 100644 src/controller/binance.js create mode 100644 src/middleware/binance.js rename {app => src}/middleware/file.js (97%) rename {app => src}/middleware/http.js (98%) rename {app => src}/middleware/index.js (97%) rename {app => src}/middleware/user.js (98%) rename {app => src}/router/file.route.js (100%) rename {app => src}/router/http.route.js (100%) rename {app => src}/router/index.js (68%) rename {app => src}/router/root.route.js (100%) rename {app => src}/router/test.route.js (100%) rename {app => src}/router/user.route.js (100%) create mode 100644 src/schedule/binance.schedule.js create mode 100644 src/schedule/index.js create mode 100644 src/service/binance.js create mode 100644 src/service/mail.js create mode 100644 src/service/mongo.js diff --git a/.vscode/settings.json b/.vscode/settings.json index c11306d..328f1fd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,7 +12,7 @@ "source.sortImports": "always", "source.fixAll.eslint": "always" }, - "cSpell.words": ["rosendofun"], + "cSpell.words": ["MACD", "rosendofun"], "outline.showConstants": false, "breadcrumbs.showConstants": false, "emmet.includeLanguages": { diff --git a/app/common/utils.js b/app/common/utils.js deleted file mode 100644 index 3166a96..0000000 --- a/app/common/utils.js +++ /dev/null @@ -1,64 +0,0 @@ -const crypto = require('crypto'); -const dayjs = require('dayjs'); -const path = require('path'); -const fs = require('fs'); -const { v4: uuidV4 } = require('uuid'); -const env = require('./env'); -const faker = require('chance').Chance(); - -module.exports = { - faker, - timestamp() { - return dayjs().format('YYYY-MM-DD HH:mm:ss'); - }, - getStaticFile(fileName) { - return fs.createReadStream(path.resolve('static', fileName)); - }, - waitForSeconds(ms = 1e3) { - return new Promise(resolve => { - setTimeout(() => { - resolve(1); - }, ms); - }); - }, - uid() { - return uuidV4(); - }, - hmac(message) { - const hmac = crypto.createHmac('sha256', env.SECRET_KEYS); - hmac.update(message); - return hmac.digest('hex'); - }, - rsa: { - // 加密函数 - encryptRSA(text, publicKey = env.PUBLIC_KEY) { - return crypto.publicEncrypt(publicKey, Buffer.from(text, 'utf8')).toString('base64'); - }, - - // 解密函数 - decryptRSA(encrypted, privateKey = env.PRIVATE_KEY) { - return crypto.privateDecrypt(privateKey, Buffer.from(encrypted, 'base64')).toString('utf8'); - }, - }, - aes: { - // 加密函数 - encryptAES(text, key) { - const iv = crypto.randomBytes(16); // 生成随机的初始化向量 - const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv); - let encrypted = cipher.update(text, 'utf8', 'hex'); - encrypted += cipher.final('hex'); - return { - iv: iv.toString('hex'), - encryptedData: encrypted, - }; - }, - - // 解密函数 - decryptAES(encryptedData, key, iv) { - const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key), Buffer.from(iv, 'hex')); - let decrypted = decipher.update(encryptedData, 'hex', 'utf8'); - decrypted += decipher.final('utf8'); - return decrypted; - }, - }, -}; diff --git a/ecosystem.config.js b/ecosystem.config.js index 2c3fba1..fb63776 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -4,7 +4,7 @@ module.exports = { name: 'rosendofun.service', // watch: ['app', '.env', '.env.local'], // "ignore_watch":['static','script'], - script: './app/index.js', + script: './src/app.js', }, ], }; diff --git a/nodemon.json b/nodemon.json index 9d0b0e6..e2cbfa9 100644 --- a/nodemon.json +++ b/nodemon.json @@ -2,7 +2,7 @@ "restartable": "rs", "ignore": [".git", "node_modules/*", "local/*", "script/*", ".vscode/**/*", "./dist/**/*"], "verbose": true, - "watch": ["./app"], + "watch": ["./src"], "env": { "NODE_ENV": "dev" }, diff --git a/package-lock.json b/package-lock.json index fd94f29..e8caa5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@koa/router": "^12.0.1", "@types/node": "^20.12.7", "chance": "^1.1.11", + "cron": "^3.1.7", "dayjs": "^1.11.10", "dotenv": "^16.4.5", "env-cmd": "^10.1.0", @@ -23,8 +24,11 @@ "koa-body": "^6.0.1", "koa-session": "^6.4.0", "koa-static": "^5.0.0", + "node-binance-api": "github:auto-helper/node-binance-api", + "technicalindicators": "^3.1.0", "uuid": "^9.0.1", - "winston": "^3.13.0" + "winston": "^3.13.0", + "winston-daily-rotate-file": "^5.0.0" }, "devDependencies": { "@tsconfig/node20": "^20.1.4", @@ -451,6 +455,11 @@ "@types/koa": "*" } }, + "node_modules/@types/luxon": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", + "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==" + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -757,11 +766,21 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "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/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -815,11 +834,45 @@ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/async": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.0.tgz", + "integrity": "sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g==" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -844,6 +897,22 @@ } ] }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "engines": { + "node": "*" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -941,6 +1010,11 @@ "node": ">=6" } }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1038,6 +1112,17 @@ "text-hex": "1.0.x" } }, + "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/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -1096,6 +1181,15 @@ "buffer": "^5.1.0" } }, + "node_modules/cron": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/cron/-/cron-3.1.7.tgz", + "integrity": "sha512-tlBg7ARsAMQLzgwqVxy8AZl/qlTc5nibqYwtNGoCrd+cV+ugI+tvZC1oT/8dFH8W455YrywGykx/KMmAqOr7Jw==", + "dependencies": { + "@types/luxon": "~3.4.0", + "luxon": "~3.4.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1109,6 +1203,17 @@ "node": ">= 8" } }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/dayjs": { "version": "1.11.10", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", @@ -1157,6 +1262,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -1228,6 +1341,15 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -1293,6 +1415,19 @@ "node": ">= 0.4" } }, + "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": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1452,11 +1587,23 @@ "node": ">=0.10.0" } }, + "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/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "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==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-glob": { "version": "3.3.2", @@ -1489,8 +1636,7 @@ "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==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -1524,6 +1670,14 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-stream-rotator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.6.1.tgz", + "integrity": "sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==", + "dependencies": { + "moment": "^2.29.1" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1592,6 +1746,27 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "engines": { + "node": "*" + } + }, + "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/formidable": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", @@ -1659,6 +1834,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, "node_modules/glob": { "version": "10.3.12", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", @@ -1771,6 +1954,27 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1881,6 +2085,40 @@ "node": ">= 0.6" } }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "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/https-proxy-agent/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/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -1968,6 +2206,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha512-rBtCAQAJm8A110nbwn6YdveUnuZH3WrC36IwkRXxDnq53JvXA2NVQvB7IHyKomxK1MJ4VDNw3UtFDdXQ+AvLYA==" + }, "node_modules/is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", @@ -2060,6 +2303,11 @@ "isstream": "~0.1.2" } }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2099,17 +2347,34 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + }, + "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.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, "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==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -2117,6 +2382,11 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "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": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -2149,6 +2419,20 @@ "npm": ">=6" } }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/jwa": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", @@ -2407,6 +2691,14 @@ "node": ">=10" } }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "engines": { + "node": ">=12" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -2484,6 +2776,14 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -2503,6 +2803,37 @@ "node": ">= 0.6" } }, + "node_modules/node-binance-api": { + "version": "0.13.1", + "resolved": "git+ssh://git@github.com/auto-helper/node-binance-api.git#84a43eb9daec923417dc8bdf8aa1bdf29925e2fc", + "license": "MIT", + "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/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/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "engines": { + "node": ">= 6" + } + }, "node_modules/object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", @@ -2672,6 +3003,11 @@ "node": ">=8" } }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -2693,11 +3029,15 @@ "node": ">= 0.8.0" } }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, "engines": { "node": ">=6" } @@ -2786,6 +3126,54 @@ "node": ">= 6" } }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "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/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -3038,6 +3426,75 @@ "node": ">=8" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "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/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "dependencies": { + "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", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -3062,6 +3519,11 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==" + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -3169,6 +3631,19 @@ "node": ">=8" } }, + "node_modules/technicalindicators": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/technicalindicators/-/technicalindicators-3.1.0.tgz", + "integrity": "sha512-f16mOc+Y05hNy/of+UbGxhxQQmxUztCiluhsqC5QLUYz4WowUgKde9m6nIjK1Kay0wGHigT0IkOabpp0+22UfA==", + "dependencies": { + "@types/node": "^6.0.96" + } + }, + "node_modules/technicalindicators/node_modules/@types/node": { + "version": "6.14.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.14.13.tgz", + "integrity": "sha512-J1F0XJ/9zxlZel5ZlbeSuHW2OpabrUAqpFuC2sm2I3by8sERQ8+KCjNKUcq8QHuzpGMWiJpo9ZxeHrqrP2KzQw==" + }, "node_modules/text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", @@ -3200,6 +3675,18 @@ "node": ">=0.6" } }, + "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/triple-beam": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", @@ -3228,6 +3715,22 @@ "node": ">=0.6.x" } }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "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": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -3303,11 +3806,24 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "dependencies": { "punycode": "^2.1.0" } }, + "node_modules/url": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz", + "integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.11.2" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -3333,6 +3849,24 @@ "node": ">= 0.8" } }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "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/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -3368,6 +3902,23 @@ "node": ">= 12.0.0" } }, + "node_modules/winston-daily-rotate-file": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-5.0.0.tgz", + "integrity": "sha512-JDjiXXkM5qvwY06733vf09I2wnMXpZEhxEVOSPenZMii+g7pcDcTBt2MRugnoi8BwVSuCT2jfRXBUy+n1Zz/Yw==", + "dependencies": { + "file-stream-rotator": "^0.6.1", + "object-hash": "^3.0.0", + "triple-beam": "^1.4.1", + "winston-transport": "^4.7.0" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "winston": "^3" + } + }, "node_modules/winston-transport": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", @@ -3473,6 +4024,26 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index 62245b0..6b14529 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,9 @@ "version": "0.0.1", "type": "commonjs", "description": "rosendofun.service", - "main": "app/index.js", + "main": "src/app.js", "scripts": { - "dev": "nodemon app/index.js", + "dev": "nodemon src/app.js", "prod": "pm2 start ecosystem.config.js" }, "repository": { @@ -26,6 +26,7 @@ "@koa/router": "^12.0.1", "@types/node": "^20.12.7", "chance": "^1.1.11", + "cron": "^3.1.7", "dayjs": "^1.11.10", "dotenv": "^16.4.5", "env-cmd": "^10.1.0", @@ -36,8 +37,11 @@ "koa-body": "^6.0.1", "koa-session": "^6.4.0", "koa-static": "^5.0.0", + "node-binance-api": "github:auto-helper/node-binance-api", + "technicalindicators": "^3.1.0", "uuid": "^9.0.1", - "winston": "^3.13.0" + "winston": "^3.13.0", + "winston-daily-rotate-file": "^5.0.0" }, "devDependencies": { "@tsconfig/node20": "^20.1.4", diff --git a/app/index.js b/src/app.js similarity index 87% rename from app/index.js rename to src/app.js index ab59248..586e994 100644 --- a/app/index.js +++ b/src/app.js @@ -2,13 +2,15 @@ require('dotenv').config({ path: ['.env', '.env.local'], override: true }); const Koa = require('koa'); const serve = require('koa-static'); -const logger = require('./common/logger'); +const { logger } = require('./common/logger'); const cors = require('@koa/cors'); const router = require('./router/index'); const dayjs = require('dayjs'); const relativeTime = require('dayjs/plugin/relativeTime'); +const duration = require('dayjs/plugin/duration'); // Extend dayjs with the relativeTime plugin dayjs.extend(relativeTime); +dayjs.extend(duration); const { commonHandle, useKoaBody } = require('./middleware'); const koaSession = require('koa-session'); const constant = require('./common/constant'); @@ -29,7 +31,7 @@ app.use(user.userHandle()); app.use(useKoaBody()); app.use(serve(path.join(constant.rootDir, 'temp/upload'))); app.use(router.routes()).use(router.allowedMethods()); - +require('./schedule/index'); app.listen(env.PORT, () => { logger.info(`Server running at http://localhost:%s`, env.PORT); }); diff --git a/app/common/constant.js b/src/common/constant.js similarity index 100% rename from app/common/constant.js rename to src/common/constant.js diff --git a/app/common/env.js b/src/common/env.js similarity index 100% rename from app/common/env.js rename to src/common/env.js diff --git a/app/common/jsonStream.js b/src/common/jsonStream.js similarity index 97% rename from app/common/jsonStream.js rename to src/common/jsonStream.js index ad9807c..0db4a10 100644 --- a/app/common/jsonStream.js +++ b/src/common/jsonStream.js @@ -1,5 +1,5 @@ const { Transform } = require('stream'); -const logger = require('./logger'); +const { logger } = require('./logger'); // Define a Transform stream to parse JSON objects line by line class JSONStream extends Transform { diff --git a/app/common/logger.js b/src/common/logger.js similarity index 57% rename from app/common/logger.js rename to src/common/logger.js index a187d19..d3ce9a0 100644 --- a/app/common/logger.js +++ b/src/common/logger.js @@ -3,10 +3,12 @@ const utils = require('./utils'); const path = require('path'); const { isProdEnv, rootDir } = require('./constant'); const { ensureDirSync } = require('fs-extra'); +const DailyRotateFile = require('winston-daily-rotate-file'); -const appLogPath = path.resolve(rootDir, 'temp/logs', utils.timestamp().split(' ')[0]); +const appLogPath = path.resolve(rootDir, 'temp/logs'); ensureDirSync(appLogPath); -const loggerFileNameList = ['app']; + +const loggerFileNameList = ['app', 'binance']; const fileFormat = winston.format.combine( winston.format.splat(), @@ -29,13 +31,22 @@ for (const loggerName of loggerFileNameList) { function loggerOptions(key) { const transports = [ - new winston.transports.File({ - filename: `${appLogPath}/${key}.error.log`, - level: 'error', - }), - new winston.transports.File({ - filename: `${appLogPath}/${key}.log`, - level: 'debug', + // new winston.transports.File({ + // filename: `${appLogPath}/${key}.error.log`, + // level: 'error', + // }), + // new winston.transports.File({ + // filename: `${appLogPath}/${key}.log`, + // }), + new DailyRotateFile({ + dirname: `${appLogPath}`, + filename: `%DATE%-${key}`, + level: !isProdEnv ? 'debug' : 'info', + datePattern: 'YYYY-MM-DD', + maxSize: '5m', + extension: '.log', + maxFiles: '7d', + zippedArchive: false, }), ]; if (!isProdEnv) { @@ -50,16 +61,18 @@ function loggerOptions(key) { level: isProdEnv ? 'info' : 'debug', exitOnError: false, format: fileFormat, - // defaultMeta: { service: 'user-service' }, + // defaultMeta: { key }, transports: transports, }; } const logger = getLogger('app'); +process.on('uncaughtException', err => logger.error('uncaughtException %s', err)); +process.on('uncaughtExceptionMonitor', err => logger.error('uncaughtExceptionMonitor %s', err)); +process.on('unhandledRejection', err => logger.error('unhandledRejection %s', err)); function getLogger(type = 'app') { return winston.loggers.get(type); } -module.exports = logger; -exports.getLogger = getLogger; +module.exports = { logger, getLogger }; diff --git a/src/common/useCompose.js b/src/common/useCompose.js new file mode 100644 index 0000000..c83e3da --- /dev/null +++ b/src/common/useCompose.js @@ -0,0 +1,25 @@ +const compose = require('koa-compose'); +const { logger } = require('./logger'); +module.exports = class CreateCompose { + static middleware = []; + use(channel, ...cb) { + if (!channel) return this; + if (!CreateCompose.middleware[channel]) { + CreateCompose.middleware[channel] = []; + } + CreateCompose.middleware[channel].push(...cb); + return this; + } + static async useCallback(channel, ctx) { + try { + if (!channel) return; + const fn = compose(this.middleware[channel]); + await fn(ctx, ctx => Promise.resolve(ctx)); + } catch (err) { + logger.error(`CreateCompose middleware %s %s`, channel, err.toString()); + } + } + trigger(channel, ctx) { + return CreateCompose.useCallback(channel, ctx); + } +}; diff --git a/src/common/utils.js b/src/common/utils.js new file mode 100644 index 0000000..965f4f7 --- /dev/null +++ b/src/common/utils.js @@ -0,0 +1,149 @@ +const crypto = require('crypto'); +const dayjs = require('dayjs'); +const path = require('path'); +const fs = require('fs'); +const { v4: uuidV4 } = require('uuid'); +const env = require('./env'); +const { text } = require('stream/consumers'); +const { log } = require('console'); +const faker = require('chance').Chance(); + +function timestamp() { + return dayjs().format('YYYY-MM-DD HH:mm:ss'); +} +function getStaticFile(fileName) { + return fs.createReadStream(path.resolve('static', fileName)); +} +function waitForSeconds(ms = 1e3) { + return new Promise(resolve => { + setTimeout(() => { + resolve(1); + }, ms); + }); +} +async function delay(ms) { + return new Promise(resolve => { + setTimeout(() => { + resolve(1); + }, ms); + }); +} +function betweenMinMax(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; +} +function createConcurrent(concurrency, msFn) { + let pendingCount = 0; + const queue = []; + async function concurrentWrapper(callback) { + if (pendingCount >= concurrency) { + await new Promise(resolve => queue.push(resolve)); + } + pendingCount++; + try { + await Promise.resolve(callback()); + await delay(msFn()); + } finally { + pendingCount--; + if (queue.length > 0) { + const resolve = queue.shift(); + resolve(); + } + } + } + return concurrentWrapper; +} +async function waitFor(fn, msFn, maxCount = -1) { + let pollCount = 0; + async function callback(resolve, reject) { + try { + const res = await Promise.resolve(fn()); + if (res) { + return resolve(res); + } + } catch (err) { + log('fn poll err', fn?.name, err); + } + pollCount++; + if (maxCount != -1 && pollCount > maxCount) { + return reject(`maxCount limit, maxCount`); + } + await delay(msFn()); + callback(resolve, reject); + } + return new Promise((resolve, reject) => callback(resolve, reject)); +} +function uid() { + return uuidV4(); +} +function hmac(message) { + const hmac = crypto.createHmac('sha256', env.SECRET_KEYS); + hmac.update(message); + return hmac.digest('hex'); +} + +// 加密函数 +function encryptRSA(text, publicKey = env.PUBLIC_KEY) { + return crypto.publicEncrypt(publicKey, Buffer.from(text, 'utf8')).toString('base64'); +} + +// 解密函数 +function decryptRSA(encrypted, privateKey = env.PRIVATE_KEY) { + return crypto.privateDecrypt(privateKey, Buffer.from(encrypted, 'base64')).toString('utf8'); +} + +// 加密函数 +function encryptAES(text, key) { + const iv = crypto.randomBytes(16); // 生成随机的初始化向量 + const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv); + let encrypted = cipher.update(text, 'utf8', 'hex'); + encrypted += cipher.final('hex'); + return { + iv: iv.toString('hex'), + encryptedData: encrypted, + }; +} + +// 解密函数 +function decryptAES(encryptedData, key, iv) { + const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key), Buffer.from(iv, 'hex')); + let decrypted = decipher.update(encryptedData, 'hex', 'utf8'); + decrypted += decipher.final('utf8'); + return decrypted; +} + +function displayDuration(date) { + let diff = dayjs().diff(date); + const duration = dayjs.duration(diff); + const days = duration.days(); + const hours = duration.hours(); + const minutes = duration.minutes(); + const seconds = duration.seconds(); + + return `${days ? days + 'd' : ''}${hours ? hours + 'h' : ''}${minutes ? minutes + 'm' : ''}${ + seconds ? seconds + 's' : '' + }`; +} + +module.exports = { + displayDuration, + faker, + betweenMinMax, + timestamp, + getStaticFile, + waitForSeconds, + delay, + createConcurrent, + waitFor, + uid, + hmac, + rsa: { + encryptRSA, + decryptRSA, + }, + aes: { + encryptAES, + decryptAES, + }, +}; diff --git a/src/controller/binance.js b/src/controller/binance.js new file mode 100644 index 0000000..e69de29 diff --git a/src/middleware/binance.js b/src/middleware/binance.js new file mode 100644 index 0000000..8139b35 --- /dev/null +++ b/src/middleware/binance.js @@ -0,0 +1,94 @@ +const { BollingerBands, MACD, Stochastic } = require('technicalindicators'); +const { getLogger } = require('../common/logger'); +const binance = require('../service/binance'); +const log = getLogger('binance'); + +module.exports = { + async getCandlesticks(ctx, next) { + const { symbol, interval = '1h' } = ctx; + await new Promise((resolve, reject) => { + binance.api.candlesticks( + symbol, + interval, + (error, ticks, symbol) => { + if (error) { + return reject(error); + } + ctx.ticks = ticks; + // let last_tick = ticks[ticks.length - 1]; + // log.info('%s %s last close: %j', symbol, interval, last_tick); + resolve(1); + }, + { limit: 50, endTime: Date.now() } + ); + }); + await next(); + }, + async calculateIndicators(ctx, next) { + const { symbol, interval } = ctx; + const len = ctx.ticks.length, + ticks = ctx.ticks; + + let last_tick = ticks[len - 1]; + // [time,open,high,low,close,volume,closeTime,assetVolume,trades,buyBaseVolume,buyAssetVolume,ignored,] + const closes = ticks.map(data => parseFloat(data[4])); + const highs = ticks.map(data => parseFloat(data[2])); + const lows = ticks.map(data => parseFloat(data[3])); + ctx.BOLL = BollingerBands.calculate({ + period: 20, + values: closes, + stdDev: 2, + }); + ctx.boll = ctx.BOLL[ctx.BOLL.length - 1]; + // BOLL: {"middle":545.4050000000002,"upper":605.7570496752184,"lower":485.05295032478205,"pb":0.4137974596058109} + + ctx.MACD = MACD.calculate({ + values: closes, + fastPeriod: 12, + slowPeriod: 26, + signalPeriod: 9, + SimpleMAOscillator: false, + SimpleMASignal: false, + }); + ctx.macd = ctx.MACD[ctx.MACD.length - 1]; + // { MACD: -20.590545983117522,signal: -22.632049483954525,histogram: 2.0415035008370026,} + const stoch = Stochastic.calculate({ + high: highs, + low: lows, + close: closes, + period: 9, + signalPeriod: 3, + }); + + const K = stoch.map(item => item.k); + const D = stoch.map(item => item.d); + const J = K.map((k, i) => 3 * k - 2 * D[i]); + + ctx.KDJ = { K, D, J }; + ctx.kdj = { K: K[K.length - 1], D: D[D.length - 1], J: J[J.length - 1] }; + // { K: 88.59357696566991,D: 73.51245717446496,J: 118.75581654807982,} + + log.debug('%s %s indicator: BOLL: %j ,MACD: %j , KDJ: %j', symbol, interval, ctx.boll, ctx.macd, ctx.kdj); + await next(); + }, + async matchIndicators(ctx, next) { + const { kdj, macd, boll, symbol, interval } = ctx; + if (boll.pb <= 0.1 && macd.histogram <= 0 && kdj.j <= 10) { + ctx.action = 'buy'; + } else if (boll.pb >= 0.5 && macd.histogram >= 0 && kdj.j >= 100) { + ctx.action = 'sell'; + } + ctx.action && + log.warn( + '%s %s [%s] indicator: BOLL: %j ,MACD: %j , KDJ: %j', + symbol, + interval, + ctx.action, + ctx.boll, + ctx.macd, + ctx.kdj + ); + + await next(); + }, +}; diff --git a/app/middleware/file.js b/src/middleware/file.js similarity index 97% rename from app/middleware/file.js rename to src/middleware/file.js index 642c74a..ba4e3de 100644 --- a/app/middleware/file.js +++ b/src/middleware/file.js @@ -5,7 +5,7 @@ const util = require('node:util'); const { rootDir } = require('../common/constant'); const { glob } = require('glob'); const { spawn, exec } = require('child_process'); -const logger = require('../common/logger'); +const { logger } = require('../common/logger'); module.exports = { async uploadFile(ctx, next) { const { uid, nickname } = ctx.session; diff --git a/app/middleware/http.js b/src/middleware/http.js similarity index 98% rename from app/middleware/http.js rename to src/middleware/http.js index 031840e..20e1883 100644 --- a/app/middleware/http.js +++ b/src/middleware/http.js @@ -1,7 +1,7 @@ const fs = require('fs'); const path = require('path'); const { getStaticFile } = require('../common/utils'); -const logger = require('../common/logger'); +const { logger } = require('../common/logger'); const utils = require('../common/utils'); const JSONStream = require('../common/jsonStream'); const { rootDir } = require('../common/constant'); diff --git a/app/middleware/index.js b/src/middleware/index.js similarity index 97% rename from app/middleware/index.js rename to src/middleware/index.js index f1d1e56..910a0f0 100644 --- a/app/middleware/index.js +++ b/src/middleware/index.js @@ -1,6 +1,6 @@ const { koaBody } = require('koa-body'); const path = require('path'); -const logger = require('../common/logger'); +const { logger } = require('../common/logger'); const { isProdEnv, rootDir } = require('../common/constant'); const { ensureDirSync } = require('fs-extra'); diff --git a/app/middleware/user.js b/src/middleware/user.js similarity index 98% rename from app/middleware/user.js rename to src/middleware/user.js index cafeb55..5e8c120 100644 --- a/app/middleware/user.js +++ b/src/middleware/user.js @@ -1,6 +1,6 @@ const { koaBody } = require('koa-body'); const path = require('path'); -const logger = require('../common/logger'); +const { logger } = require('../common/logger'); const { isProdEnv, rootDir } = require('../common/constant'); const utils = require('../common/utils'); const fs = require('fs'); diff --git a/app/router/file.route.js b/src/router/file.route.js similarity index 100% rename from app/router/file.route.js rename to src/router/file.route.js diff --git a/app/router/http.route.js b/src/router/http.route.js similarity index 100% rename from app/router/http.route.js rename to src/router/http.route.js diff --git a/app/router/index.js b/src/router/index.js similarity index 68% rename from app/router/index.js rename to src/router/index.js index 7796341..f805f63 100644 --- a/app/router/index.js +++ b/src/router/index.js @@ -1,13 +1,13 @@ const Router = require('@koa/router'); const { glob } = require('glob'); -const logger = require('../common/logger'); +const { logger } = require('../common/logger'); const path = require('path'); const { isProdEnv, rootDir } = require('../common/constant'); const router = new Router(); -const routerFiles = glob.sync('./**/*.route.js', { cwd: path.resolve(rootDir, 'app/router') }); +const routerFiles = glob.sync('./**/*.route.js', { cwd: __dirname }); if (!isProdEnv) { - logger.debug('Router/index.js %O', routerFiles); + logger.info('Router/index.js %O', routerFiles); } try { for (const routerPath of routerFiles) { diff --git a/app/router/root.route.js b/src/router/root.route.js similarity index 100% rename from app/router/root.route.js rename to src/router/root.route.js diff --git a/app/router/test.route.js b/src/router/test.route.js similarity index 100% rename from app/router/test.route.js rename to src/router/test.route.js diff --git a/app/router/user.route.js b/src/router/user.route.js similarity index 100% rename from app/router/user.route.js rename to src/router/user.route.js diff --git a/src/schedule/binance.schedule.js b/src/schedule/binance.schedule.js new file mode 100644 index 0000000..29a1735 --- /dev/null +++ b/src/schedule/binance.schedule.js @@ -0,0 +1,47 @@ +const { CronJob } = require('cron'); +const { getCandlesticks, calculateIndicators, matchIndicators } = require('../middleware/binance'); +const binance = require('../service/binance'); +const { getLogger } = require('../common/logger'); +const utils = require('../common/utils'); +const dayjs = require('dayjs'); +const { start } = require('repl'); +const log = getLogger('binance'); + +binance.use('spot/candlesticks', getCandlesticks, calculateIndicators, matchIndicators); + +let runner = utils.createConcurrent(5, () => utils.betweenMinMax(1, 3) * 1e2); +utils.waitFor( + async function () { + // Intervals: 1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,1M + const iter = [...binance.symbolMap.keys()]; + // const iter = ['BNBUSDT']; + let start = dayjs(); + log.info('symbol size %s', iter.length); + + await Promise.allSettled( + iter.map(symbol => + runner(async () => { + await binance.trigger('spot/candlesticks', { symbol, interval: '1d' }); + binance.usedWeight(); + }) + ) + ); + + log.info('calculate %s symbols %s', iter.length, utils.displayDuration(start)); + }, + () => 15 * 6e4 +); +// new CronJob( +// '15 * * * * *', // cronTime +// async function () { +// // Intervals: 1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,1M +// const iter = binance.symbolMap.keys(); +// log.info('symbol size %s',binance.symbolMap.size) +// for (const symbol of iter) { +// await binance.trigger('spot/candlesticks', { symbol, interval: '1d' }); +// await utils.delay +// } +// }, // onTick +// null, // onComplete +// true // start +// ); diff --git a/src/schedule/index.js b/src/schedule/index.js new file mode 100644 index 0000000..37c5f25 --- /dev/null +++ b/src/schedule/index.js @@ -0,0 +1,17 @@ +const { glob } = require('glob'); +const { logger } = require('../common/logger'); +const path = require('path'); +const { isProdEnv } = require('../common/constant'); + +const jobs = glob.sync('./**/*.schedule.js', { cwd: __dirname }); + +if (!isProdEnv) { + logger.info('schedule %s', jobs); +} +try { + for (const jobPath of jobs) { + require(path.resolve(__dirname, jobPath)); + } +} catch (err) { + logger.error('schedule/index.js %s', err.toString()); +} diff --git a/src/service/binance.js b/src/service/binance.js new file mode 100644 index 0000000..08a7742 --- /dev/null +++ b/src/service/binance.js @@ -0,0 +1,83 @@ +const Binance = require('node-binance-api'); +const CreateCompose = require('../common/useCompose'); +const { getLogger } = require('../common/logger'); +const log = getLogger('binance'); +const binance = new Binance().options({ + useServerTime: true, + reconnect: true, + verbose: true, + family: 4, + log: (...params) => log.debug(params), + APIKEY: process.env.BINANCE_APIKEY, + APISECRET: process.env.BINANCE_APISECRET, +}); + +class Service extends CreateCompose { + constructor() { + super(); + this.api = binance; + this.symbolMap = new Map(); + this.symbolFilters = new Map(); + this.rateLimits = []; + // this.exchangeFilters = [] + this.init(); + } + async init() { + // const res = await this.api.openOrders(false); + // log.info('Open orders %j', res); + this.api.websockets.prevDay(false, (error, res) => { + if (error) { + log.error('prevDay %s', error.toString()); + } + // {"eventType":"24hrTicker","eventTime":1720847862334,"symbol":"BNBETH","priceChange":"0.00200000","percentChange":"1.186","averagePrice":"0.17010335","prevClose":"0.16860000","close":"0.17070000","closeQty":"0.01400000","bestBid":"0.17060000","bestBidQty":"52.04300000","bestAsk":"0.17070000","bestAskQty":"2.69200000","open":"0.16870000","high":"0.17120000","low":"0.16840000","volume":"2632.09700000","quoteVolume":"447.72852340","openTime":1720761462334,"closeTime":1720847862334,"firstTradeId":60390397,"lastTradeId":60399160,"numTrades":8764} + this.symbolMap.set(res.symbol, res); + // log.info('spot symbols %s', list.length); + }); + this.api.exchangeInfo((error, data) => { + if (error) { + log.error('exchangeInfo %s', error.toString()); + } + // {rateLimitType: 'REQUEST_WEIGHT', interval: 'MINUTE', intervalNum: 1, limit: 6000} + this.rateLimits = data.rateLimits; + // this.exchangeFilters =data.exchangeFilters + for (let obj of data.symbols) { + let filters = { status: obj.status }; + for (let filter of obj.filters) { + if (filter.filterType == 'MIN_NOTIONAL') { + filters.minNotional = filter.minNotional; + } else if (filter.filterType == 'PRICE_FILTER') { + filters.minPrice = filter.minPrice; + filters.maxPrice = filter.maxPrice; + filters.tickSize = filter.tickSize; + } else if (filter.filterType == 'LOT_SIZE') { + filters.stepSize = filter.stepSize; + filters.minQty = filter.minQty; + filters.maxQty = filter.maxQty; + } + } + //filters.baseAssetPrecision = obj.baseAssetPrecision; + //filters.quoteAssetPrecision = obj.quoteAssetPrecision; + filters.orderTypes = obj.orderTypes; + filters.icebergAllowed = obj.icebergAllowed; + obj.status === 'TRADING' && this.symbolFilters.set(obj.symbol, filters); + } + log.info('exchangeInfo: %s', this.symbolFilters.size); + + // global.filters = minimums; + //fs.writeFile("minimums.json", JSON.stringify(minimums, null, 4), function(err){}); + }); + } + usedWeight() { + const binance = this.api; + const max = this.rateLimits.find(item => item.rateLimitType === 'REQUEST_WEIGHT')?.limit || 0; + const used = binance.usedWeight(); + if (used >= max || max - used <= 30) { + log.warn( + '%s', + `statusCode: ${binance.statusCode()} usedWeight:${binance.usedWeight()} / ${max} ${binance.lastURL()}` + ); + } + } +} + +module.exports = new Service(); diff --git a/src/service/mail.js b/src/service/mail.js new file mode 100644 index 0000000..e69de29 diff --git a/src/service/mongo.js b/src/service/mongo.js new file mode 100644 index 0000000..e69de29 diff --git a/tsconfig.json b/tsconfig.json index bfeacd3..6d1cff8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -108,5 +108,5 @@ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, - "include": ["app/**/*", "test", "custom.d.ts"] + "include": ["src/**/*", "test", "custom.d.ts"] }