From 15d4e06a0fe3e7e40806fe8330b8fad5984a4f54 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 17 Nov 2018 09:04:11 +0100 Subject: [PATCH 01/76] Email and Profile Config files now inside AACloud Folder Structure --- .gitignore | 3 +++ Run.js | 6 +++--- this.config.json | 10 +++++----- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 402b59b95..54bc08006 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ bin/* *.cache node_modules/* exchange/Auth0.js +Email-Config/Email.Config.json +Execution.Config.json +User-Profile/User.Profile.json diff --git a/Run.js b/Run.js index 937991c36..c0c86ad7c 100644 --- a/Run.js +++ b/Run.js @@ -49,7 +49,7 @@ function readStoragePermissions() { console.log( "[INFO] Run -> readStoragePermissions -> Entering function. "); let fs = require('fs'); - filePath = '../' + 'User-Profile' + '/' + 'User.Profile.json'; + filePath = './' + 'User-Profile' + '/' + 'User.Profile.json'; global.USER_PROFILE = JSON.parse(fs.readFileSync(filePath, 'utf8')); @@ -83,7 +83,7 @@ function readEmailConfiguration() { console.log( "Run : [INFO] readEmailConfiguration -> Entering function. "); let fs = require('fs'); - filePath = '../' + 'Email-Config' + '/' + 'Email.Config.json'; + filePath = './' + 'Email-Config' + '/' + 'Email.Config.json'; global.EMAIL_CONFIG = JSON.parse(fs.readFileSync(filePath, 'utf8')); readExecutionConfiguration(); @@ -98,7 +98,7 @@ function readExecutionConfiguration() { let filePath; try { let fs = require('fs'); - filePath = '../Execution-Config/Execution.Config.json'; + filePath = 'Execution.Config.json'; let executionProperties = JSON.parse(fs.readFileSync(filePath, 'utf8')); global.DEV_TEAM = executionProperties.devTeam; global.EXCHANGE_NAME = executionProperties.exchangeName; diff --git a/this.config.json b/this.config.json index 3a23977c8..d4a37b864 100644 --- a/this.config.json +++ b/this.config.json @@ -14,35 +14,35 @@ "repo": "AAMariam-Trading-Bot" }, { - "enabled": "true", + "enabled": "false", "devTeam": "AAMasters", "bot": "AACharly", "process": "Poloniex-Live-Trades", "repo": "AACharly-Extraction-Bot" }, { - "enabled": "true", + "enabled": "false", "devTeam": "AAMasters", "bot": "AACharly", "process": "Poloniex-Hole-Fixing", "repo": "AACharly-Extraction-Bot" }, { - "enabled": "true", + "enabled": "false", "devTeam": "AAMasters", "bot": "AABruce", "process": "One-Min-Daily-Candles-Volumes", "repo": "AABruce-Indicator-Bot" }, { - "enabled": "true", + "enabled": "false", "devTeam": "AAMasters", "bot": "AAOlivia", "process": "Multi-Period-Daily", "repo": "AAOlivia-Indicator-Bot" }, { - "enabled": "true", + "enabled": "false", "devTeam": "AAMasters", "bot": "AAOlivia", "process": "Multi-Period-Market", From 7dc099cbdf218a0baf4654b82ddfe9371fe0ad2e Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 17 Nov 2018 09:09:51 +0100 Subject: [PATCH 02/76] One folder for all configs --- .gitignore | 7 ++++--- Run.js | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 54bc08006..52053745f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ bin/* *.cache node_modules/* exchange/Auth0.js -Email-Config/Email.Config.json -Execution.Config.json -User-Profile/User.Profile.json +configs/Email.Config.json + +configs/User.Profile.json +configs/Execution.Config.json diff --git a/Run.js b/Run.js index c0c86ad7c..03e0ffdfc 100644 --- a/Run.js +++ b/Run.js @@ -49,7 +49,7 @@ function readStoragePermissions() { console.log( "[INFO] Run -> readStoragePermissions -> Entering function. "); let fs = require('fs'); - filePath = './' + 'User-Profile' + '/' + 'User.Profile.json'; + filePath = './' + 'configs' + '/' + 'User.Profile.json'; global.USER_PROFILE = JSON.parse(fs.readFileSync(filePath, 'utf8')); @@ -83,7 +83,7 @@ function readEmailConfiguration() { console.log( "Run : [INFO] readEmailConfiguration -> Entering function. "); let fs = require('fs'); - filePath = './' + 'Email-Config' + '/' + 'Email.Config.json'; + filePath = './' + 'configs' + '/' + 'Email.Config.json'; global.EMAIL_CONFIG = JSON.parse(fs.readFileSync(filePath, 'utf8')); readExecutionConfiguration(); @@ -98,7 +98,7 @@ function readExecutionConfiguration() { let filePath; try { let fs = require('fs'); - filePath = 'Execution.Config.json'; + filePath = './configs/Execution.Config.json'; let executionProperties = JSON.parse(fs.readFileSync(filePath, 'utf8')); global.DEV_TEAM = executionProperties.devTeam; global.EXCHANGE_NAME = executionProperties.exchangeName; From 0a406e7ad32f0f743417618e640ab47f866c479b Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 17 Nov 2018 09:23:55 +0100 Subject: [PATCH 03/76] Keys also read from the same config folder --- .gitignore | 1 + Run.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 52053745f..d9043d22a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ configs/Email.Config.json configs/User.Profile.json configs/Execution.Config.json +configs/Secret.Keys.json diff --git a/Run.js b/Run.js index 03e0ffdfc..56f3bfd7f 100644 --- a/Run.js +++ b/Run.js @@ -123,7 +123,7 @@ function readExchangeAPIKey() { console.log( "[INFO] Run -> readExchangeAPIKey -> Entering function. "); let fs = require('fs'); - let filePath = '../' + 'Exchange-Keys' + '/' + 'Secret.Keys' + '.json'; + let filePath = './configs/Secret.Keys' + '.json'; global.EXCHANGE_KEYS = JSON.parse(fs.readFileSync(filePath, 'utf8')); startRoot(); From 68e4a0011469a0c0908412deb3b29e6bc73590c6 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 17 Nov 2018 11:08:06 +0100 Subject: [PATCH 04/76] LOGGED IN USER taken from Execution Config File --- Run.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Run.js b/Run.js index 56f3bfd7f..3a49cb7fc 100644 --- a/Run.js +++ b/Run.js @@ -2,8 +2,6 @@ global.CURRENT_ENVIRONMENT = "Develop"; global.CURRENT_EXECUTION_AT = "Browser"; global.SHALL_BOT_STOP = false; -global.USER_LOGGED_IN = "Ciencias"; -global.DEV_TEAM = "AAMasters"; global.AT_BREAKPOINT = false; // This is used only when running at the browser. /* Default parameters can be changed by the execution configuration */ @@ -101,6 +99,7 @@ function readExecutionConfiguration() { filePath = './configs/Execution.Config.json'; let executionProperties = JSON.parse(fs.readFileSync(filePath, 'utf8')); global.DEV_TEAM = executionProperties.devTeam; + global.USER_LOGGED_IN = executionProperties.userName; global.EXCHANGE_NAME = executionProperties.exchangeName; global.MARKET = executionProperties.market; global.EXECUTION_CONFIG = { From f2e042e7a3d2c34888fcd643d754a04249d8299a Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 17 Nov 2018 11:35:57 +0100 Subject: [PATCH 05/76] By default it should run at the CLOUD --- Run.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Run.js b/Run.js index 3a49cb7fc..6b2399998 100644 --- a/Run.js +++ b/Run.js @@ -1,6 +1,6 @@  global.CURRENT_ENVIRONMENT = "Develop"; -global.CURRENT_EXECUTION_AT = "Browser"; +global.CURRENT_EXECUTION_AT = "Cloud"; global.SHALL_BOT_STOP = false; global.AT_BREAKPOINT = false; // This is used only when running at the browser. From 9725ec52db0469da81c6924a804b1f91610c3cc8 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 17 Nov 2018 16:14:42 +0100 Subject: [PATCH 06/76] Generate Dinamically Storage Permissions --- Project.njsproj | 1 + Run.js | 46 ++++++++++++++++++++++++------ StorageAccessManager.js | 63 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 9 deletions(-) create mode 100644 StorageAccessManager.js diff --git a/Project.njsproj b/Project.njsproj index 516525a6d..c6a345349 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -68,6 +68,7 @@ Code + Code diff --git a/Run.js b/Run.js index 6b2399998..f930cb063 100644 --- a/Run.js +++ b/Run.js @@ -50,22 +50,50 @@ function readStoragePermissions() { filePath = './' + 'configs' + '/' + 'User.Profile.json'; global.USER_PROFILE = JSON.parse(fs.readFileSync(filePath, 'utf8')); + /* Dinamically generating the azure storage permissions for the bot to run */ - /* Here we will rearrange the storage permissions array into a map, so that it can be easily consumed when needed. */ + const MAX_STORAGE_PERMISSION_DAYS = 10; + const STORAGE_ACCESS_MANAGER = require('./StorageAccessManager'); + storageAccessManager = STORAGE_ACCESS_MANAGER.newStorageAccessManager(); - let permissionsMap = new Map; + storageAccessManager.initialize(global.USER_PROFILE.connectionString, onInitialized); - for (i = 0; i < global.USER_PROFILE.storagePermissions.length; i++) { + function onInitialized() { - let permission = global.USER_PROFILE.storagePermissions[i]; + /* Here we will rearrange the storage permissions array into a map, so that it can be easily consumed when needed. */ - permissionsMap.set(permission[0], permission[1]); + let permissionsMap = new Map; + + let containers = ["AAPlatform", "AAVikings", global.USER_PROFILE.teamName] + let container; + let key; + let value; + + for (let i = 0; i < containers.length; i++) { + + container = containers[i]; + let readPermission = storageAccessManager.getPermission(container.toLowerCase(), "READ", MAX_STORAGE_PERMISSION_DAYS); + + key = container + ".READ"; + value = readPermission; + + permissionsMap.set(key, value); + + } + + let writePermission = storageAccessManager.getPermission(container.toLowerCase(), "WRITE", MAX_STORAGE_PERMISSION_DAYS); + + key = container + ".WRITE"; + value = writePermission; + + permissionsMap.set(key, value); + + global.USER_PROFILE.storagePermissions = permissionsMap; + global.USER_PROFILE.connectionString = ""; + + readEmailConfiguration(); } - - global.USER_PROFILE.storagePermissions = permissionsMap; - - readEmailConfiguration(); } catch (err) { console.log("[ERROR] Run -> readStoragePermissions -> err = " + err.message); diff --git a/StorageAccessManager.js b/StorageAccessManager.js new file mode 100644 index 000000000..ae4ad9a67 --- /dev/null +++ b/StorageAccessManager.js @@ -0,0 +1,63 @@ +exports.newStorageAccessManager = function newStorageAccessManager() { + + let thisObject = { + getPermission: getPermission, + initialize: initialize + } + + let connectionString; + + return thisObject; + + function initialize(pConnectionString, callBackFunction) { + + connectionString = pConnectionString; + + callBackFunction(); + } + + function getPermission(pContainer, pType, pDays) { + + let azure = require('azure-storage'); + let blobService = azure.createBlobService(connectionString); + + let startDate = new Date(); + startDate.setDate(startDate.getDate() - 1); + + let expiryDate = new Date(startDate); + expiryDate.setDate(startDate.getDate() + pDays); + + let azurePermissions; + + switch (pType) { + case "READ": { + azurePermissions = azure.BlobUtilities.SharedAccessPermissions.READ; + break; + } + case "WRITE": { + azurePermissions = azure.BlobUtilities.SharedAccessPermissions.WRITE; + break; + } + case "DELETE": { + azurePermissions = azure.BlobUtilities.SharedAccessPermissions.DELETE; + break; + } + } + + let blobName = undefined; + + let sharedAccessPolicy = { + AccessPolicy: { + Permissions: azurePermissions, + Start: startDate, + Expiry: expiryDate + } + }; + + let sasToken = blobService.generateSharedAccessSignature(pContainer, blobName, sharedAccessPolicy); + + return "BlobEndpoint=https://aadevelop.blob.core.windows.net;SharedAccessSignature=" + sasToken + ""; + + } +} + From 616f17f99040b959f764ec63e9d2820d7b64193b Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Sat, 17 Nov 2018 12:37:07 -0300 Subject: [PATCH 07/76] Removing secrets file and adding paramater for the execution config --- Run.js | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/Run.js b/Run.js index f930cb063..c2324344f 100644 --- a/Run.js +++ b/Run.js @@ -124,7 +124,13 @@ function readExecutionConfiguration() { let filePath; try { let fs = require('fs'); - filePath = './configs/Execution.Config.json'; + + let configDirectory = process.argv[2]; + if(configDirectory === undefined){ + console.log("[ERROR] Configuration file not passed as a command line argument."); + return; + } + filePath = configDirectory +'/Execution.Config.json'; let executionProperties = JSON.parse(fs.readFileSync(filePath, 'utf8')); global.DEV_TEAM = executionProperties.devTeam; global.USER_LOGGED_IN = executionProperties.userName; @@ -135,7 +141,7 @@ function readExecutionConfiguration() { startMode: executionProperties.startMode }; - readExchangeAPIKey(); + startRoot(); } catch (err) { console.log("[ERROR] readExecutionConfiguration -> err = " + err.message); @@ -143,33 +149,6 @@ function readExecutionConfiguration() { } } -//TODO Move this method inside ExchangeAPI -function readExchangeAPIKey() { - - try { - console.log( "[INFO] Run -> readExchangeAPIKey -> Entering function. "); - - let fs = require('fs'); - let filePath = './configs/Secret.Keys' + '.json'; - - global.EXCHANGE_KEYS = JSON.parse(fs.readFileSync(filePath, 'utf8')); - startRoot(); - } - catch (err) { - console.log("[ERROR] Run -> readExchangeAPIKey -> err = " + err.message); - console.log("[HINT] Run -> You need to have a file at this path -> " + filePath); - - global.EXCHANGE_KEYS = { - Poloniex: [{ - Key: "", - Secret: "" - }] - } - - startRoot(); - } -} - function startRoot() { console.log( "[INFO] Run -> startRoot -> Entering function. "); From 8310b6b6afdb120106ee2acbe30d7080eb276b40 Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Sat, 17 Nov 2018 12:58:34 -0300 Subject: [PATCH 08/76] Removing USER_LOGGED_IN since it's only used on Browser execution --- Run.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Run.js b/Run.js index c2324344f..fc86c4bcd 100644 --- a/Run.js +++ b/Run.js @@ -133,7 +133,6 @@ function readExecutionConfiguration() { filePath = configDirectory +'/Execution.Config.json'; let executionProperties = JSON.parse(fs.readFileSync(filePath, 'utf8')); global.DEV_TEAM = executionProperties.devTeam; - global.USER_LOGGED_IN = executionProperties.userName; global.EXCHANGE_NAME = executionProperties.exchangeName; global.MARKET = executionProperties.market; global.EXECUTION_CONFIG = { From 4fa295fc87c2c21fe920b860151c812423680309 Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Sat, 17 Nov 2018 13:14:39 -0300 Subject: [PATCH 09/76] Adding azure dependency --- package-lock.json | 117 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 +- 2 files changed, 119 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index e49ce5eda..8197cfa4b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -170,6 +170,31 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, + "azure-storage": { + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/azure-storage/-/azure-storage-2.10.2.tgz", + "integrity": "sha512-pOyGPya9+NDpAfm5YcFfklo57HfjDbYLXxs4lomPwvRxmb0Di/A+a+RkUmEFzaQ8S13CqxK40bRRB0sjj2ZQxA==", + "requires": { + "browserify-mime": "1.2.9", + "extend": "3.0.2", + "json-edm-parser": "0.1.2", + "md5.js": "1.3.4", + "readable-stream": "2.0.6", + "request": "2.88.0", + "underscore": "1.8.3", + "uuid": "3.3.2", + "validator": "9.4.1", + "xml2js": "0.2.8", + "xmlbuilder": "9.0.7" + }, + "dependencies": { + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + } + } + }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -179,6 +204,11 @@ "tweetnacl": "0.14.5" } }, + "browserify-mime": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/browserify-mime/-/browserify-mime-1.2.9.tgz", + "integrity": "sha1-rrGvKN5sDXpqLOQK22j/GEIq8x8=" + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -334,6 +364,15 @@ "har-schema": "2.0.0" } }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "requires": { + "inherits": "2.0.1", + "safe-buffer": "5.1.2" + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -367,6 +406,11 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, "isomorphic-fetch": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", @@ -392,6 +436,14 @@ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "optional": true }, + "json-edm-parser": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/json-edm-parser/-/json-edm-parser-0.1.2.tgz", + "integrity": "sha1-HmCw/vG8CvZ7wNFG393lSGzWFbQ=", + "requires": { + "jsonparse": "1.2.0" + } + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -407,6 +459,11 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, + "jsonparse": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.2.0.tgz", + "integrity": "sha1-XAxWhRBxYOcv50ib3eoLRMK8Z70=" + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -423,6 +480,15 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, + "md5.js": { + "version": "1.3.4", + "resolved": "http://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", + "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", + "requires": { + "hash-base": "3.0.4", + "inherits": "2.0.1" + } + }, "mime-db": { "version": "1.36.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", @@ -465,6 +531,11 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, "psl": { "version": "1.1.29", "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", @@ -485,6 +556,19 @@ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" }, + "readable-stream": { + "version": "2.0.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.1", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + } + }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -527,6 +611,11 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "sax": { + "version": "0.5.8", + "resolved": "http://registry.npmjs.org/sax/-/sax-0.5.8.tgz", + "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=" + }, "sshpk": { "version": "1.14.2", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", @@ -543,6 +632,11 @@ "tweetnacl": "0.14.5" } }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, "symbol-observable": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", @@ -584,11 +678,21 @@ "inherits": "2.0.1" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, + "validator": { + "version": "9.4.1", + "resolved": "http://registry.npmjs.org/validator/-/validator-9.4.1.tgz", + "integrity": "sha512-YV5KjzvRmSyJ1ee/Dm5UED0G+1L4GZnLN3w6/T+zZm8scVua4sOhYKWTUrKa0H/tMiJyO9QLHMPN+9mB/aMunA==" + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -604,6 +708,19 @@ "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" }, + "xml2js": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.2.8.tgz", + "integrity": "sha1-m4FpCTFjH/CdGVdUn69U9PmAs8I=", + "requires": { + "sax": "0.5.8" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + }, "zen-observable": { "version": "0.8.9", "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.9.tgz", diff --git a/package.json b/package.json index 16aaf5699..564db3a39 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "querystring": "^0.2.0", "request": "^2.88.0", "retry": "^0.12.0", - "underscore": "^1.9.1" + "underscore": "^1.9.1", + "azure-storage": "^2.8.2" } } From 4027f54f6257b743b2b3b8f47506121fe05e31f2 Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Sat, 17 Nov 2018 13:50:29 -0300 Subject: [PATCH 10/76] Changing execution order --- Run.js | 62 +++++++++++++++++++++++++++------------------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/Run.js b/Run.js index fc86c4bcd..980a4d657 100644 --- a/Run.js +++ b/Run.js @@ -34,13 +34,37 @@ process.on('exit', function (code) { } }); -global.USER_PROFILE = {}; -global.EMAIL_CONFIG = {}; +readExecutionConfiguration(); -readStoragePermissions(); +function readExecutionConfiguration() { + let filePath; + try { + let fs = require('fs'); + + let configDirectory = process.argv[2]; + if (configDirectory === undefined) { + console.log("[ERROR] Configuration file not passed as a command line argument."); + return; + } + filePath = configDirectory + '/Execution.Config.json'; + let executionProperties = JSON.parse(fs.readFileSync(filePath, 'utf8')); + global.DEV_TEAM = executionProperties.devTeam; + global.EXCHANGE_NAME = executionProperties.exchangeName; + global.MARKET = executionProperties.market; + global.EXECUTION_CONFIG = { + executionList: executionProperties.executionList, + startMode: executionProperties.startMode + }; + + readStoragePermissions(); + } + catch (err) { + console.log("[ERROR] readExecutionConfiguration -> err = " + err.message); + console.log("[HINT] You need to have a file at this path -> " + filePath); + } +} function readStoragePermissions() { - let filePath; try { @@ -112,7 +136,7 @@ function readEmailConfiguration() { filePath = './' + 'configs' + '/' + 'Email.Config.json'; global.EMAIL_CONFIG = JSON.parse(fs.readFileSync(filePath, 'utf8')); - readExecutionConfiguration(); + startRoot(); } catch (err) { console.log("[ERROR] Run -> readEmailConfiguration -> err = " + err.message); @@ -120,34 +144,6 @@ function readEmailConfiguration() { } } -function readExecutionConfiguration() { - let filePath; - try { - let fs = require('fs'); - - let configDirectory = process.argv[2]; - if(configDirectory === undefined){ - console.log("[ERROR] Configuration file not passed as a command line argument."); - return; - } - filePath = configDirectory +'/Execution.Config.json'; - let executionProperties = JSON.parse(fs.readFileSync(filePath, 'utf8')); - global.DEV_TEAM = executionProperties.devTeam; - global.EXCHANGE_NAME = executionProperties.exchangeName; - global.MARKET = executionProperties.market; - global.EXECUTION_CONFIG = { - executionList: executionProperties.executionList, - startMode: executionProperties.startMode - }; - - startRoot(); - } - catch (err) { - console.log("[ERROR] readExecutionConfiguration -> err = " + err.message); - console.log("[HINT] You need to have a file at this path -> " + filePath); - } -} - function startRoot() { console.log( "[INFO] Run -> startRoot -> Entering function. "); From ad567daba47221a720c65a6482f3a9dc256a71f0 Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Sat, 17 Nov 2018 13:52:09 -0300 Subject: [PATCH 11/76] Adding dev team name to default containers --- Run.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Run.js b/Run.js index 980a4d657..ba93a3e1f 100644 --- a/Run.js +++ b/Run.js @@ -88,7 +88,7 @@ function readStoragePermissions() { let permissionsMap = new Map; - let containers = ["AAPlatform", "AAVikings", global.USER_PROFILE.teamName] + let containers = ["AAPlatform", "AAVikings", global.DEV_TEAM] let container; let key; let value; From b8f655d1ba23125805c0cd986fa1a4ac6c22fe72 Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Sat, 17 Nov 2018 14:16:22 -0300 Subject: [PATCH 12/76] Adding AAMasters by default --- Run.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Run.js b/Run.js index ba93a3e1f..f21106276 100644 --- a/Run.js +++ b/Run.js @@ -88,7 +88,7 @@ function readStoragePermissions() { let permissionsMap = new Map; - let containers = ["AAPlatform", "AAVikings", global.DEV_TEAM] + let containers = ["AAPlatform", "AAMasters", "AAVikings", global.DEV_TEAM] let container; let key; let value; From f58a9f76a5b8d6286ba8532a444a968ea65044fe Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Thu, 13 Dec 2018 09:12:25 -0300 Subject: [PATCH 13/76] Adding env variables and fixing issues --- Assistant.js | 45 ++++-------------------------------- Root.js | 7 +++++- Run.js | 38 +++++++++++++++++------------- StorageAccessManager.js | 2 +- TradingBotProcessMainLoop.js | 2 +- exchange/ExchangeAPI.js | 5 ++-- package-lock.json | 5 ++++ package.json | 3 ++- 8 files changed, 45 insertions(+), 62 deletions(-) diff --git a/Assistant.js b/Assistant.js index 6f8b9b7f4..301130f36 100644 --- a/Assistant.js +++ b/Assistant.js @@ -918,10 +918,6 @@ try { if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> Entering function."); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pType = " + pType); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pRate = " + pRate); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pAmountA = " + pAmountA); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pAmountB = " + pAmountB); } /* Removing extra decimals. */ @@ -929,6 +925,11 @@ pAmountA = thisObject.truncDecimals(pAmountA); pAmountB = thisObject.truncDecimals(pAmountB); + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pType = " + pType); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pRate = " + pRate); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pAmountA = " + pAmountA); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pAmountB = " + pAmountB); } + /* Validations that the limits are not surpassed. */ if (pType === 'buy') { @@ -947,24 +948,6 @@ callBackFunction(err); return; } - - let aRate = thisObject.truncDecimals(pAmountA / pRate); - - if (aRate !== pAmountB) { - - logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> pAmountA / pRate !== pAmountB."); - logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> pAmountA = " + pAmountA); - logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> pAmountB = " + pAmountB); - logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> pRate = " + pRate); - - let err = { - result: global.DEFAULT_FAIL_RESPONSE.result, - message: 'pAmountB * pRate !== pAmountA' - }; - - callBackFunction(err); - return; - } } if (pType === 'sell') { @@ -983,24 +966,6 @@ callBackFunction(err); return; } - - let bRate = thisObject.truncDecimals(pAmountB * pRate); - - if (bRate !== pAmountA) { - - logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> pAmountB * pRate !== pAmountA."); - logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> pAmountA = " + pAmountA); - logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> pAmountB = " + pAmountB); - logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> pRate = " + pRate); - - let err = { - result: global.DEFAULT_FAIL_RESPONSE.result, - message: 'pAmountB * pRate !== pAmountA' - }; - - callBackFunction(err); - return; - } } /* All validations passed, we proceed. */ diff --git a/Root.js b/Root.js index 4c0f321dd..5fcf14cf8 100644 --- a/Root.js +++ b/Root.js @@ -529,8 +529,9 @@ exports.newRoot = function newRoot() { if (processConfig.startMode.live !== undefined) { if (processConfig.startMode.live.run === "true" && global.EXECUTION_CONFIG.startMode.live.run === "true") { - + botConfig.startMode = "Live"; + console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode); let month = pad((new Date()).getUTCMonth() + 1, 2); let year = (new Date()).getUTCFullYear(); @@ -558,6 +559,8 @@ exports.newRoot = function newRoot() { if (processConfig.startMode.backtest.run === "true" && global.EXECUTION_CONFIG.startMode.backtest.run === "true") { botConfig.startMode = "Backtest"; + console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode); + botConfig.backtest = processConfig.startMode.backtest; /* We override these waitTimes to the one specified at the backtest configuration. */ @@ -586,6 +589,8 @@ exports.newRoot = function newRoot() { if (processConfig.startMode.competition.run === "true" && global.EXECUTION_CONFIG.startMode.competition.run === "true") { botConfig.startMode = "Competition"; + console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode); + botConfig.competition = processConfig.startMode.competition; if (processConfig.startMode.competition.resumeExecution === "false" && global.EXECUTION_CONFIG.startMode.competition.resumeExecution === "false") { diff --git a/Run.js b/Run.js index f21106276..18b7b7cca 100644 --- a/Run.js +++ b/Run.js @@ -1,4 +1,4 @@ - +require('dotenv').config() global.CURRENT_ENVIRONMENT = "Develop"; global.CURRENT_EXECUTION_AT = "Cloud"; global.SHALL_BOT_STOP = false; @@ -37,30 +37,36 @@ process.on('exit', function (code) { readExecutionConfiguration(); function readExecutionConfiguration() { - let filePath; try { - let fs = require('fs'); + console.log("[INFO] Run -> readExecutionConfiguration -> Entering function. "); + + global.DEV_TEAM = process.env.DEV_TEAM; + + let executionList = [{ + enabled: "true", + devTeam: process.env.DEV_TEAM, + bot: process.env.BOT, + process: process.env.PROCESS + }] + + // TODO Improve this by changing Root.js + let mode = + '{ "run":"false",' + + '"resumeExecution":' + process.env.RESUME_EXECUTION + + '}' + let startMode = JSON.parse('{ "live": ' + mode +', "backtest": '+mode+', "competition": '+mode+'}') + startMode[process.env.START_MODE].run="true" - let configDirectory = process.argv[2]; - if (configDirectory === undefined) { - console.log("[ERROR] Configuration file not passed as a command line argument."); - return; - } - filePath = configDirectory + '/Execution.Config.json'; - let executionProperties = JSON.parse(fs.readFileSync(filePath, 'utf8')); - global.DEV_TEAM = executionProperties.devTeam; - global.EXCHANGE_NAME = executionProperties.exchangeName; - global.MARKET = executionProperties.market; global.EXECUTION_CONFIG = { - executionList: executionProperties.executionList, - startMode: executionProperties.startMode + executionList: executionList, + startMode: startMode }; readStoragePermissions(); } catch (err) { console.log("[ERROR] readExecutionConfiguration -> err = " + err.message); - console.log("[HINT] You need to have a file at this path -> " + filePath); + console.log("[ERROR] readExecutionConfiguration -> err = " + err.stack); } } diff --git a/StorageAccessManager.js b/StorageAccessManager.js index ae4ad9a67..ed6794ced 100644 --- a/StorageAccessManager.js +++ b/StorageAccessManager.js @@ -57,7 +57,7 @@ let sasToken = blobService.generateSharedAccessSignature(pContainer, blobName, sharedAccessPolicy); return "BlobEndpoint=https://aadevelop.blob.core.windows.net;SharedAccessSignature=" + sasToken + ""; - + //return "BlobEndpoint=https://aaproduction.blob.core.windows.net;SharedAccessSignature=" + sasToken + ""; } } diff --git a/TradingBotProcessMainLoop.js b/TradingBotProcessMainLoop.js index 21b9845bf..877150c6b 100644 --- a/TradingBotProcessMainLoop.js +++ b/TradingBotProcessMainLoop.js @@ -176,7 +176,7 @@ /* We define here all the modules that the rest of the infraestructure, including the bots themselves can consume. */ const UTILITIES = require(ROOT_DIR + 'CloudUtilities'); - const EXCHANGE_API = require(ROOT_DIR + 'Exchange/ExchangeAPI'); + const EXCHANGE_API = require(ROOT_DIR + 'exchange/ExchangeAPI'); const CONTEXT = require(ROOT_DIR + 'Context'); const ASSISTANT = require(ROOT_DIR + 'Assistant'); const STATUS_REPORT = require(ROOT_DIR + 'StatusReport'); diff --git a/exchange/ExchangeAPI.js b/exchange/ExchangeAPI.js index 0d56607fe..0c1559768 100644 --- a/exchange/ExchangeAPI.js +++ b/exchange/ExchangeAPI.js @@ -37,7 +37,7 @@ // TODO integrate with financial beings module to get the exchange let botExchange = 'Poloniex'; let exchange = botExchange.toLowerCase() + 'Client.js'; - let api = require('./Wrappers/' + exchange); + let api = require('./wrappers/' + exchange); request(authOptions, onTokenResponse); @@ -67,7 +67,8 @@ if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createKeyVaultAPIClient -> Entering function."); } const keyVaultAPI = graphqlClient({ - url: 'https://app-api.advancedalgos.net/graphql', + //url: 'https://platform-api.advancedalgos.net/graphql', + url: 'https://platform-dev-api.advancedalgos.net/graphql', headers: { Authorization: 'Bearer ' + authToken } diff --git a/package-lock.json b/package-lock.json index 8197cfa4b..ef0cf5a63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -245,6 +245,11 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "dotenv": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", + "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==" + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", diff --git a/package.json b/package.json index 564db3a39..a91b814fd 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "request": "^2.88.0", "retry": "^0.12.0", "underscore": "^1.9.1", - "azure-storage": "^2.8.2" + "azure-storage": "^2.8.2", + "dotenv": "^6.0.0" } } From 1595650362101eabadef0fbd944bbf5cbdf5e1b8 Mon Sep 17 00:00:00 2001 From: Julian Molina Date: Tue, 15 Jan 2019 13:55:17 +0100 Subject: [PATCH 14/76] Legal wording --- CODE_OF_CONDUCT.md | 2 +- CONTRIBUTING.md | 34 +++++++++++++++++----------------- LICENSE | 31 ++++++++++++++----------------- 3 files changed, 32 insertions(+), 35 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index c71b685b4..4b37b0e16 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at feedback at advancedalgos dot org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team using the online form in the contacts page of the superalgos.org website. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 311653120..c67e8d115 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,44 +2,44 @@ We are thrilled you are interested in contributing to this repository. Your help may be essential to the project's success and we want you in! -Advanced Algos LTD is a startup, currently at a very early stage. Although this repository is not open source software yet, we do welcome contributions from the community. +Superalgos is a collective project, currently at a very early stage. Although this repository is not open source software yet, we do welcome contributions from the community. -Contributions are deemed _voluntary work_. There might be incentives in place for certain kinds of contributions. Contact us for more information in this regards. +Contributions are deemed _voluntary work_. There might be incentives in place for certain kinds of contributions. Contact us for more information in this regard. In any case, contributors agree to provide an express grant of patent rights for their contributions. Submitting Pull Requests to this repository represents an express agreement with the terms of our Balanced Contributor Intellectual Property Agreement. This agreement is a direct implementation of GitHub's [Balanced Employee Intellectual Property Agreement 1.0.1](https://github.com/github/balanced-employee-ip-agreement/blob/master/Balanced_Employee_IP_Agreement.md). # Balanced Contributor Intellectual Property Agreement 1.0.1 -This BALANCED CONTRIBUTOR INTELLECTUAL PROPERTY AGREEMENT is between person or team submitting Pull Requests to this repository and Advanced Algos LTD ("Company"). +This BALANCED CONTRIBUTOR INTELLECTUAL PROPERTY AGREEMENT is between person or team submitting Pull Requests to this repository and Superalgos.org ("Project"). -**What is this?** This is the Company's Intellectual Property Agreement ("Agreement"). If you've worked in the technology space before, there's a good chance that you've run across one or more of these in the past. This document is the official, entire and exclusive agreement on what intellectual property ("IP") is yours, and what belongs to the Company. +**What is this?** This is the Project's Intellectual Property Agreement ("Agreement"). If you've worked in the technology space before, there's a good chance that you've run across one or more of these in the past. This document is the official, entire and exclusive agreement on what intellectual property ("IP") is yours, and what belongs to the Project. -**Why is this?** The Company needs to be clear on what IP it owns and has rights to. Its customers, contributors, and investors depend on the Company having the legal rights to the products and services it is providing so that the Company can continue operating and doing business. +**Why is this?** The Project needs to be clear on what IP it owns and has rights to. Its customers, contributors, and investors depend on the Project having the legal rights to the products and services it is providing so that the Project can continue operating and doing business. -The Company also believes that it's important to be clear on what it doesn't own. The Company doesn't want you looking over your shoulder every time you work on something personal or worrying that the Company will someday seize your open source non-lethal mousetrap simulation software. In other words, the Company isn't interested in appropriating your personal projects. +The Project also believes that it's important to be clear on what it doesn't own. The Project doesn't want you looking over your shoulder every time you work on something personal or worrying that the Project will someday seize your open source non-lethal mousetrap simulation software. In other words, the Project isn't interested in appropriating your personal projects. -**Read this.** Please read this document and be sure you understand it before you submit any Pull Requests. Due to legal risk and corporate obligations, the Company cannot, by and large, negotiate its terms. If you feel you have a particular circumstance that keeps you from signing, please let the Company's legal department ("Legal") know. And, of course, you're always free and encouraged to get your own legal counsel to explain anything you're not clear on. +**Read this.** Please read this document and be sure you understand it before you submit any Pull Requests. Due to legal risk and corporate obligations, the Project cannot, by and large, negotiate its terms. If you feel you have a particular circumstance that keeps you from signing, please let the Project's legal department ("Legal") know. And, of course, you're always free and encouraged to get your own legal counsel to explain anything you're not clear on. Cool? Then, by submitting your first Pull Request, and as a condition of your contribution, you agree to the following: -1. **What the Company owns.** The Company owns any IP ("Company IP") that you create, or help create _as its contributor_, but only if it meets one or more of these additional conditions: The IP was (i) related to an existing or prospective Company product or service at the time you developed, invented, or created it, (ii) developed for use by the Company, or (iii) developed or promoted with existing Company IP or with the Company's endorsement. You hereby grant and assign, and will grant and assign, to the Company all rights and interests in all Company IP. +1. **What the Project owns.** The Project owns any IP ("Project IP") that you create, or help create _as its contributor_, but only if it meets one or more of these additional conditions: The IP was (i) related to an existing or prospective Project product or service at the time you developed, invented, or created it, (ii) developed for use by the Project, or (iii) developed or promoted with existing Project IP or with the Project's endorsement. You hereby grant and assign, and will grant and assign, to the Project all rights and interests in all Project IP. - "Company IP" includes concepts, designs, developments, discoveries, ideas, improvements, inventions, trade secrets, trademarks, and works of authorship. + "Project IP" includes concepts, designs, developments, discoveries, ideas, improvements, inventions, trade secrets, trademarks, and works of authorship. -2. **What the Company doesn't own.** If you create IP that doesn't fit into one of the categories listed above, the Company doesn't own it. In other words, the Company doesn't own concepts, designs, developments, discoveries, ideas, improvements, inventions, trade secrets, trademarks, or works of authorship that you develop, invent, or create that do not meet any of the conditions in Section 1. +2. **What the Project doesn't own.** If you create IP that doesn't fit into one of the categories listed above, the Project doesn't own it. In other words, the Project doesn't own concepts, designs, developments, discoveries, ideas, improvements, inventions, trade secrets, trademarks, or works of authorship that you develop, invent, or create that do not meet any of the conditions in Section 1. -3. **Contribution of your IP to Company projects.** If you include your own IP – such as IP you created prior to working for the Company – into a Company product or service, it's still yours, of course, but you grant the Company a non-exclusive, irrevocable, fully paid-up, royalty-free, perpetual, sublicensable, transferable, worldwide license to use it without restriction in any way or implementation, in modified form, or as is, by itself, or incorporated into another product or service ("License"). If you include your name in any project over which the Company would have rights under this Agreement, such as in a copyright notice or a comment in code or documentation, then the License covers the rights associated with that use of your name as well. +3. **Contribution of your IP to Project projects.** If you include your own IP – such as IP you created prior to working for the Project – into a Project product or service, it's still yours, of course, but you grant the Project a non-exclusive, irrevocable, fully paid-up, royalty-free, perpetual, sublicensable, transferable, worldwide license to use it without restriction in any way or implementation, in modified form, or as is, by itself, or incorporated into another product or service ("License"). If you include your name in any project over which the Project would have rights under this Agreement, such as in a copyright notice or a comment in code or documentation, then the License covers the rights associated with that use of your name as well. -4. **Your contributions to non-Company projects.** The Company recognizes that you may be engaged in work that requires you to submit IP to entities other than the Company, such as open source projects used by the Company. Please make sure that Legal is aware of what you're working on so that Legal can help with any licensing issues. If any project asks you to sign a contribution agreement, you should check with Legal before doing so. These agreements may be legally binding on the Company and so should be run through Legal first. +4. **Your contributions to non-Project projects.** The Project recognizes that you may be engaged in work that requires you to submit IP to entities other than the Project, such as open source projects used by the Project. Please make sure that Legal is aware of what you're working on so that Legal can help with any licensing issues. If any project asks you to sign a contribution agreement, you should check with Legal before doing so. These agreements may be legally binding on the Project and so should be run through Legal first. -5. **Voluntary Works** All Company IP that you are involved with or create as part of your work for the Company is voluntary work which does not require compensation. There might be incentives in place for certain kinds of contributions. Feel free to contact the Company to learn more. +5. **Voluntary Works** All Project IP that you are involved with or create as part of your work for the Project is voluntary work which does not require compensation. There might be incentives in place for certain kinds of contributions. Feel free to contact the Project to learn more. 6. **No conflicts.** You agree that you don't have any outstanding agreements or obligations that conflict with those in this Agreement, and that you won't enter into conflicting agreements in the future. -7. **IP protection.** The Company might someday need to show the work that went into the development of IP that it uses or has used, or to make government filings to establish that it owns the IP or has rights over it. To help in those situations, you agree not to destroy any records you maintain relating to the development of any Company IP or IP under License (together, "All IP"), and, if the Company asks, to provide those records to the Company. You agree to help the Company secure and defend its rights in All IP. For your help the Company will compensate you at a reasonable rate. If the Company is unable to secure your help, you authorize the Company to act on your behalf (as your agent and attorney-in-fact) in securing all rights related to All IP. +7. **IP protection.** The Project might someday need to show the work that went into the development of IP that it uses or has used, or to make government filings to establish that it owns the IP or has rights over it. To help in those situations, you agree not to destroy any records you maintain relating to the development of any Project IP or IP under License (together, "All IP"), and, if the Project asks, to provide those records to the Project. You agree to help the Project secure and defend its rights in All IP. For your help the Project will compensate you at a reasonable rate. If the Project is unable to secure your help, you authorize the Project to act on your behalf (as your agent and attorney-in-fact) in securing all rights related to All IP. -8. **Confidentiality.** As an contributor or contractor of the Company, you will have access to sensitive confidential information that is important to the Company's business. You are responsible for keeping this information confidential, including after you end your work for the Company. +8. **Confidentiality.** As an contributor or contractor of the Project, you will have access to sensitive confidential information that is important to the Project's business. You are responsible for keeping this information confidential, including after you end your work for the Project. - "Confidential Information" includes non-public technical details about our products or services, financial information, business strategies and forecasts, customer data, or any other information, data or know-how that is valuable to the Company because it is not publicly known. + "Confidential Information" includes non-public technical details about our products or services, financial information, business strategies and forecasts, customer data, or any other information, data or know-how that is valuable to the Project because it is not publicly known. - The Company's Confidential Information is sensitive and we expect that you'll treat it as such. You agree to only use the Company's Confidential Information for the purpose of performing your contribution and for the benefit of the Company. You will do your best to keep Confidential Information secret. If you are not sure if something is Confidential Information, you should assume that it is, until you can confirm otherwise. \ No newline at end of file + The Project's Confidential Information is sensitive and we expect that you'll treat it as such. You agree to only use the Project's Confidential Information for the purpose of performing your contribution and for the benefit of the Project. You will do your best to keep Confidential Information secret. If you are not sure if something is Confidential Information, you should assume that it is, until you can confirm otherwise. \ No newline at end of file diff --git a/LICENSE b/LICENSE index c049df9cb..2fe09f449 100644 --- a/LICENSE +++ b/LICENSE @@ -1,23 +1,22 @@ COPYRIGHT NOTICE -© Copyright 2018 Advanced Algos LTD. +© Copyright 2018 Superalgos.org LICENSE NOTICE -Advanced Algos LTD. is a startup, currently at a very early stage. Because certain aspects of -the business are still not clearly defined, we have chosen to --temporarily-- grant a -restrictive license for the use of this repository, until those business aspects are clarified -and a proper open source license can be granted. +Superalgos is a collaborative project currently at a very early stage. Because certain aspects of +the project are still not clearly defined, we have chosen to --temporarily-- grant a restrictive +license for the use of this repository, until those aspects are clarified and a proper open source +license can be granted. -Advanced Algos LTD. is publishing the code of this software for several reasons. However, -it shall not be considered free software yet. Advanced Algos LTD. is a for-profit company -in the crypto space and this module is still proprietary software. +Superalgos.org is publishing the code of this software for several reasons. However, it shall not be considered free software yet. Superalgos is a collaborative project in the crypto space and this +software is still proprietary software. -The reasons for opening up the code of this module at this stage are the following: +The reasons for opening up the code of this software at this stage are the following: - * We believe that transparency is paramount to achieving our goals, so we want everyone - to be able to understand what this module does and how. Opening up the code of this module + * We believe that transparency is paramount to achieving our goals, so we want everyone to + be able to understand what this software does and how. Opening up the code of this software allows anyone to take a close look. * We welcome contributions from the community. Contributions are regarded as voluntary work. @@ -27,16 +26,14 @@ The reasons for opening up the code of this module at this stage are the followi LICENSE WORDING -Advanced Algos LTD. grants a limited license for the following uses: +Superalgos.org grants a limited license for the following uses: 1. CODE REVIEW AND AUDITS. You are granted permission to clone this repository to analyze, review or audit the code. -2. COLLABORATING WITH ADVANCED ALGOS LTD. You are granted permission to fork this repository +2. COLLABORATING WITH Superalgos.org. You are granted permission to fork this repository with the sole purpose of correcting bugs and developing functionality in agreement with - Advanced Algos LTD. By contributing to this repository you explicitely agree to the terms + Superalgos.org. By contributing to this repository you explicitely agree to the terms detailed in CONTRIBUTING.MD. -PLEASE SEE CONTRIBUTING.MD FOR MORE DETAILS ON THE IMPLICATIONS SURROUNDING YOUR CONTRIBUTIONS TO THIS REPOSITORY. - - +PLEASE SEE CONTRIBUTING.MD FOR MORE DETAILS ON THE IMPLICATIONS SURROUNDING YOUR CONTRIBUTIONS TO THIS REPOSITORY. \ No newline at end of file From 6135d516db363f6c84053d59ae805d4687fdcbc5 Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Mon, 28 Jan 2019 11:36:48 -0300 Subject: [PATCH 15/76] Container support Changes required to accepts parameters and run the bots on the virtual machine. --- .gitignore | 1 + Assistant.js | 4 +- Context.js | 1 - ExtractionBotProcessMainLoop.js | 12 +- IndicatorBotProcessMainLoop.js | 12 +- Integrations/OperationsModuleIntegration.js | 59 +++ Project.njsproj | 13 + Root.js | 28 +- Run.js | 42 +- StorageAccessManager.js | 3 +- TradingBotProcessMainLoop.js | 25 +- exchange/ExchangeAPI.js | 38 +- package-lock.json | 508 +++++++++++++++----- package.json | 8 +- utils/auth.js | 25 + utils/logger.js | 40 ++ 16 files changed, 637 insertions(+), 182 deletions(-) create mode 100644 Integrations/OperationsModuleIntegration.js create mode 100644 utils/auth.js create mode 100644 utils/logger.js diff --git a/.gitignore b/.gitignore index d9043d22a..7ab8c3a90 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ configs/Email.Config.json configs/User.Profile.json configs/Execution.Config.json configs/Secret.Keys.json +.env diff --git a/Assistant.js b/Assistant.js index 301130f36..232e61610 100644 --- a/Assistant.js +++ b/Assistant.js @@ -982,8 +982,8 @@ if (pRate !== marketRate) { - logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> putPosition Rate can not be different to marketRate while in Backtesting Mode. "); - onResponse(global.DEFAULT_FAIL_RESPONSE, positionId); + logger.write(MODULE_NAME, "[WARNING] putPosition -> Input Validations -> putPosition Rate can is different to marketRate while in Backtesting Mode. "); + //onResponse(global.DEFAULT_FAIL_RESPONSE, positionId); } let positionId = Math.trunc(Math.random(1) * 1000000); diff --git a/Context.js b/Context.js index c834d8d1a..df5cd196f 100644 --- a/Context.js +++ b/Context.js @@ -169,7 +169,6 @@ } catch (err) { logger.write(MODULE_NAME, "[ERROR] initialize -> getStatusReport -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] initialize -> getStatusReport -> key = " + key); callBack(global.DEFAULT_FAIL_RESPONSE); } } diff --git a/ExtractionBotProcessMainLoop.js b/ExtractionBotProcessMainLoop.js index 235f07587..9802d27c4 100644 --- a/ExtractionBotProcessMainLoop.js +++ b/ExtractionBotProcessMainLoop.js @@ -50,7 +50,11 @@ switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy. case "Cloud": { - filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud. + if (global.RUN_AS_TEAM) { + filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud. + } else { + filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser. + } break; } case "Browser": { @@ -154,8 +158,6 @@ return str.length < max ? pad(" " + str, max) : str; } - console.log(new Date().toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(pMonth, 2) + "/" + pad(pYear, 4) + " Entered into Main Loop # " + pad(Number(bot.loopCounter) + 1, 8)); - /* For each loop we want to create a new log file. */ logger = DEBUG_MODULE.newDebugLog(); @@ -178,6 +180,10 @@ bot.processDatetime = new Date(); // This will be considered the process date and time, so as to have it consistenly all over the execution. + /* High level log entry */ + + console.log(processDatetime.toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(pMonth, 2) + "/" + pad(pYear, 4) + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8)); + /* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */ let userBot; diff --git a/IndicatorBotProcessMainLoop.js b/IndicatorBotProcessMainLoop.js index 9cd328bf9..8248487dd 100644 --- a/IndicatorBotProcessMainLoop.js +++ b/IndicatorBotProcessMainLoop.js @@ -50,7 +50,11 @@ switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy. case "Cloud": { - filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud. + if (global.RUN_AS_TEAM) { + filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud. + } else { + filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser. + } break; } case "Browser": { @@ -155,8 +159,6 @@ return str.length < max ? pad(" " + str, max) : str; } - console.log(new Date().toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(pMonth, 2) + "/" + pad(pYear, 4) + " Entered into Main Loop # " + pad(Number(bot.loopCounter) + 1, 8 )); - /* For each loop we want to create a new log file. */ logger = DEBUG_MODULE.newDebugLog(); @@ -178,6 +180,10 @@ bot.processDatetime = new Date(); // This will be considered the process date and time, so as to have it consistenly all over the execution. + /* High level log entry */ + + console.log(bot.processDatetime.toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(pMonth, 2) + "/" + pad(pYear, 4) + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8)); + /* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */ let userBot; diff --git a/Integrations/OperationsModuleIntegration.js b/Integrations/OperationsModuleIntegration.js new file mode 100644 index 000000000..41c4642c7 --- /dev/null +++ b/Integrations/OperationsModuleIntegration.js @@ -0,0 +1,59 @@ +const axios = require('axios') +const appRoot = require('app-root-path') +const { logger } = require(`${appRoot}/utils/logger`) +const auth = require(`${appRoot}/utils/auth`) + +exports.updateExecutionResults = async function (summaryDate, buyAverage, sellAverage, + marketRate, combinedProfitsA, combinedProfitsB) { + + logger.debug('updateExecutionResults -> Entering Function.') + + try { + + const authResponse = await auth.authenticate() + + const operationsResponse = await axios({ + url: process.env.GATEWAY_ENDPOINT, + method: 'post', + data: { + query: ` + mutation($id: ID!, $summaryDate: Int!, $buyAverage: Float!, $sellAverage: Float!, + $marketRate: Float!, $combinedProfitsA: Float!, $combinedProfitsB: Float!, + $assetA: String!, $assetB: String!){ + operations_UpdateExecutionSummary( + id: $id, + summaryDate: $summaryDate, + buyAverage: $buyAverage, + sellAverage: $sellAverage, + marketRate: $marketRate, + combinedProfitsA: $combinedProfitsA, + combinedProfitsB: $combinedProfitsB, + assetA: $assetA, + assetB: $assetB + ) + } + `, + variables: { + id: process.env.CLONE_ID, + summaryDate: summaryDate, + buyAverage: buyAverage, + sellAverage: sellAverage, + marketRate: marketRate, + combinedProfitsA: combinedProfitsA, + combinedProfitsB: combinedProfitsB, + assetA: global.MARKET.assetA, + assetB: global.MARKET.assetB + }, + }, + headers: { + authorization: 'Bearer ' + authResponse.data.access_token + } + }) + + logger.debug('updateExecutionResults -> Operations Module Response: %s', operationsResponse.data.data.operations_UpdateExecutionSummary) + + } catch (error) { + logger.error('updateExecutionResults -> Error: ' + error.stack) + throw new Error('There has been an error updating the execution report: ' + error) + } +} \ No newline at end of file diff --git a/Project.njsproj b/Project.njsproj index c6a345349..c8f20791c 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -33,6 +33,12 @@ Code + + Code + + + Code + Code @@ -45,6 +51,9 @@ + + Code + Code @@ -76,13 +85,17 @@ + + + + diff --git a/Root.js b/Root.js index 5fcf14cf8..92ac034fc 100644 --- a/Root.js +++ b/Root.js @@ -1,4 +1,5 @@ - +const appRoot = require('app-root-path') +const operationsIntegration = require(`${appRoot}/Integrations/OperationsModuleIntegration`) exports.newRoot = function newRoot() { @@ -218,14 +219,13 @@ exports.newRoot = function newRoot() { Here we check that the local configuration for the execution exist, if it doesn't exist we will take the one on the server. */ - let executionListItem; if (global.EXECUTION_CONFIG === undefined) { - executionListItem = listItem; + listItem = PLATFORM_CONFIG.executionList[p]; } else { - executionListItem = global.EXECUTION_CONFIG.executionList[p]; + listItem = global.EXECUTION_CONFIG.executionList[p]; } - if (listItem.enabled !== "true" || executionListItem.enabled !== "true") { + if (listItem.enabled !== "true") { console.log(logDisplace + "Root : [INFO] start -> Skipping process for being disabled."); console.log(logDisplace + "Root : [INFO] start -> listItem.process = " + listItem.process); @@ -344,7 +344,7 @@ exports.newRoot = function newRoot() { if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> listItem.process = " + listItem.process); } let processConfig = botConfig.processes[i]; - + processConfig.startMode = global.EXECUTION_CONFIG.startMode // Override file storage configuration try { /* @@ -888,7 +888,7 @@ exports.newRoot = function newRoot() { tradingBotMainLoop.run(pGenes, pTotalInstances, whenRunFinishes); - function whenRunFinishes(err) { + function whenRunFinishes(err, context) { pBotConfig.loopCounter = 0; @@ -914,6 +914,20 @@ exports.newRoot = function newRoot() { console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot execution finished with errors. Please check the logs."); logger.persist(); } + + // Update operations module with latest context + if (context !== undefined) { + let lastExecution = context.executionHistory[context.executionHistory.length - 1] + let date = lastExecution[0] / 1000 | 0 + let buyAvgRate = lastExecution[1] + let sellAvgRate = lastExecution[2] + let marketRate = lastExecution[7] + let combinedProfitsA = lastExecution[13] + let combinedProfitsB = lastExecution[14] + + operationsIntegration.updateExecutionResults(date, buyAvgRate, sellAvgRate, + marketRate, combinedProfitsA, combinedProfitsB) + } } } else { diff --git a/Run.js b/Run.js index 18b7b7cca..747440525 100644 --- a/Run.js +++ b/Run.js @@ -1,8 +1,10 @@ require('dotenv').config() -global.CURRENT_ENVIRONMENT = "Develop"; -global.CURRENT_EXECUTION_AT = "Cloud"; + +global.CURRENT_ENVIRONMENT = "Develop"; +global.CURRENT_EXECUTION_AT = "Cloud"; global.SHALL_BOT_STOP = false; global.AT_BREAKPOINT = false; // This is used only when running at the browser. +global.RUN_AS_TEAM = false; /* Default parameters can be changed by the execution configuration */ global.EXCHANGE_NAME = "Poloniex"; @@ -13,6 +15,7 @@ global.MARKET = { process.on('uncaughtException', function (err) { console.log('[INFO] Run -> uncaughtException -> err.message = ' + err.message); + console.log('[INFO] Run -> uncaughtException -> err.stack = ', err.stack); return; }); @@ -40,22 +43,31 @@ function readExecutionConfiguration() { try { console.log("[INFO] Run -> readExecutionConfiguration -> Entering function. "); + global.CURRENT_ENVIRONMENT = process.env.PLATFORM_ENVIRONMENT global.DEV_TEAM = process.env.DEV_TEAM; + global.RUN_AS_TEAM = (process.env.RUN_AS_TEAM === "true"); + global.GATEWAY_ENDPOINT = process.env.GATEWAY_ENDPOINT; + global.STORAGE_URL = process.env.STORAGE_URL; + global.USER_LOGGED_IN = process.env.USER_LOGGED_IN; + global.CURRENT_BOT_REPO = process.env.BOT + "-" + process.env.TYPE + "-Bot"; let executionList = [{ - enabled: "true", - devTeam: process.env.DEV_TEAM, - bot: process.env.BOT, - process: process.env.PROCESS + enabled: "true", + devTeam: process.env.DEV_TEAM, + bot: process.env.BOT, + process: process.env.PROCESS, + repo: global.CURRENT_BOT_REPO }] - // TODO Improve this by changing Root.js let mode = - '{ "run":"false",' + - '"resumeExecution":' + process.env.RESUME_EXECUTION + + '{ "run": "false",' + + '"resumeExecution": "' + process.env.RESUME_EXECUTION + '",' + + '"beginDatetime": "' + process.env.BEGIN_DATE_TIME + '",' + + '"endDatetime": "' + process.env.END_DATE_TIME + '",' + + '"waitTime": "' + process.env.WAIT_TIME + '"' + '}' let startMode = JSON.parse('{ "live": ' + mode +', "backtest": '+mode+', "competition": '+mode+'}') - startMode[process.env.START_MODE].run="true" + startMode[process.env.START_MODE].run = "true" global.EXECUTION_CONFIG = { executionList: executionList, @@ -64,6 +76,7 @@ function readExecutionConfiguration() { readStoragePermissions(); } + catch (err) { console.log("[ERROR] readExecutionConfiguration -> err = " + err.message); console.log("[ERROR] readExecutionConfiguration -> err = " + err.stack); @@ -76,17 +89,14 @@ function readStoragePermissions() { try { console.log( "[INFO] Run -> readStoragePermissions -> Entering function. "); - let fs = require('fs'); - filePath = './' + 'configs' + '/' + 'User.Profile.json'; - global.USER_PROFILE = JSON.parse(fs.readFileSync(filePath, 'utf8')); - /* Dinamically generating the azure storage permissions for the bot to run */ - + global.STORAGE_BASE_URL = process.env.STORAGE_BASE_URL + global.USER_PROFILE = {} const MAX_STORAGE_PERMISSION_DAYS = 10; const STORAGE_ACCESS_MANAGER = require('./StorageAccessManager'); storageAccessManager = STORAGE_ACCESS_MANAGER.newStorageAccessManager(); - storageAccessManager.initialize(global.USER_PROFILE.connectionString, onInitialized); + storageAccessManager.initialize(process.env.STORAGE_CONNECTION_STRING, onInitialized); function onInitialized() { diff --git a/StorageAccessManager.js b/StorageAccessManager.js index ed6794ced..9a36d9d25 100644 --- a/StorageAccessManager.js +++ b/StorageAccessManager.js @@ -56,8 +56,7 @@ let sasToken = blobService.generateSharedAccessSignature(pContainer, blobName, sharedAccessPolicy); - return "BlobEndpoint=https://aadevelop.blob.core.windows.net;SharedAccessSignature=" + sasToken + ""; - //return "BlobEndpoint=https://aaproduction.blob.core.windows.net;SharedAccessSignature=" + sasToken + ""; + return "BlobEndpoint=" + global.STORAGE_BASE_URL + ";SharedAccessSignature=" + sasToken + ""; } } diff --git a/TradingBotProcessMainLoop.js b/TradingBotProcessMainLoop.js index 877150c6b..3c39c5660 100644 --- a/TradingBotProcessMainLoop.js +++ b/TradingBotProcessMainLoop.js @@ -52,7 +52,12 @@ switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy. case "Cloud": { - filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud. + if (global.RUN_AS_TEAM) { + filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud. + } else { + filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser. + } + break; } case "Browser": { @@ -134,6 +139,8 @@ function run(pGenes, pTotalAlgobots, callBackFunction) { + let context; + try { if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[INFO] run -> Entering function."); } @@ -160,8 +167,6 @@ return str.length < max ? pad(" " + str, max) : str; } - console.log(new Date().toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.instance, 20) + " " + pad(bot.process, 30) + " Entered into Main Loop # " + pad(Number(bot.loopCounter) + 1, 8)); - /* For each loop we want to create a new log file. */ logger = DEBUG_MODULE.newDebugLog(); @@ -289,7 +294,7 @@ clearTimeout(nextLoopTimeoutHandle); clearTimeout(checkLoopHealthHandle); bot.enableCheckLoopHealth = false; - callBackFunction(global.DEFAULT_OK_RESPONSE); + callBackFunction(global.DEFAULT_OK_RESPONSE, context); return; } } @@ -341,7 +346,7 @@ clearTimeout(nextLoopTimeoutHandle); clearTimeout(checkLoopHealthHandle); bot.enableCheckLoopHealth = false; - callBackFunction(global.DEFAULT_OK_RESPONSE); + callBackFunction(global.DEFAULT_OK_RESPONSE, context); return; } } @@ -369,9 +374,12 @@ } - /* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */ + /* High level log entry */ - let context; + console.log(bot.processDatetime.toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.devTeam, 20) + " " + pad(bot.process, 30) + " " + bot.startMode + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8)); + + /* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */ + let exchangeAPI; let assistant; let userBot; @@ -994,7 +1002,7 @@ clearTimeout(nextLoopTimeoutHandle); clearTimeout(checkLoopHealthHandle); bot.enableCheckLoopHealth = false; - callBackFunction(global.DEFAULT_OK_RESPONSE); + callBackFunction(global.DEFAULT_OK_RESPONSE, context); return; } @@ -1184,6 +1192,7 @@ callBackFunction(err); } } + } catch (err) { diff --git a/exchange/ExchangeAPI.js b/exchange/ExchangeAPI.js index 0c1559768..a2d728c97 100644 --- a/exchange/ExchangeAPI.js +++ b/exchange/ExchangeAPI.js @@ -5,12 +5,12 @@ This module allows trading bots to connect to the exchange and do trading operations on it. So far it can only work with Poloniex. */ - const _ = require('lodash'); - const isValidOrder = require('./exchangeUtils').isValidOrder; + const _ = require('lodash') + const isValidOrder = require('./exchangeUtils').isValidOrder const graphqlClient = require('graphql-client') - const request = require('request') - const authOptions = require('./Auth0') - + const appRoot = require('app-root-path') + const auth = require(`${appRoot}/utils/auth`) + let MODULE_NAME = "Exchange API"; let thisObject = { @@ -29,7 +29,7 @@ return thisObject; - function initialize(callBackFunction) { + async function initialize(callBackFunction) { try { if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } @@ -38,27 +38,16 @@ let botExchange = 'Poloniex'; let exchange = botExchange.toLowerCase() + 'Client.js'; let api = require('./wrappers/' + exchange); - - request(authOptions, onTokenResponse); - function onTokenResponse(error, response, body) { - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] onTokenResponse -> Entering function."); } + const authResponse = await auth.authenticate() - if (error) { - logger.write(MODULE_NAME, "[ERROR] onTokenResponse -> err = " + error.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } else { - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] onTokenResponse -> Token Received."); } - let response = JSON.parse(body) - let authToken = response.access_token - let keyVaultAPI = createKeyVaultAPIClient(authToken) - apiClient = api.newAPIClient(keyVaultAPI, logger); + let keyVaultAPI = createKeyVaultAPIClient(authResponse.data.access_token) + apiClient = api.newAPIClient(keyVaultAPI, logger); + + callBackFunction(global.DEFAULT_OK_RESPONSE); - callBackFunction(global.DEFAULT_OK_RESPONSE); - } - } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -67,8 +56,7 @@ if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createKeyVaultAPIClient -> Entering function."); } const keyVaultAPI = graphqlClient({ - //url: 'https://platform-api.advancedalgos.net/graphql', - url: 'https://platform-dev-api.advancedalgos.net/graphql', + url: global.GATEWAY_ENDPOINT, headers: { Authorization: 'Bearer ' + authToken } diff --git a/package-lock.json b/package-lock.json index ef0cf5a63..d98bbf8d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,10 +20,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "apollo-boost": { @@ -31,14 +31,14 @@ "resolved": "https://registry.npmjs.org/apollo-boost/-/apollo-boost-0.1.16.tgz", "integrity": "sha512-ppnQr90n2cn0ZMveEbqxW6NxmskIpThiLziLlRpRLy4keoAICg1NZecxJQmeaBLMtyhf5UholAjpS2SLmEJeHg==", "requires": { - "apollo-cache": "1.1.17", - "apollo-cache-inmemory": "1.2.10", - "apollo-client": "2.4.2", - "apollo-link": "1.2.3", - "apollo-link-error": "1.1.1", - "apollo-link-http": "1.5.5", - "apollo-link-state": "0.4.2", - "graphql-tag": "2.10.0" + "apollo-cache": "^1.1.17", + "apollo-cache-inmemory": "^1.2.10", + "apollo-client": "^2.4.2", + "apollo-link": "^1.0.6", + "apollo-link-error": "^1.0.3", + "apollo-link-http": "^1.3.1", + "apollo-link-state": "^0.4.0", + "graphql-tag": "^2.4.2" } }, "apollo-cache": { @@ -46,7 +46,7 @@ "resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.1.17.tgz", "integrity": "sha512-7sp24n2HZO4vXgTaKNomLyIfGxG4gDdDkBB0jkRzRi7HhnKmfwhiF/RCiKNbgLdrPX151INdls0KwIVliD0dHQ==", "requires": { - "apollo-utilities": "1.0.21" + "apollo-utilities": "^1.0.21" } }, "apollo-cache-inmemory": { @@ -54,9 +54,9 @@ "resolved": "https://registry.npmjs.org/apollo-cache-inmemory/-/apollo-cache-inmemory-1.2.10.tgz", "integrity": "sha512-eBusPFVtYIuo+PIfJdAwUCQ4cs7AJ4mB7sTdXxNQCXToYw8mzE6EfHnV37kdVfBXSaa82BzE2rb/YUq/duuamw==", "requires": { - "apollo-cache": "1.1.17", - "apollo-utilities": "1.0.21", - "graphql-anywhere": "4.1.19" + "apollo-cache": "^1.1.17", + "apollo-utilities": "^1.0.21", + "graphql-anywhere": "^4.1.19" } }, "apollo-client": { @@ -65,13 +65,13 @@ "integrity": "sha512-g1z23umaVSoKLj9xNl0aAnk2KBF4JeBi7MeKFc9CGTixH7TkqeQUQtxcjrC7j2h4KmDbuhOAHOFUGf8YshN+ag==", "requires": { "@types/async": "2.0.49", - "@types/zen-observable": "0.8.0", + "@types/zen-observable": "^0.8.0", "apollo-cache": "1.1.17", - "apollo-link": "1.2.3", - "apollo-link-dedup": "1.0.10", + "apollo-link": "^1.0.0", + "apollo-link-dedup": "^1.0.0", "apollo-utilities": "1.0.21", - "symbol-observable": "1.2.0", - "zen-observable": "0.8.9" + "symbol-observable": "^1.0.2", + "zen-observable": "^0.8.0" } }, "apollo-link": { @@ -79,8 +79,8 @@ "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.3.tgz", "integrity": "sha512-iL9yS2OfxYhigme5bpTbmRyC+Htt6tyo2fRMHT3K1XRL/C5IQDDz37OjpPy4ndx7WInSvfSZaaOTKFja9VWqSw==", "requires": { - "apollo-utilities": "1.0.21", - "zen-observable-ts": "0.8.10" + "apollo-utilities": "^1.0.0", + "zen-observable-ts": "^0.8.10" } }, "apollo-link-dedup": { @@ -88,7 +88,7 @@ "resolved": "https://registry.npmjs.org/apollo-link-dedup/-/apollo-link-dedup-1.0.10.tgz", "integrity": "sha512-tpUI9lMZsidxdNygSY1FxflXEkUZnvKRkMUsXXuQUNoSLeNtEvUX7QtKRAl4k9ubLl8JKKc9X3L3onAFeGTK8w==", "requires": { - "apollo-link": "1.2.3" + "apollo-link": "^1.2.3" } }, "apollo-link-error": { @@ -96,7 +96,7 @@ "resolved": "https://registry.npmjs.org/apollo-link-error/-/apollo-link-error-1.1.1.tgz", "integrity": "sha512-/yPcaQWcBdB94vpJ4FsiCJt1dAGGRm+6Tsj3wKwP+72taBH+UsGRQQZk7U/1cpZwl1yqhHZn+ZNhVOebpPcIlA==", "requires": { - "apollo-link": "1.2.3" + "apollo-link": "^1.2.3" } }, "apollo-link-http": { @@ -104,8 +104,8 @@ "resolved": "https://registry.npmjs.org/apollo-link-http/-/apollo-link-http-1.5.5.tgz", "integrity": "sha512-C5N6N/mRwmepvtzO27dgMEU3MMtRKSqcljBkYNZmWwH11BxkUQ5imBLPM3V4QJXNE7NFuAQAB5PeUd4ligivTQ==", "requires": { - "apollo-link": "1.2.3", - "apollo-link-http-common": "0.2.5" + "apollo-link": "^1.2.3", + "apollo-link-http-common": "^0.2.5" } }, "apollo-link-http-common": { @@ -113,7 +113,7 @@ "resolved": "https://registry.npmjs.org/apollo-link-http-common/-/apollo-link-http-common-0.2.5.tgz", "integrity": "sha512-6FV1wr5AqAyJ64Em1dq5hhGgiyxZE383VJQmhIoDVc3MyNcFL92TkhxREOs4rnH2a9X2iJMko7nodHSGLC6d8w==", "requires": { - "apollo-link": "1.2.3" + "apollo-link": "^1.2.3" } }, "apollo-link-state": { @@ -121,8 +121,8 @@ "resolved": "https://registry.npmjs.org/apollo-link-state/-/apollo-link-state-0.4.2.tgz", "integrity": "sha512-xMPcAfuiPVYXaLwC6oJFIZrKgV3GmdO31Ag2eufRoXpvT0AfJZjdaPB4450Nu9TslHRePN9A3quxNueILlQxlw==", "requires": { - "apollo-utilities": "1.0.21", - "graphql-anywhere": "4.1.19" + "apollo-utilities": "^1.0.8", + "graphql-anywhere": "^4.1.0-alpha.0" } }, "apollo-utilities": { @@ -130,16 +130,21 @@ "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.0.21.tgz", "integrity": "sha512-ZcxELlEl+sDCYBgEMdNXJAsZtRVm8wk4HIA58bMsqYfd1DSAJQEtZ93F0GZgYNAGy3QyaoBeZtbb0/01++G8JQ==", "requires": { - "fast-json-stable-stringify": "2.0.0", - "fclone": "1.0.11" + "fast-json-stable-stringify": "^2.0.0", + "fclone": "^1.0.11" } }, + "app-root-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.1.0.tgz", + "integrity": "sha1-mL9lmTJ+zqGZMJhm6BQDaP0uZGo=" + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": "~2.1.0" } }, "assert": { @@ -155,6 +160,14 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, + "async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "requires": { + "lodash": "^4.17.10" + } + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -170,22 +183,31 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, + "axios": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "requires": { + "follow-redirects": "^1.3.0", + "is-buffer": "^1.1.5" + } + }, "azure-storage": { "version": "2.10.2", "resolved": "https://registry.npmjs.org/azure-storage/-/azure-storage-2.10.2.tgz", "integrity": "sha512-pOyGPya9+NDpAfm5YcFfklo57HfjDbYLXxs4lomPwvRxmb0Di/A+a+RkUmEFzaQ8S13CqxK40bRRB0sjj2ZQxA==", "requires": { - "browserify-mime": "1.2.9", - "extend": "3.0.2", + "browserify-mime": "~1.2.9", + "extend": "^3.0.2", "json-edm-parser": "0.1.2", "md5.js": "1.3.4", - "readable-stream": "2.0.6", - "request": "2.88.0", - "underscore": "1.8.3", - "uuid": "3.3.2", - "validator": "9.4.1", + "readable-stream": "~2.0.0", + "request": "^2.86.0", + "underscore": "~1.8.3", + "uuid": "^3.0.0", + "validator": "~9.4.1", "xml2js": "0.2.8", - "xmlbuilder": "9.0.7" + "xmlbuilder": "^9.0.7" }, "dependencies": { "underscore": { @@ -201,7 +223,7 @@ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "optional": true, "requires": { - "tweetnacl": "0.14.5" + "tweetnacl": "^0.14.3" } }, "browserify-mime": { @@ -219,12 +241,62 @@ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" }, + "color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colornames": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", + "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=" + }, + "colors": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", + "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==" + }, + "colorspace": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.1.tgz", + "integrity": "sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw==", + "requires": { + "color": "3.0.x", + "text-hex": "1.0.x" + } + }, "combined-stream": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "core-util-is": { @@ -237,7 +309,15 @@ "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" + } + }, + "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" } }, "delayed-stream": { @@ -245,6 +325,16 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "diagnostics": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", + "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", + "requires": { + "colorspace": "1.1.x", + "enabled": "1.0.x", + "kuler": "1.0.x" + } + }, "dotenv": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", @@ -256,8 +346,16 @@ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "optional": true, "requires": { - "jsbn": "0.1.1", - "safer-buffer": "2.1.2" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "enabled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", + "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", + "requires": { + "env-variable": "0.0.x" } }, "encoding": { @@ -265,9 +363,14 @@ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", "requires": { - "iconv-lite": "0.4.24" + "iconv-lite": "~0.4.13" } }, + "env-variable": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", + "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==" + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -288,11 +391,29 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "fast-safe-stringify": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", + "integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==" + }, "fclone": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fclone/-/fclone-1.0.11.tgz", "integrity": "sha1-EOhdo4v+p/xZk0HClu4ddyZu5kA=" }, + "fecha": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", + "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" + }, + "follow-redirects": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.1.tgz", + "integrity": "sha512-t2JCjbzxQpWvbhts3l6SH1DKzSrx8a+SsaVf4h6bG4kOXUuPYS/kg2Lr4gQSb7eemaHqJkOThF1BGyjlUkO1GQ==", + "requires": { + "debug": "=3.1.0" + } + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -303,9 +424,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "requires": { - "asynckit": "0.4.0", + "asynckit": "^0.4.0", "combined-stream": "1.0.6", - "mime-types": "2.1.20" + "mime-types": "^2.1.12" }, "dependencies": { "combined-stream": { @@ -313,7 +434,7 @@ "resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } } } @@ -323,7 +444,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" } }, "graphql": { @@ -331,7 +452,7 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.0.2.tgz", "integrity": "sha512-gUC4YYsaiSJT1h40krG3J+USGlwhzNTXSb4IOZljn9ag5Tj+RkoXrWp+Kh7WyE3t1NCfab5kzCuxBIvOMERMXw==", "requires": { - "iterall": "1.2.2" + "iterall": "^1.2.2" } }, "graphql-anywhere": { @@ -339,7 +460,7 @@ "resolved": "https://registry.npmjs.org/graphql-anywhere/-/graphql-anywhere-4.1.19.tgz", "integrity": "sha512-mQlvbECzYPBcgBC9JsdM4v+DSvNmcIP+8Vwr+ij3gktbaLSE0Iza30mztuz40Jlf7ooMs+0emBZucNjLzqz7tA==", "requires": { - "apollo-utilities": "1.0.21" + "apollo-utilities": "^1.0.21" } }, "graphql-client": { @@ -347,7 +468,7 @@ "resolved": "https://registry.npmjs.org/graphql-client/-/graphql-client-2.0.1.tgz", "integrity": "sha512-XXdjUD3mwsBDcUB7g+iXQeRt+3gmIbvA/Yx1nE5aq2RQmaJwiH4hEoYw27AW8cDR90pCrPlHJAb1jJq3zUMbZA==", "requires": { - "isomorphic-fetch": "2.2.1" + "isomorphic-fetch": "^2.2.1" } }, "graphql-tag": { @@ -365,8 +486,8 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", "requires": { - "ajv": "5.5.2", - "har-schema": "2.0.0" + "ajv": "^5.3.0", + "har-schema": "^2.0.0" } }, "hash-base": { @@ -374,8 +495,8 @@ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "requires": { - "inherits": "2.0.1", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "http-signature": { @@ -383,9 +504,9 @@ "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.14.2" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "iconv-lite": { @@ -393,7 +514,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "inherits": { @@ -401,6 +522,16 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" }, + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -421,8 +552,8 @@ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", "requires": { - "node-fetch": "1.7.3", - "whatwg-fetch": "3.0.0" + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" } }, "isstream": { @@ -446,7 +577,7 @@ "resolved": "https://registry.npmjs.org/json-edm-parser/-/json-edm-parser-0.1.2.tgz", "integrity": "sha1-HmCw/vG8CvZ7wNFG393lSGzWFbQ=", "requires": { - "jsonparse": "1.2.0" + "jsonparse": "~1.2.0" } }, "json-schema": { @@ -480,18 +611,45 @@ "verror": "1.10.0" } }, + "kuler": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", + "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", + "requires": { + "colornames": "^1.1.1" + } + }, "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, + "logform": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-1.10.0.tgz", + "integrity": "sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg==", + "requires": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^2.3.3", + "ms": "^2.1.1", + "triple-beam": "^1.2.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, "md5.js": { "version": "1.3.4", "resolved": "http://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.1" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, "mime-db": { @@ -504,16 +662,21 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", "requires": { - "mime-db": "1.36.0" + "mime-db": "~1.36.0" } }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, "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.12", - "is-stream": "1.1.0" + "encoding": "^0.1.11", + "is-stream": "^1.0.1" } }, "nodemailer": { @@ -531,6 +694,11 @@ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, + "one-time": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", + "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=" + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -566,12 +734,12 @@ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.1", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" } }, "request": { @@ -579,26 +747,26 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.8.0", - "caseless": "0.12.0", - "combined-stream": "1.0.7", - "extend": "3.0.2", - "forever-agent": "0.6.1", - "form-data": "2.3.2", - "har-validator": "5.1.0", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.20", - "oauth-sign": "0.9.0", - "performance-now": "2.1.0", - "qs": "6.5.2", - "safe-buffer": "5.1.2", - "tough-cookie": "2.4.3", - "tunnel-agent": "0.6.0", - "uuid": "3.3.2" + "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.0", + "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.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" } }, "retry": { @@ -621,22 +789,35 @@ "resolved": "http://registry.npmjs.org/sax/-/sax-0.5.8.tgz", "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=" }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + } + }, "sshpk": { "version": "1.14.2", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", "requires": { - "asn1": "0.2.4", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.2", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.2", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "safer-buffer": "2.1.2", - "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", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" } }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", @@ -647,21 +828,31 @@ "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "requires": { - "psl": "1.1.29", - "punycode": "1.4.1" + "psl": "^1.1.24", + "punycode": "^1.4.1" } }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, "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.2" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { @@ -703,9 +894,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" } }, "whatwg-fetch": { @@ -713,12 +904,105 @@ "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" }, + "winston": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.1.0.tgz", + "integrity": "sha512-FsQfEE+8YIEeuZEYhHDk5cILo1HOcWkGwvoidLrDgPog0r4bser1lEIOco2dN9zpDJ1M88hfDgZvxe5z4xNcwg==", + "requires": { + "async": "^2.6.0", + "diagnostics": "^1.1.1", + "is-stream": "^1.1.0", + "logform": "^1.9.1", + "one-time": "0.0.4", + "readable-stream": "^2.3.6", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.2.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "winston-transport": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", + "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", + "requires": { + "readable-stream": "^2.3.6", + "triple-beam": "^1.2.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "xml2js": { "version": "0.2.8", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.2.8.tgz", "integrity": "sha1-m4FpCTFjH/CdGVdUn69U9PmAs8I=", "requires": { - "sax": "0.5.8" + "sax": "0.5.x" } }, "xmlbuilder": { @@ -736,7 +1020,7 @@ "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.10.tgz", "integrity": "sha512-5vqMtRggU/2GhePC9OU4sYEWOdvmayp2k3gjPf4F0mXwB3CSbbNznfDUvDJx9O2ZTa1EIXdJhPchQveFKwNXPQ==", "requires": { - "zen-observable": "0.8.9" + "zen-observable": "^0.8.0" } } } diff --git a/package.json b/package.json index a91b814fd..8b4027f28 100644 --- a/package.json +++ b/package.json @@ -10,17 +10,19 @@ "license": "ISC", "dependencies": { "apollo-boost": "^0.1.16", + "app-root-path": "^2.1.0", "assert": "^1.4.1", + "axios": "^0.18.0", + "azure-storage": "^2.8.2", + "dotenv": "^6.0.0", "graphql": "^14.0.2", "graphql-client": "^2.0.1", "lodash": "^4.17.11", "nodemailer": "^4.6.8", "nonce": "^1.0.4", "querystring": "^0.2.0", - "request": "^2.88.0", "retry": "^0.12.0", "underscore": "^1.9.1", - "azure-storage": "^2.8.2", - "dotenv": "^6.0.0" + "winston": "^3.1.0" } } diff --git a/utils/auth.js b/utils/auth.js new file mode 100644 index 000000000..114a25e9e --- /dev/null +++ b/utils/auth.js @@ -0,0 +1,25 @@ +const axios = require('axios') +const appRoot = require('app-root-path') +const { logger } = require(`${appRoot}/utils/logger`) + +exports.authenticate = function () { + try { + logger.debug('authenticate -> Entering Function.') + + const authBody = '{"client_id":"' + process.env.AUTH_CLIENT_ID + + '","client_secret": "' + process.env.AUTH_CLIENT_SECRET + + '","audience":"' + process.env.AUTH_AUDIENCE + + '","grant_type":"client_credentials"}' + + return axios({ + url: process.env.AUTH_URL, + method: 'post', + data: authBody, + headers: { 'content-type': 'application/json' } + }) + + } catch (error) { + logger.error('authenticate -> Error: ' + error.stack) + throw new Error('There has been an error on the authentication: ' + error) + } +} \ No newline at end of file diff --git a/utils/logger.js b/utils/logger.js new file mode 100644 index 000000000..1cc942d0c --- /dev/null +++ b/utils/logger.js @@ -0,0 +1,40 @@ +const winston = require('winston') +const appRoot = require('app-root-path') +const util = require('util') + +const options = { + file: { + level: 'info', + filename: `${appRoot}/logs/app.log`, + handleExceptions: true, + json: true, + maxsize: 5242880, // 5MB + maxFiles: 5, + colorize: false, + timestamp: true + }, + console: { + level: 'debug', + handleExceptions: true, + json: false, + colorize: true, + timestamp: true + } +} + +exports.logger = winston.createLogger({ + level: 'info', + format: winston.format.combine( + winston.format.colorize(), + winston.format.splat(), + winston.format.timestamp({ format: 'YY/MM/DD HH:mm' }), + winston.format.printf( + info => `${info.timestamp} - ${info.level}: ${JSON.parse(JSON.stringify(util.inspect(info.message)))}` + ) + ), + transports: [ + new winston.transports.File(options.file), + new winston.transports.Console(options.console) + ], + exitOnError: false // do not exit on handled exceptions +}) \ No newline at end of file From 46309d6cc577d60b0a625f52e45a7d07e1261684 Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Mon, 28 Jan 2019 17:27:45 -0300 Subject: [PATCH 16/76] Adding support for extractors and indicators --- Root.js | 6 +- Run.js | 84 ++++++++-- package-lock.json | 408 ++++++++++++++++++++++++++++------------------ package.json | 1 + 4 files changed, 321 insertions(+), 178 deletions(-) diff --git a/Root.js b/Root.js index 92ac034fc..d07ebb858 100644 --- a/Root.js +++ b/Root.js @@ -211,7 +211,7 @@ exports.newRoot = function newRoot() { for (let p = 0; p < global.PLATFORM_CONFIG.executionList.length; p++) { - let listItem = PLATFORM_CONFIG.executionList[p]; + let listItem; /* The local configuration allows to select the configuration to run @@ -225,10 +225,10 @@ exports.newRoot = function newRoot() { listItem = global.EXECUTION_CONFIG.executionList[p]; } - if (listItem.enabled !== "true") { + if (listItem === undefined || listItem.enabled !== "true") { console.log(logDisplace + "Root : [INFO] start -> Skipping process for being disabled."); - console.log(logDisplace + "Root : [INFO] start -> listItem.process = " + listItem.process); + console.log(logDisplace + "Root : [INFO] start -> listItem.process = " + PLATFORM_CONFIG.executionList[p].process); continue; } diff --git a/Run.js b/Run.js index 747440525..bd58bb8ec 100644 --- a/Run.js +++ b/Run.js @@ -42,14 +42,76 @@ readExecutionConfiguration(); function readExecutionConfiguration() { try { console.log("[INFO] Run -> readExecutionConfiguration -> Entering function. "); + let startMode + // Environment Configuration global.CURRENT_ENVIRONMENT = process.env.PLATFORM_ENVIRONMENT - global.DEV_TEAM = process.env.DEV_TEAM; - global.RUN_AS_TEAM = (process.env.RUN_AS_TEAM === "true"); - global.GATEWAY_ENDPOINT = process.env.GATEWAY_ENDPOINT; - global.STORAGE_URL = process.env.STORAGE_URL; - global.USER_LOGGED_IN = process.env.USER_LOGGED_IN; - global.CURRENT_BOT_REPO = process.env.BOT + "-" + process.env.TYPE + "-Bot"; + global.GATEWAY_ENDPOINT = process.env.GATEWAY_ENDPOINT + global.STORAGE_URL = process.env.STORAGE_URL + + // General Financial Being Configuration + global.DEV_TEAM = process.env.DEV_TEAM + global.CURRENT_BOT_REPO = process.env.BOT + "-" + process.env.TYPE + "-Bot" + global.RUN_AS_TEAM = (process.env.RUN_AS_TEAM === "true") + global.USER_LOGGED_IN = process.env.USER_LOGGED_IN + + if (process.env.TYPE === 'Trading') { + let live = { + run: "false", + resumeExecution: process.env.RESUME_EXECUTION + } + + let backtest = { + run: "false", + resumeExecution: process.env.RESUME_EXECUTION, + beginDatetime: process.env.BEGIN_DATE_TIME, + endDatetime: process.env.END_DATE_TIME, + waitTime: process.env.WAIT_TIME + } + + let competition = { + run: "false", + resumeExecution: process.env.RESUME_EXECUTION, + beginDatetime: process.env.BEGIN_DATE_TIME, + endDatetime: process.env.END_DATE_TIME + } + + startMode = { + live: live, + backtest: backtest, + competition: competition + } + } else if (process.env.TYPE === 'Indicator' || process.env.TYPE === 'Extractor') { + let allMonths = { + run: "false", + minYear: process.env.MIN_YEAR, + maxYear: process.env.MAX_YEAR + } + let oneMonth = { + run: "false", + year: process.env.YEAR, + month: process.env.MONTH + } + let noTime = { + run: "false" + } + let fixedInterval = { + run: "false", + interval: process.env.INTERVAL + } + + startMode = { + allMonths: allMonths, + oneMonth: oneMonth, + noTime: noTime, + fixedInterval: fixedInterval + } + } else { + console.log("[ERROR] readExecutionConfiguration -> Bot Type is invalid." ); + throw new Error("readExecutionConfiguration -> Bot Type is invalid.") + } + + startMode[process.env.START_MODE].run = "true" let executionList = [{ enabled: "true", @@ -59,16 +121,6 @@ function readExecutionConfiguration() { repo: global.CURRENT_BOT_REPO }] - let mode = - '{ "run": "false",' + - '"resumeExecution": "' + process.env.RESUME_EXECUTION + '",' + - '"beginDatetime": "' + process.env.BEGIN_DATE_TIME + '",' + - '"endDatetime": "' + process.env.END_DATE_TIME + '",' + - '"waitTime": "' + process.env.WAIT_TIME + '"' + - '}' - let startMode = JSON.parse('{ "live": ' + mode +', "backtest": '+mode+', "competition": '+mode+'}') - startMode[process.env.START_MODE].run = "true" - global.EXECUTION_CONFIG = { executionList: executionList, startMode: startMode diff --git a/package-lock.json b/package-lock.json index d98bbf8d0..fb0afbaa8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,10 +20,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" } }, "apollo-boost": { @@ -31,14 +31,14 @@ "resolved": "https://registry.npmjs.org/apollo-boost/-/apollo-boost-0.1.16.tgz", "integrity": "sha512-ppnQr90n2cn0ZMveEbqxW6NxmskIpThiLziLlRpRLy4keoAICg1NZecxJQmeaBLMtyhf5UholAjpS2SLmEJeHg==", "requires": { - "apollo-cache": "^1.1.17", - "apollo-cache-inmemory": "^1.2.10", - "apollo-client": "^2.4.2", - "apollo-link": "^1.0.6", - "apollo-link-error": "^1.0.3", - "apollo-link-http": "^1.3.1", - "apollo-link-state": "^0.4.0", - "graphql-tag": "^2.4.2" + "apollo-cache": "1.1.17", + "apollo-cache-inmemory": "1.2.10", + "apollo-client": "2.4.2", + "apollo-link": "1.2.3", + "apollo-link-error": "1.1.1", + "apollo-link-http": "1.5.5", + "apollo-link-state": "0.4.2", + "graphql-tag": "2.10.0" } }, "apollo-cache": { @@ -46,7 +46,7 @@ "resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.1.17.tgz", "integrity": "sha512-7sp24n2HZO4vXgTaKNomLyIfGxG4gDdDkBB0jkRzRi7HhnKmfwhiF/RCiKNbgLdrPX151INdls0KwIVliD0dHQ==", "requires": { - "apollo-utilities": "^1.0.21" + "apollo-utilities": "1.0.21" } }, "apollo-cache-inmemory": { @@ -54,9 +54,9 @@ "resolved": "https://registry.npmjs.org/apollo-cache-inmemory/-/apollo-cache-inmemory-1.2.10.tgz", "integrity": "sha512-eBusPFVtYIuo+PIfJdAwUCQ4cs7AJ4mB7sTdXxNQCXToYw8mzE6EfHnV37kdVfBXSaa82BzE2rb/YUq/duuamw==", "requires": { - "apollo-cache": "^1.1.17", - "apollo-utilities": "^1.0.21", - "graphql-anywhere": "^4.1.19" + "apollo-cache": "1.1.17", + "apollo-utilities": "1.0.21", + "graphql-anywhere": "4.1.19" } }, "apollo-client": { @@ -65,13 +65,13 @@ "integrity": "sha512-g1z23umaVSoKLj9xNl0aAnk2KBF4JeBi7MeKFc9CGTixH7TkqeQUQtxcjrC7j2h4KmDbuhOAHOFUGf8YshN+ag==", "requires": { "@types/async": "2.0.49", - "@types/zen-observable": "^0.8.0", + "@types/zen-observable": "0.8.0", "apollo-cache": "1.1.17", - "apollo-link": "^1.0.0", - "apollo-link-dedup": "^1.0.0", + "apollo-link": "1.2.3", + "apollo-link-dedup": "1.0.10", "apollo-utilities": "1.0.21", - "symbol-observable": "^1.0.2", - "zen-observable": "^0.8.0" + "symbol-observable": "1.2.0", + "zen-observable": "0.8.9" } }, "apollo-link": { @@ -79,8 +79,8 @@ "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.3.tgz", "integrity": "sha512-iL9yS2OfxYhigme5bpTbmRyC+Htt6tyo2fRMHT3K1XRL/C5IQDDz37OjpPy4ndx7WInSvfSZaaOTKFja9VWqSw==", "requires": { - "apollo-utilities": "^1.0.0", - "zen-observable-ts": "^0.8.10" + "apollo-utilities": "1.0.21", + "zen-observable-ts": "0.8.10" } }, "apollo-link-dedup": { @@ -88,7 +88,7 @@ "resolved": "https://registry.npmjs.org/apollo-link-dedup/-/apollo-link-dedup-1.0.10.tgz", "integrity": "sha512-tpUI9lMZsidxdNygSY1FxflXEkUZnvKRkMUsXXuQUNoSLeNtEvUX7QtKRAl4k9ubLl8JKKc9X3L3onAFeGTK8w==", "requires": { - "apollo-link": "^1.2.3" + "apollo-link": "1.2.3" } }, "apollo-link-error": { @@ -96,7 +96,7 @@ "resolved": "https://registry.npmjs.org/apollo-link-error/-/apollo-link-error-1.1.1.tgz", "integrity": "sha512-/yPcaQWcBdB94vpJ4FsiCJt1dAGGRm+6Tsj3wKwP+72taBH+UsGRQQZk7U/1cpZwl1yqhHZn+ZNhVOebpPcIlA==", "requires": { - "apollo-link": "^1.2.3" + "apollo-link": "1.2.3" } }, "apollo-link-http": { @@ -104,8 +104,8 @@ "resolved": "https://registry.npmjs.org/apollo-link-http/-/apollo-link-http-1.5.5.tgz", "integrity": "sha512-C5N6N/mRwmepvtzO27dgMEU3MMtRKSqcljBkYNZmWwH11BxkUQ5imBLPM3V4QJXNE7NFuAQAB5PeUd4ligivTQ==", "requires": { - "apollo-link": "^1.2.3", - "apollo-link-http-common": "^0.2.5" + "apollo-link": "1.2.3", + "apollo-link-http-common": "0.2.5" } }, "apollo-link-http-common": { @@ -113,7 +113,7 @@ "resolved": "https://registry.npmjs.org/apollo-link-http-common/-/apollo-link-http-common-0.2.5.tgz", "integrity": "sha512-6FV1wr5AqAyJ64Em1dq5hhGgiyxZE383VJQmhIoDVc3MyNcFL92TkhxREOs4rnH2a9X2iJMko7nodHSGLC6d8w==", "requires": { - "apollo-link": "^1.2.3" + "apollo-link": "1.2.3" } }, "apollo-link-state": { @@ -121,8 +121,8 @@ "resolved": "https://registry.npmjs.org/apollo-link-state/-/apollo-link-state-0.4.2.tgz", "integrity": "sha512-xMPcAfuiPVYXaLwC6oJFIZrKgV3GmdO31Ag2eufRoXpvT0AfJZjdaPB4450Nu9TslHRePN9A3quxNueILlQxlw==", "requires": { - "apollo-utilities": "^1.0.8", - "graphql-anywhere": "^4.1.0-alpha.0" + "apollo-utilities": "1.0.21", + "graphql-anywhere": "4.1.19" } }, "apollo-utilities": { @@ -130,8 +130,8 @@ "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.0.21.tgz", "integrity": "sha512-ZcxELlEl+sDCYBgEMdNXJAsZtRVm8wk4HIA58bMsqYfd1DSAJQEtZ93F0GZgYNAGy3QyaoBeZtbb0/01++G8JQ==", "requires": { - "fast-json-stable-stringify": "^2.0.0", - "fclone": "^1.0.11" + "fast-json-stable-stringify": "2.0.0", + "fclone": "1.0.11" } }, "app-root-path": { @@ -144,7 +144,7 @@ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "requires": { - "safer-buffer": "~2.1.0" + "safer-buffer": "2.1.2" } }, "assert": { @@ -165,7 +165,7 @@ "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", "requires": { - "lodash": "^4.17.10" + "lodash": "4.17.11" } }, "asynckit": { @@ -188,8 +188,8 @@ "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", "requires": { - "follow-redirects": "^1.3.0", - "is-buffer": "^1.1.5" + "follow-redirects": "1.6.1", + "is-buffer": "1.1.6" } }, "azure-storage": { @@ -197,17 +197,17 @@ "resolved": "https://registry.npmjs.org/azure-storage/-/azure-storage-2.10.2.tgz", "integrity": "sha512-pOyGPya9+NDpAfm5YcFfklo57HfjDbYLXxs4lomPwvRxmb0Di/A+a+RkUmEFzaQ8S13CqxK40bRRB0sjj2ZQxA==", "requires": { - "browserify-mime": "~1.2.9", - "extend": "^3.0.2", + "browserify-mime": "1.2.9", + "extend": "3.0.2", "json-edm-parser": "0.1.2", "md5.js": "1.3.4", - "readable-stream": "~2.0.0", - "request": "^2.86.0", - "underscore": "~1.8.3", - "uuid": "^3.0.0", - "validator": "~9.4.1", + "readable-stream": "2.0.6", + "request": "2.88.0", + "underscore": "1.8.3", + "uuid": "3.3.2", + "validator": "9.4.1", "xml2js": "0.2.8", - "xmlbuilder": "^9.0.7" + "xmlbuilder": "9.0.7" }, "dependencies": { "underscore": { @@ -223,7 +223,7 @@ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "optional": true, "requires": { - "tweetnacl": "^0.14.3" + "tweetnacl": "0.14.5" } }, "browserify-mime": { @@ -231,6 +231,11 @@ "resolved": "https://registry.npmjs.org/browserify-mime/-/browserify-mime-1.2.9.tgz", "integrity": "sha1-rrGvKN5sDXpqLOQK22j/GEIq8x8=" }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -246,8 +251,8 @@ "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" + "color-convert": "1.9.3", + "color-string": "1.5.3" } }, "color-convert": { @@ -268,8 +273,8 @@ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "color-name": "1.1.3", + "simple-swizzle": "0.2.2" } }, "colornames": { @@ -287,8 +292,8 @@ "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.1.tgz", "integrity": "sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw==", "requires": { - "color": "3.0.x", - "text-hex": "1.0.x" + "color": "3.0.0", + "text-hex": "1.0.0" } }, "combined-stream": { @@ -296,7 +301,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", "requires": { - "delayed-stream": "~1.0.0" + "delayed-stream": "1.0.0" } }, "core-util-is": { @@ -309,7 +314,7 @@ "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" } }, "debug": { @@ -330,9 +335,9 @@ "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", "requires": { - "colorspace": "1.1.x", - "enabled": "1.0.x", - "kuler": "1.0.x" + "colorspace": "1.1.1", + "enabled": "1.0.2", + "kuler": "1.0.1" } }, "dotenv": { @@ -346,8 +351,16 @@ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "optional": true, "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "jsbn": "0.1.1", + "safer-buffer": "2.1.2" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz", + "integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=", + "requires": { + "safe-buffer": "5.1.2" } }, "enabled": { @@ -355,7 +368,7 @@ "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", "requires": { - "env-variable": "0.0.x" + "env-variable": "0.0.5" } }, "encoding": { @@ -363,7 +376,7 @@ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", "requires": { - "iconv-lite": "~0.4.13" + "iconv-lite": "0.4.24" } }, "env-variable": { @@ -411,7 +424,7 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.1.tgz", "integrity": "sha512-t2JCjbzxQpWvbhts3l6SH1DKzSrx8a+SsaVf4h6bG4kOXUuPYS/kg2Lr4gQSb7eemaHqJkOThF1BGyjlUkO1GQ==", "requires": { - "debug": "=3.1.0" + "debug": "3.1.0" } }, "forever-agent": { @@ -424,9 +437,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "requires": { - "asynckit": "^0.4.0", + "asynckit": "0.4.0", "combined-stream": "1.0.6", - "mime-types": "^2.1.12" + "mime-types": "2.1.20" }, "dependencies": { "combined-stream": { @@ -434,7 +447,7 @@ "resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "requires": { - "delayed-stream": "~1.0.0" + "delayed-stream": "1.0.0" } } } @@ -444,7 +457,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" } }, "graphql": { @@ -452,7 +465,7 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.0.2.tgz", "integrity": "sha512-gUC4YYsaiSJT1h40krG3J+USGlwhzNTXSb4IOZljn9ag5Tj+RkoXrWp+Kh7WyE3t1NCfab5kzCuxBIvOMERMXw==", "requires": { - "iterall": "^1.2.2" + "iterall": "1.2.2" } }, "graphql-anywhere": { @@ -460,7 +473,7 @@ "resolved": "https://registry.npmjs.org/graphql-anywhere/-/graphql-anywhere-4.1.19.tgz", "integrity": "sha512-mQlvbECzYPBcgBC9JsdM4v+DSvNmcIP+8Vwr+ij3gktbaLSE0Iza30mztuz40Jlf7ooMs+0emBZucNjLzqz7tA==", "requires": { - "apollo-utilities": "^1.0.21" + "apollo-utilities": "1.0.21" } }, "graphql-client": { @@ -468,7 +481,7 @@ "resolved": "https://registry.npmjs.org/graphql-client/-/graphql-client-2.0.1.tgz", "integrity": "sha512-XXdjUD3mwsBDcUB7g+iXQeRt+3gmIbvA/Yx1nE5aq2RQmaJwiH4hEoYw27AW8cDR90pCrPlHJAb1jJq3zUMbZA==", "requires": { - "isomorphic-fetch": "^2.2.1" + "isomorphic-fetch": "2.2.1" } }, "graphql-tag": { @@ -486,8 +499,8 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", "requires": { - "ajv": "^5.3.0", - "har-schema": "^2.0.0" + "ajv": "5.5.2", + "har-schema": "2.0.0" } }, "hash-base": { @@ -495,8 +508,8 @@ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "2.0.1", + "safe-buffer": "5.1.2" } }, "http-signature": { @@ -504,9 +517,9 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.14.2" } }, "iconv-lite": { @@ -514,7 +527,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": "2.1.2" } }, "inherits": { @@ -552,8 +565,8 @@ "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" + "node-fetch": "1.7.3", + "whatwg-fetch": "3.0.0" } }, "isstream": { @@ -577,7 +590,7 @@ "resolved": "https://registry.npmjs.org/json-edm-parser/-/json-edm-parser-0.1.2.tgz", "integrity": "sha1-HmCw/vG8CvZ7wNFG393lSGzWFbQ=", "requires": { - "jsonparse": "~1.2.0" + "jsonparse": "1.2.0" } }, "json-schema": { @@ -600,6 +613,29 @@ "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.2.0.tgz", "integrity": "sha1-XAxWhRBxYOcv50ib3eoLRMK8Z70=" }, + "jsonwebtoken": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.4.0.tgz", + "integrity": "sha512-coyXjRTCy0pw5WYBpMvWOMN+Kjaik2MwTUIq9cna/W7NpO9E+iYbumZONAz3hcr+tXFJECoQVrtmIoC3Oz0gvg==", + "requires": { + "jws": "3.2.1", + "lodash.includes": "4.3.0", + "lodash.isboolean": "3.0.3", + "lodash.isinteger": "4.0.4", + "lodash.isnumber": "3.0.3", + "lodash.isplainobject": "4.0.6", + "lodash.isstring": "4.0.1", + "lodash.once": "4.1.1", + "ms": "2.1.1" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -611,12 +647,31 @@ "verror": "1.10.0" } }, + "jwa": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.2.0.tgz", + "integrity": "sha512-Grku9ZST5NNQ3hqNUodSkDfEBqAmGA1R8yiyPHOnLzEKI0GaCQC/XhFmsheXYuXzFQJdILbh+lYBiliqG5R/Vg==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.10", + "safe-buffer": "5.1.2" + } + }, + "jws": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.1.tgz", + "integrity": "sha512-bGA2omSrFUkd72dhh05bIAN832znP4wOU3lfuXtRBuGTbsmNmDXMQg28f0Vsxaxgk4myF5YkKQpz6qeRpMgX9g==", + "requires": { + "jwa": "1.2.0", + "safe-buffer": "5.1.2" + } + }, "kuler": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", "requires": { - "colornames": "^1.1.1" + "colornames": "1.1.1" } }, "lodash": { @@ -624,16 +679,51 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "logform": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/logform/-/logform-1.10.0.tgz", "integrity": "sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg==", "requires": { - "colors": "^1.2.1", - "fast-safe-stringify": "^2.0.4", - "fecha": "^2.3.3", - "ms": "^2.1.1", - "triple-beam": "^1.2.0" + "colors": "1.3.3", + "fast-safe-stringify": "2.0.6", + "fecha": "2.3.3", + "ms": "2.1.1", + "triple-beam": "1.3.0" }, "dependencies": { "ms": { @@ -648,8 +738,8 @@ "resolved": "http://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" + "hash-base": "3.0.4", + "inherits": "2.0.1" } }, "mime-db": { @@ -662,7 +752,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", "requires": { - "mime-db": "~1.36.0" + "mime-db": "1.36.0" } }, "ms": { @@ -675,8 +765,8 @@ "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" + "encoding": "0.1.12", + "is-stream": "1.1.0" } }, "nodemailer": { @@ -734,12 +824,12 @@ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.1", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" } }, "request": { @@ -747,26 +837,26 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "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.0", - "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.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" + "aws-sign2": "0.7.0", + "aws4": "1.8.0", + "caseless": "0.12.0", + "combined-stream": "1.0.7", + "extend": "3.0.2", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.1.0", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.20", + "oauth-sign": "0.9.0", + "performance-now": "2.1.0", + "qs": "6.5.2", + "safe-buffer": "5.1.2", + "tough-cookie": "2.4.3", + "tunnel-agent": "0.6.0", + "uuid": "3.3.2" } }, "retry": { @@ -794,7 +884,7 @@ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", "requires": { - "is-arrayish": "^0.3.1" + "is-arrayish": "0.3.2" } }, "sshpk": { @@ -802,15 +892,15 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", "requires": { - "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" + "asn1": "0.2.4", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.2", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.2", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "safer-buffer": "2.1.2", + "tweetnacl": "0.14.5" } }, "stack-trace": { @@ -838,8 +928,8 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" + "psl": "1.1.29", + "punycode": "1.4.1" } }, "triple-beam": { @@ -852,7 +942,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "^5.0.1" + "safe-buffer": "5.1.2" } }, "tweetnacl": { @@ -894,9 +984,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.2.0" + "extsprintf": "1.3.0" } }, "whatwg-fetch": { @@ -909,15 +999,15 @@ "resolved": "https://registry.npmjs.org/winston/-/winston-3.1.0.tgz", "integrity": "sha512-FsQfEE+8YIEeuZEYhHDk5cILo1HOcWkGwvoidLrDgPog0r4bser1lEIOco2dN9zpDJ1M88hfDgZvxe5z4xNcwg==", "requires": { - "async": "^2.6.0", - "diagnostics": "^1.1.1", - "is-stream": "^1.1.0", - "logform": "^1.9.1", + "async": "2.6.1", + "diagnostics": "1.1.1", + "is-stream": "1.1.0", + "logform": "1.10.0", "one-time": "0.0.4", - "readable-stream": "^2.3.6", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.2.0" + "readable-stream": "2.3.6", + "stack-trace": "0.0.10", + "triple-beam": "1.3.0", + "winston-transport": "4.3.0" }, "dependencies": { "inherits": { @@ -935,13 +1025,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -949,7 +1039,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -959,8 +1049,8 @@ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", "requires": { - "readable-stream": "^2.3.6", - "triple-beam": "^1.2.0" + "readable-stream": "2.3.6", + "triple-beam": "1.3.0" }, "dependencies": { "inherits": { @@ -978,13 +1068,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -992,7 +1082,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -1002,7 +1092,7 @@ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.2.8.tgz", "integrity": "sha1-m4FpCTFjH/CdGVdUn69U9PmAs8I=", "requires": { - "sax": "0.5.x" + "sax": "0.5.8" } }, "xmlbuilder": { @@ -1020,7 +1110,7 @@ "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.10.tgz", "integrity": "sha512-5vqMtRggU/2GhePC9OU4sYEWOdvmayp2k3gjPf4F0mXwB3CSbbNznfDUvDJx9O2ZTa1EIXdJhPchQveFKwNXPQ==", "requires": { - "zen-observable": "^0.8.0" + "zen-observable": "0.8.9" } } } diff --git a/package.json b/package.json index 8b4027f28..fa8757b2c 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "dotenv": "^6.0.0", "graphql": "^14.0.2", "graphql-client": "^2.0.1", + "jsonwebtoken": "^8.4.0", "lodash": "^4.17.11", "nodemailer": "^4.6.8", "nonce": "^1.0.4", From 23ad5e8a9411cf27c3ae66716ae8f370815f852b Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Tue, 29 Jan 2019 16:17:41 -0300 Subject: [PATCH 17/76] Updating indicator oneMonth start mode --- Run.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Run.js b/Run.js index bd58bb8ec..1dd32de50 100644 --- a/Run.js +++ b/Run.js @@ -89,7 +89,7 @@ function readExecutionConfiguration() { } let oneMonth = { run: "false", - year: process.env.YEAR, + year: process.env.MIN_YEAR, month: process.env.MONTH } let noTime = { From 76a0ce15f21a92137a6a7a22546b295b8c7a1221 Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Thu, 7 Feb 2019 09:51:21 -0300 Subject: [PATCH 18/76] Updating logs format --- ExtractionBotProcessMainLoop.js | 3 ++- IndicatorBotProcessMainLoop.js | 3 ++- TradingBotProcessMainLoop.js | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ExtractionBotProcessMainLoop.js b/ExtractionBotProcessMainLoop.js index 9802d27c4..e3caf7318 100644 --- a/ExtractionBotProcessMainLoop.js +++ b/ExtractionBotProcessMainLoop.js @@ -182,7 +182,8 @@ /* High level log entry */ - console.log(processDatetime.toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(pMonth, 2) + "/" + pad(pYear, 4) + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8)); + console.log(bot.processDatetime.toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(pMonth, 2) + "/" + pad(pYear, 4) + + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8)); /* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */ diff --git a/IndicatorBotProcessMainLoop.js b/IndicatorBotProcessMainLoop.js index 8248487dd..5ed0969df 100644 --- a/IndicatorBotProcessMainLoop.js +++ b/IndicatorBotProcessMainLoop.js @@ -182,7 +182,8 @@ /* High level log entry */ - console.log(bot.processDatetime.toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(pMonth, 2) + "/" + pad(pYear, 4) + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8)); + console.log(bot.processDatetime.toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(pMonth, 2) + "/" + pad(pYear, 4) + + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8)); /* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */ diff --git a/TradingBotProcessMainLoop.js b/TradingBotProcessMainLoop.js index 3c39c5660..b31cc9492 100644 --- a/TradingBotProcessMainLoop.js +++ b/TradingBotProcessMainLoop.js @@ -366,7 +366,7 @@ } } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> bot.processDatetime = " + bot.processDatetime); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> bot.processDatetime = " + bot.processDatetime.toISOString()); } if (global.AT_BREAKPOINT === true) { @@ -376,7 +376,8 @@ /* High level log entry */ - console.log(bot.processDatetime.toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.devTeam, 20) + " " + pad(bot.process, 30) + " " + bot.startMode + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8)); + console.log(new Date().toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.devTeam, 20) + " " + pad(bot.process, 30) + + " " + bot.startMode + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8) + " bot.processDatetime = " + bot.processDatetime.toISOString()); /* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */ From 3c0c7f43dec89f0a5b93e81461e484267dd4af99 Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Sun, 10 Feb 2019 17:31:09 -0300 Subject: [PATCH 19/76] Adding clone support --- Assistant.js | 41 +-------------------- Integrations/OperationsModuleIntegration.js | 8 ++-- Project.njsproj | 2 - Root.js | 12 ++++-- Run.js | 23 +----------- exchange/ExchangeAPI.js | 4 +- utils/auth.js | 38 +++++++++++++------ 7 files changed, 45 insertions(+), 83 deletions(-) diff --git a/Assistant.js b/Assistant.js index 232e61610..f5e86c857 100644 --- a/Assistant.js +++ b/Assistant.js @@ -1358,45 +1358,8 @@ } function sendEmail(pTitle, pBody, pTo) { - try { - - /** - Email configuration is not available when running the bot on the browser. - */ - if (global.CURRENT_EXECUTION_AT === "Browser") { - logger.write(MODULE_NAME, "[WARN] sendEmail -> Send emails is disabled from the browser."); - return; - } - - let emailList = pTo; //TODO Pending to add spam controller - let runIndex = context.statusReport.runs.length - 1; - - let transporter = nodemailer.createTransport({ - service: global.EMAIL_CONFIG.service, - auth: { - user: global.EMAIL_CONFIG.user, - pass: global.EMAIL_CONFIG.pass - } - }); - - let mailOptions = { - from: global.EMAIL_CONFIG.from, - bcc: emailList, - subject: bot.startMode + "." + runIndex + ' - ' + pTitle, - text: pBody - }; - - transporter.sendMail(mailOptions, function (error, info) { - if (error) { - logger.write(MODULE_NAME, "[ERROR] sendEmail -> err = " + error); - } else { - logger.write(MODULE_NAME, "[INFO] sendEmail -> Email sent = " + info.response); - } - }); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] sendEmail -> err = " + err.message); - } + logger.write(MODULE_NAME, "[WARN] sendEmail -> Send emails is currently disabled."); + return; } function truncDecimals(pFloatValue, pDecimals) { diff --git a/Integrations/OperationsModuleIntegration.js b/Integrations/OperationsModuleIntegration.js index 41c4642c7..b8de71616 100644 --- a/Integrations/OperationsModuleIntegration.js +++ b/Integrations/OperationsModuleIntegration.js @@ -10,7 +10,7 @@ exports.updateExecutionResults = async function (summaryDate, buyAverage, sellAv try { - const authResponse = await auth.authenticate() + const accessToken = await auth.authenticate() const operationsResponse = await axios({ url: process.env.GATEWAY_ENDPOINT, @@ -46,11 +46,13 @@ exports.updateExecutionResults = async function (summaryDate, buyAverage, sellAv }, }, headers: { - authorization: 'Bearer ' + authResponse.data.access_token + authorization: 'Bearer ' + accessToken } }) - logger.debug('updateExecutionResults -> Operations Module Response: %s', operationsResponse.data.data.operations_UpdateExecutionSummary) + if (!operationsResponse.data.errors) + logger.debug('updateExecutionResults -> Operations Module Response: %s', operationsResponse.data.data.operations_UpdateExecutionSummary) + else throw new Error(operationsResponse.data.errors[0].message) } catch (error) { logger.error('updateExecutionResults -> Error: ' + error.stack) diff --git a/Project.njsproj b/Project.njsproj index c8f20791c..fe4d8f923 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -85,13 +85,11 @@ - - diff --git a/Root.js b/Root.js index d07ebb858..86486ae54 100644 --- a/Root.js +++ b/Root.js @@ -841,11 +841,11 @@ exports.newRoot = function newRoot() { } - let clonName = "Clon" + clonKey; + let clonName = botConfig.codeName + "-" + "Clon" + clonKey + "-" + process.env.CLONE_ID; - botConfig.filePathRoot = botConfig.devTeam + "/" + botConfig.codeName + "-" + clonName + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion; + botConfig.filePathRoot = botConfig.devTeam + "/" + clonName + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion; - botConfig.instance = "Clon" + clonKey; + botConfig.instance = clonName; botConfig.instanceIndex = i; setTimeout(execute, i * Math.random() * 10 * 1000); @@ -861,7 +861,11 @@ exports.newRoot = function newRoot() { /* If the bot does not have any genes at all */ let genes = {}; - pBotConfig.instance = "Master"; + let clonName = botConfig.codeName + "-" + process.env.CLONE_ID; + + botConfig.filePathRoot = botConfig.devTeam + "/" + clonName + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion; + + pBotConfig.instance = clonName; pBotConfig.instanceIndex = 0; createBotInstance(genes, 1, pBotConfig); diff --git a/Run.js b/Run.js index 1dd32de50..2abe7cb4c 100644 --- a/Run.js +++ b/Run.js @@ -47,7 +47,6 @@ function readExecutionConfiguration() { // Environment Configuration global.CURRENT_ENVIRONMENT = process.env.PLATFORM_ENVIRONMENT global.GATEWAY_ENDPOINT = process.env.GATEWAY_ENDPOINT - global.STORAGE_URL = process.env.STORAGE_URL // General Financial Being Configuration global.DEV_TEAM = process.env.DEV_TEAM @@ -182,8 +181,9 @@ function readStoragePermissions() { global.USER_PROFILE.storagePermissions = permissionsMap; global.USER_PROFILE.connectionString = ""; + process.env.STORAGE_CONNECTION_STRING = ""; - readEmailConfiguration(); + startRoot(); } } @@ -193,25 +193,6 @@ function readStoragePermissions() { } } -function readEmailConfiguration() { - - let filePath; - - try { - console.log( "Run : [INFO] readEmailConfiguration -> Entering function. "); - - let fs = require('fs'); - filePath = './' + 'configs' + '/' + 'Email.Config.json'; - global.EMAIL_CONFIG = JSON.parse(fs.readFileSync(filePath, 'utf8')); - - startRoot(); - } - catch (err) { - console.log("[ERROR] Run -> readEmailConfiguration -> err = " + err.message); - console.log("[HINT] Run -> You need to have a file at this path -> " + filePath); - } -} - function startRoot() { console.log( "[INFO] Run -> startRoot -> Entering function. "); diff --git a/exchange/ExchangeAPI.js b/exchange/ExchangeAPI.js index a2d728c97..2ad5eddfd 100644 --- a/exchange/ExchangeAPI.js +++ b/exchange/ExchangeAPI.js @@ -39,9 +39,9 @@ let exchange = botExchange.toLowerCase() + 'Client.js'; let api = require('./wrappers/' + exchange); - const authResponse = await auth.authenticate() + const accessToken = await auth.authenticate() - let keyVaultAPI = createKeyVaultAPIClient(authResponse.data.access_token) + let keyVaultAPI = createKeyVaultAPIClient(accessToken) apiClient = api.newAPIClient(keyVaultAPI, logger); callBackFunction(global.DEFAULT_OK_RESPONSE); diff --git a/utils/auth.js b/utils/auth.js index 114a25e9e..c7f0b8d87 100644 --- a/utils/auth.js +++ b/utils/auth.js @@ -2,22 +2,36 @@ const appRoot = require('app-root-path') const { logger } = require(`${appRoot}/utils/logger`) -exports.authenticate = function () { +exports.authenticate = async function () { try { - logger.debug('authenticate -> Entering Function.') - const authBody = '{"client_id":"' + process.env.AUTH_CLIENT_ID - + '","client_secret": "' + process.env.AUTH_CLIENT_SECRET - + '","audience":"' + process.env.AUTH_AUDIENCE - + '","grant_type":"client_credentials"}' + if (!global.ACCESS_TOKEN) { + logger.debug('authenticate -> Entering Function.') - return axios({ - url: process.env.AUTH_URL, - method: 'post', - data: authBody, - headers: { 'content-type': 'application/json' } - }) + const authBody = '{"client_id":"' + process.env.AUTH_CLIENT_ID + + '","client_secret": "' + process.env.AUTH_CLIENT_SECRET + + '","audience":"' + process.env.AUTH_AUDIENCE + + '","grant_type":"client_credentials"}' + let authResponse = await axios({ + url: process.env.AUTH_URL, + method: 'post', + data: authBody, + headers: { 'content-type': 'application/json' } + }) + + if (!authResponse.data.errors) + global.ACCESS_TOKEN = authResponse.data.access_token + else throw new Error(operationsResponse.data.errors[0].message) + + process.env.AUTH_CLIENT_ID = "" + process.env.AUTH_CLIENT_SECRET = "" + process.env.AUTH_AUDIENCE = "" + process.env.AUTH_URL = "" + } + + return global.ACCESS_TOKEN + } catch (error) { logger.error('authenticate -> Error: ' + error.stack) throw new Error('There has been an error on the authentication: ' + error) From b3da8aba4108c0ae51ffad922172a4af8ee41ef3 Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Sun, 10 Feb 2019 18:08:11 -0300 Subject: [PATCH 20/76] Upercase Exchange Folder --- exchange/ExchangeAPI.js | 301 -- exchange/exchangeUtils.js | 100 - exchange/wrappers/beautifier.js | 183 - exchange/wrappers/binance.js | 368 -- exchange/wrappers/binanceClient.js | 360 -- exchange/wrappers/binanceProperties.json | 4594 --------------------- exchange/wrappers/poloniex.js | 440 -- exchange/wrappers/poloniexClient.js | 353 -- exchange/wrappers/poloniexProperties.json | 3513 ---------------- 9 files changed, 10212 deletions(-) delete mode 100644 exchange/ExchangeAPI.js delete mode 100644 exchange/exchangeUtils.js delete mode 100644 exchange/wrappers/beautifier.js delete mode 100644 exchange/wrappers/binance.js delete mode 100644 exchange/wrappers/binanceClient.js delete mode 100644 exchange/wrappers/binanceProperties.json delete mode 100644 exchange/wrappers/poloniex.js delete mode 100644 exchange/wrappers/poloniexClient.js delete mode 100644 exchange/wrappers/poloniexProperties.json diff --git a/exchange/ExchangeAPI.js b/exchange/ExchangeAPI.js deleted file mode 100644 index 2ad5eddfd..000000000 --- a/exchange/ExchangeAPI.js +++ /dev/null @@ -1,301 +0,0 @@ -exports.newExchangeAPI = function newExchangeAPI(bot, logger) { - - /* - - This module allows trading bots to connect to the exchange and do trading operations on it. So far it can only work with Poloniex. - - */ - const _ = require('lodash') - const isValidOrder = require('./exchangeUtils').isValidOrder - const graphqlClient = require('graphql-client') - const appRoot = require('app-root-path') - const auth = require(`${appRoot}/utils/auth`) - - let MODULE_NAME = "Exchange API"; - - let thisObject = { - initialize: initialize, - getTicker: getTicker, - getOpenPositions: getOpenPositions, - getExecutedTrades: getExecutedTrades, - putPosition: putPosition, - movePosition: movePosition, - getPublicTradeHistory: getPublicTradeHistory, - getExchangeProperties: getExchangeProperties, - getMaxDecimalPositions: getMaxDecimalPositions - }; - - let apiClient; - - return thisObject; - - async function initialize(callBackFunction) { - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } - - // TODO integrate with financial beings module to get the exchange - let botExchange = 'Poloniex'; - let exchange = botExchange.toLowerCase() + 'Client.js'; - let api = require('./wrappers/' + exchange); - - const accessToken = await auth.authenticate() - - let keyVaultAPI = createKeyVaultAPIClient(accessToken) - apiClient = api.newAPIClient(keyVaultAPI, logger); - - callBackFunction(global.DEFAULT_OK_RESPONSE); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function createKeyVaultAPIClient(authToken) { - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createKeyVaultAPIClient -> Entering function."); } - - const keyVaultAPI = graphqlClient({ - url: global.GATEWAY_ENDPOINT, - headers: { - Authorization: 'Bearer ' + authToken - } - }); - - keyVaultAPI.signTransaction = function (transaction, next) { - let variables = { - botId: bot.codeName, - transaction: transaction - } - - keyVaultAPI.query(` - mutation($botId: String, $transaction: String!){ - keyVault_SignTransaction(botId: $botId, transaction: $transaction){ - key, - signature, - date - } - }`, variables, function (req, res) { - if (res.status === 401) { - next(undefined, 'Error from graphql: Not authorized'); - } - }).then(res => { - if (res.errors) { - next(undefined, 'Error from graphql: ' + res.errors); - } else { - let signature = { - Key: res.data.keyVault_SignTransaction.key, - Sign: res.data.keyVault_SignTransaction.signature - } - next(signature) - } - }).catch(error => { - next(undefined, 'Error signing the message on the key vault: ' + error.message); - }); - } - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createKeyVaultAPIClient -> Returning graphql client."); } - - return keyVaultAPI; - } - - /* - * Position Object = { - * id, String - * type, String - * rate, Number - * amountA, Number - * amountB, Number - * fee, Number - * datetime Date - * }; - */ - function truncDecimals(pFloatValue) { - let decimals = getMaxDecimalPositions(); - return parseFloat(parseFloat(pFloatValue).toFixed(decimals)); - } - - /* - * Return number of decimals for the current market - */ - function getMaxDecimalPositions() { - return getMarketConfig().maxDecimals; - } - - /* - * Return number of decimals for the current market - */ - function getMarketConfig() { - return _.find(getExchangeProperties().markets, (p) => { - return _.first(p.pair) === global.MARKET.assetA.toUpperCase() && - _.last(p.pair) === global.MARKET.assetB.toUpperCase(); - }); - } - - /* - * Return number of decimals for the current market - */ - function getExchangeProperties() { - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getExchangeProperties -> Entering function."); } - - return apiClient.getExchangeProperties(); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] getExchangeProperties -> err = " + err.message); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - - /* - * Returns the price for a given pair of assets. - * The object returned is an array of trades: - * ticker = { - * bid, Number - * ask, Number - * last Number - * }; - */ - function getTicker(pMarket, callBack) { - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getTicker -> Entering function."); } - - apiClient.getTicker(pMarket, callBack); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] getTicker -> err = " + err.message); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - - /* - * Returns the open positions ath the exchange for a given market and user account. - * The object returned is an array of positions - * - */ - function getOpenPositions(pMarket, callBack) { - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getOpenPositions -> Entering function."); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getOpenPositions -> pMarket = " + JSON.stringify(pMarket)); } - - apiClient.getOpenPositions(pMarket, callBack); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] getOpenPositions -> Error = " + err.message); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - - /* - * Returns the trades for a given order number. - * The object returned is an array of positions - */ - function getExecutedTrades(pPositionId, callBack) { - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getExecutedTrades -> Entering function."); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getExecutedTrades -> pPositionId = " + pPositionId); } - - apiClient.getExecutedTrades(pPositionId, callBack); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] getExecutedTrades -> Error = " + err.message); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - - /* - * Creates a new buy or sell order. - * The orderNumber is returned. String - */ - function putPosition(pMarket, pType, pRate, pAmountA, pAmountB, callBack) { - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> Entering function."); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pMarket = " + JSON.stringify(pMarket)); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pType = " + pType); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pRate = " + truncDecimals(pRate)); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pAmountA = " + truncDecimals(pAmountA)); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pAmountB = " + truncDecimals(pAmountB)); } - - let check = isValidOrder({ - market: getMarketConfig(), - api: apiClient, - amount: truncDecimals(pAmountB), - price: truncDecimals(pRate) - }); - - if (check.valid) { - if (pType === "buy") { - apiClient.buy(pMarket.assetA, pMarket.assetB, truncDecimals(pRate), truncDecimals(pAmountB), callBack); - return; - } - - if (pType === "sell") { - apiClient.sell(pMarket.assetA, pMarket.assetB, truncDecimals(pRate), truncDecimals(pAmountB), callBack); - return; - } - - logger.write(MODULE_NAME, "[ERROR] putPosition -> pType must be either 'buy' or 'sell'."); - callBack(global.DEFAULT_FAIL_RESPONSE); - - } else { - logger.write(MODULE_NAME, "[ERROR] putPosition -> The order is invalid: " + check.reason); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] putPosition -> err = " + err.message); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - - /* - * Move an existing position to the new rate. - * The new orderNumber is returned. - */ - function movePosition(pPosition, pNewRate, pNewAmountB, callBack) { - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] movePosition -> Entering function."); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] movePosition -> pPosition = " + JSON.stringify(pPosition)); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] movePosition -> pNewRate = " + truncDecimals(pNewRate)); } - - apiClient.movePosition(pPosition, truncDecimals(pNewRate), truncDecimals(pNewAmountB), callBack); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] movePosition -> err = " + err.message); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - - /* - * Returns all the trade history from the Exchange since startTime to endTime orderd by tradeId. - * It's possible that the exchange doesn't support this method. - * The object returned is an array of trades: - * trade = { - * tradeID, String - * globalTradeID, String - * type, String - * rate, Number - * amountA, Number - * amountB, Number - * date Date - * }; - */ - function getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack) { - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getTradeHistory -> Entering function."); } - - apiClient.getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] getTradeHistory -> err = " + err.message); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } -}; diff --git a/exchange/exchangeUtils.js b/exchange/exchangeUtils.js deleted file mode 100644 index 853d6d825..000000000 --- a/exchange/exchangeUtils.js +++ /dev/null @@ -1,100 +0,0 @@ -// generic low level reusuable utils for interacting with exchanges. - -const retry = require('retry'); -const _ = require('lodash'); - -const retryInstance = (options, checkFn, callback) => { - if(!options) { - options = { - retries: 100, - factor: 1.2, - minTimeout: 1 * 1000, - maxTimeout: 4 * 1000 - }; - } - - let attempt = 0; - - const operation = retry.operation(options); - operation.attempt(function(currentAttempt) { - checkFn((err, result) => { - if (!err) { - return callback(global.DEFAULT_OK_RESPONSE, result); - } else { - if (err.result === global.CUSTOM_OK_RESPONSE.result) { - return callback(err, result); - } - } - - let maxAttempts = err.retry; - if(maxAttempts === true) - maxAttempts = 10; - - if(err.retry && attempt++ < maxAttempts) { - return operation.retry(err); - } - - if(err.notFatal) { - if(err.backoffDelay) { - return setTimeout(() => operation.retry(err), err.backoffDelay); - } - - return operation.retry(err); - } - - callback(err, result); - }); - }); -} - -const isValidOrder = ({api, market, amount, price}) => { - let reason = false; - - // Check amount - if(amount < market.minimalOrder.amount) { - reason = 'Amount is too small'; - } - - // Some exchanges have restrictions on prices - if( - _.isFunction(api.isValidPrice) && - !api.isValidPrice(price) - ) { - reason = 'Price is not valid'; - } - - if( - _.isFunction(api.isValidLot) && - !api.isValidLot(price, amount) - ) { - reason = 'Lot size is too small'; - } - - return { - reason, - valid: !reason - } -} - -const includes = function(str, list) { - if (!_.isString(str)) - return false; - - return _.some(list, item => str.includes(item)); -} - - -const getMarketConfig = function(exchangeProperties) { - return _.find(exchangeProperties.markets, (p) => { - return _.first(p.pair) === global.MARKET.assetA.toUpperCase() && - _.last(p.pair) === global.MARKET.assetB.toUpperCase(); - }); -} - -module.exports = { - retry: retryInstance, - includes: includes, - isValidOrder, - getMarketConfig - -} \ No newline at end of file diff --git a/exchange/wrappers/beautifier.js b/exchange/wrappers/beautifier.js deleted file mode 100644 index 5e5e6a051..000000000 --- a/exchange/wrappers/beautifier.js +++ /dev/null @@ -1,183 +0,0 @@ -const _ = require('underscore'); - -class Beautifier { - - constructor() { - this._beautifications = { - aggTrades: { - a: 'aggTradeId', - p: 'price', - q: 'quantity', - f: 'firstTradeId', - l: 'lastTradeId', - T: 'timestamp', - m: 'maker', - M: 'bestPriceMatch' - }, - klines: { - 0: 'openTime', - 1: 'open', - 2: 'high', - 3: 'low', - 4: 'close', - 5: 'volume', - 6: 'closeTime', - 7: 'quoteAssetVolume', - 8: 'trades', - 9: 'takerBaseAssetVolume', - 10: 'takerQuoteAssetVolume', - 11: 'ignored' - }, - bids: [ - { - 0: 'price', - 1: 'quantity', - 2: 'ignored' - } - ], - asks: [ - { - 0: 'price', - 1: 'quantity', - 2: 'ignored' - } - ], - depthUpdateEvent: { - e: 'eventType', - E: 'eventTime', - s: 'symbol', - u: 'updateId', - b: 'bidDepthDelta', - a: 'askDepthDelta' - }, - bidDepthDelta: [ - { - 0: 'price', - 1: 'quantity', - 2: 'ignored' - } - ], - askDepthDelta: [ - { - 0: 'price', - 1: 'quantity', - 2: 'ignored' - } - ], - klineEvent: { - e: 'eventType', - E: 'eventTime', - s: 'symbol', - k: 'kline' - }, - kline: { - t: 'startTime', - T: 'endTime', - s: 'symbol', - i: 'interval', - f: 'firstTradeId', - L: 'lastTradeId', - o: 'open', - c: 'close', - h: 'high', - l: 'low', - v: 'volume', - n: 'trades', - x: 'final', - q: 'quoteVolume', - V: 'volumeActive', - Q: 'quoteVolumeActive', - B: 'ignored' - }, - aggTradeEvent: { - e: 'eventType', - E: 'eventTime', - s: 'symbol', - a: 'tradeId', - p: 'price', - q: 'quantity', - f: 'firstTradeId', - l: 'lastTradeId', - T: 'time', - m: 'maker', - M: 'ignored' - }, - outboundAccountInfoEvent: { - e: 'eventType', - E: 'eventTime', - m: 'makerCommission', - t: 'takerCommission', - b: 'buyerCommission', - s: 'sellerCommission', - T: 'canTrade', - W: 'canWithdraw', - D: 'canDeposit', - B: 'balances' - }, - balances: [ - { - a: 'asset', - f: 'availableBalance', - l: 'onOrderBalance' - } - ], - executionReportEvent: { - e: 'eventType', - E: 'eventTime', - s: 'symbol', - c: 'newClientOrderId', - S: 'side', - o: 'orderType', - f: 'cancelType', // GTC 'Good till Cancel', IOC: 'Immediate or Cancel' - q: 'quantity', - p: 'price', - x: 'executionType', - X: 'orderStatus', - r: 'rejectReason', - i: 'orderId', - l: 'lastTradeQuantity', - z: 'accumulatedQuantity', - L: 'lastTradePrice', - n: 'commission', - N: 'commissionAsset', - m: 'maker', - T: 'tradeTime', - t: 'tradeId' - } - } - } - - beautify(object, type) { - const beautifications = _.isObject(type) ? type : this._beautifications[type]; - if (!beautifications) { - return object; - } - let newItem = {}; - _.each(object, (value, key) => { - if (_.isArray(value)) { - const newArray = []; - if (_.isArray(this._beautifications[beautifications[key]])) { - _.each(value, arrayValue => { - newArray.push(this.beautify(arrayValue, this._beautifications[beautifications[key]][0])); - }); - } else { - _.each(value, (value, key) => { - newItem.push(this.beautify(value, beautifications[key])) - }); - } - const newKey = beautifications[key] || key; - newItem[newKey] = newArray; - } else if (_.isObject(value)) { - const newKey = beautifications[key] || key; - newItem[newKey] = this.beautify(value, beautifications[key]); - } else { - const newKey = beautifications[key] || key; - newItem[newKey] = value; - } - }); - return newItem; - } - -} - -module.exports = Beautifier; \ No newline at end of file diff --git a/exchange/wrappers/binance.js b/exchange/wrappers/binance.js deleted file mode 100644 index 624c0fc06..000000000 --- a/exchange/wrappers/binance.js +++ /dev/null @@ -1,368 +0,0 @@ -// Source: https://github.com/zoeyg/binance/blob/master/lib/rest.js - -const request = require('request'); -const qs = require('querystring'); -const _ = require('underscore'); -const crypto = require('crypto'); -const Beautifier = require('./beautifier.js'); -const assert = require('assert'); - -class BinanceRest { - - constructor({ - key, - secret, - recvWindow = false, - timeout = 15000, - disableBeautification = false, - handleDrift = false - }) { - this.key = key; - this.secret = secret; - this.recvWindow = recvWindow; - this.timeout = timeout; - this.disableBeautification = disableBeautification; - this.handleDrift = handleDrift; - - this._beautifier = new Beautifier(); - this._baseUrl = 'https://api.binance.com/'; - this._drift = 0; - this._syncInterval = 0; - } - - _makeRequest(query, callback, route, security, method, attempt = 0) { - assert(_.isUndefined(callback) || _.isFunction(callback), 'callback must be a function or undefined'); - assert(_.isObject(query), 'query must be an object'); - - let queryString; - const type = _.last(route.split('/')), - options = { - url: `${this._baseUrl}${route}`, - timeout: this.timeout - }; - - if (security === 'SIGNED') { - if (this.recvWindow) { - query.recvWindow = this.recvWindow; - } - queryString = qs.stringify(query); - options.url += '?' + queryString; - if (options.url.substr(options.url.length - 1) !== '?') { - options.url += '&'; - } - options.url += `signature=${this._sign(queryString)}`; - } else { - queryString = qs.stringify(query); - if (queryString) { - options.url += '?' + queryString; - } - } - if (security === 'API-KEY' || security === 'SIGNED') { - options.headers = { 'X-MBX-APIKEY': this.key }; - } - if (method) { - options.method = method; - } - - const action = cb => { - request(options, (err, response, body) => { - let payload; - try { - payload = JSON.parse(body); - } catch (e) { - payload = body; - } - if (err) { - cb(err, payload); - } else if (response.statusCode < 200 || response.statusCode > 299) { - /* - * If we get a response that the timestamp is ahead of the server, - * calculate the drift and then attempt the request again - */ - if (response.statusCode === 400 && payload.code === -1021 && - this.handleDrift && attempt === 0) { - - this.calculateDrift() - .then(() => { - query.timestamp = this._getTime() + this._drift; - return this._makeRequest(query, cb, route, security, method, - ++attempt); - }); - } else { - cb(new Error(`Response code ${response.statusCode}`), payload); - } - } else { - if (_.isArray(payload)) { - payload = _.map(payload, (item) => { - return this._doBeautifications(item, type); - }); - } else { - payload = this._doBeautifications(payload); - } - cb(err, payload); - } - }); - }; - if (callback) { - action(callback); - } else { - return new Promise((resolve, reject) => action((err, payload) => { - if (err) { - if (payload === undefined) { - reject(err); - } else { - reject(payload); - } - } else { - resolve(payload); - } - })); - } - } - - _doBeautifications(response, route) { - if (this.disableBeautification) { - return response; - } - return this._beautifier.beautify(response, route); - } - - _sign(queryString) { - return crypto.createHmac('sha256', this.secret) - .update(queryString) - .digest('hex'); - } - - _setTimestamp(query) { - if (!query.timestamp) { - query.timestamp = this._getTime() + this._drift; - } - } - - _getTime() { - return new Date().getTime(); - } - - calculateDrift() { - const systemTime = this._getTime(); - return this.time() - .then((response) => { - // Calculate the approximate trip time from here to binance - const transitTime = parseInt((this._getTime() - systemTime) / 2); - this._drift = response.serverTime - (systemTime + transitTime); - }); - } - - startTimeSync(interval = 300000, onRecalculateDriftCb) { - return new Promise((resolve, reject) => { - // If there's already an interval running, clear it and reset values - if (this._syncInterval !== 0) { - this.endTimeSync(); - return resolve(); - } - - // Calculate initial drift value and setup interval to periodically update it - this.calculateDrift() - .then(resolve) - .catch(reject); - - this._syncInterval = setInterval(() => { - const promise = this.calculateDrift(); - - if (_.isFunction(onRecalculateDriftCb)) { - onRecalculateDriftCb(promise); - } - }, interval); - }); - } - - endTimeSync() { - clearInterval(this._syncInterval); - this._drift = 0; - this._syncInterval = 0; - } - - // Public APIs - ping(callback) { - return this._makeRequest({}, callback, 'api/v1/ping'); - } - - time(callback) { - return this._makeRequest({}, callback, 'api/v1/time'); - } - - depth(query = {}, callback) { - if (_.isString(query)) { - query = { symbol: query }; - } - - return this._makeRequest(query, callback, 'api/v1/depth'); - } - - trades(query = {}, callback) { - if (_.isString(query)) { - query = { symbol: query }; - } - - return this._makeRequest(query, callback, 'api/v1/trades'); - } - - historicalTrades(query = {}, callback) { - if (_.isString(query)) { - query = { symbol: query }; - } - - return this._makeRequest(query, callback, 'api/v1/historicalTrades', 'API-KEY'); - } - - aggTrades(query = {}, callback) { - if (_.isString(query)) { - query = { symbol: query }; - } - - return this._makeRequest(query, callback, 'api/v1/aggTrades'); - } - - exchangeInfo(callback) { - return this._makeRequest({}, callback, 'api/v1/exchangeInfo'); - } - - klines(query = {}, callback) { - return this._makeRequest(query, callback, 'api/v1/klines'); - } - - ticker24hr(query = {}, callback) { - if (_.isString(query)) { - query = { symbol: query }; - } - - return this._makeRequest(query, callback, 'api/v1/ticker/24hr'); - } - - tickerPrice(query = {}, callback) { - if (_.isString(query)) { - query = { symbol: query }; - } - - return this._makeRequest(query, callback, 'api/v3/ticker/price'); - } - - bookTicker(query = {}, callback) { - if (_.isString(query)) { - query = { symbol: query }; - } - - return this._makeRequest(query, callback, 'api/v3/ticker/bookTicker'); - } - - allBookTickers(callback) { - return this._makeRequest({}, callback, 'api/v1/ticker/allBookTickers'); - } - - allPrices(callback) { - return this._makeRequest({}, callback, 'api/v1/ticker/allPrices'); - } - - // Private APIs - newOrder(query = {}, callback) { - this._setTimestamp(query); - return this._makeRequest(query, callback, 'api/v3/order', 'SIGNED', 'POST'); - } - - testOrder(query = {}, callback) { - this._setTimestamp(query); - return this._makeRequest(query, callback, 'api/v3/order/test', 'SIGNED', 'POST'); - } - - queryOrder(query = {}, callback) { - this._setTimestamp(query); - return this._makeRequest(query, callback, 'api/v3/order', 'SIGNED'); - } - - cancelOrder(query = {}, callback) { - this._setTimestamp(query); - return this._makeRequest(query, callback, 'api/v3/order', 'SIGNED', 'DELETE'); - } - - openOrders(query = {}, callback) { - if (_.isString(query)) { - query = { symbol: query }; - } - this._setTimestamp(query); - return this._makeRequest(query, callback, 'api/v3/openOrders', 'SIGNED'); - } - - allOrders(query = {}, callback) { - if (_.isString(query)) { - query = { symbol: query }; - } - this._setTimestamp(query); - return this._makeRequest(query, callback, 'api/v3/allOrders', 'SIGNED'); - } - - account(query = {}, callback) { - if (_.isFunction(query)) { - callback = query; - query = {}; - } - this._setTimestamp(query); - return this._makeRequest(query, callback, 'api/v3/account', 'SIGNED'); - } - - myTrades(query = {}, callback) { - if (_.isString(query)) { - query = { symbol: query }; - } - this._setTimestamp(query); - return this._makeRequest(query, callback, 'api/v3/myTrades', 'SIGNED'); - } - - withdraw(query = {}, callback) { - this._setTimestamp(query); - return this._makeRequest(query, callback, 'wapi/v3/withdraw.html', 'SIGNED', 'POST'); - } - - depositHistory(query = {}, callback) { - if (_.isString(query)) { - query = { asset: query }; - } - this._setTimestamp(query); - return this._makeRequest(query, callback, 'wapi/v3/depositHistory.html', 'SIGNED'); - } - - withdrawHistory(query = {}, callback) { - if (_.isString(query)) { - query = { asset: query }; - } - this._setTimestamp(query); - return this._makeRequest(query, callback, 'wapi/v3/withdrawHistory.html', 'SIGNED'); - } - - depositAddress(query = {}, callback) { - if (_.isString(query)) { - query = { asset: query }; - } - this._setTimestamp(query); - return this._makeRequest(query, callback, 'wapi/v3/depositAddress.html', 'SIGNED'); - } - - accountStatus(callback) { - const query = {}; - this._setTimestamp(query); - return this._makeRequest(query, callback, 'wapi/v3/accountStatus.html', 'SIGNED'); - } - - startUserDataStream(callback) { - return this._makeRequest({}, callback, 'api/v1/userDataStream', 'API-KEY', 'POST'); - } - - keepAliveUserDataStream(query = {}, callback) { - return this._makeRequest(query, callback, 'api/v1/userDataStream', 'API-KEY', 'PUT'); - } - - closeUserDataStream(query = {}, callback) { - return this._makeRequest(query, callback, 'api/v1/userDataStream', 'API-KEY', 'DELETE'); - } -} - -module.exports = BinanceRest; \ No newline at end of file diff --git a/exchange/wrappers/binanceClient.js b/exchange/wrappers/binanceClient.js deleted file mode 100644 index a46ca7d24..000000000 --- a/exchange/wrappers/binanceClient.js +++ /dev/null @@ -1,360 +0,0 @@ -exports.newAPIClient = function newAPIClient(pKey, pSecret, logger) { - - /* - /* ATENTION: This Library is used both a the cloud (AACloud) and also at the AAWeb on the server side without any modifications. - /* There is a second version, stripped of all the inner functionality that runs at AAWeb browser side, which channels the requests to the server side one. - */ - - const FULL_LOG = true; - const LOG_FILE_CONTENT = true; - const MODULE_NAME = "binanceClient"; - - const retry = require('../exchangeUtils').retry; - const includes = require('../exchangeUtils').includes; - const _ = require('lodash'); - const Binance = require("./binance"); - const exchangeProperties = require('./poloniexProperties.json'); - - const recoverableErrors = [ - 'SOCKETTIMEDOUT', - 'TIMEDOUT', - 'CONNRESET', - 'CONNREFUSED', - 'NOTFOUND', - 'Error -1021', - 'Response code 429', - 'Response code 5', - 'ETIMEDOUT' - ]; - - let API = new Binance({ - key: pKey, - secret: pSecret, - timeout: 15000, - recvWindow: 60000, - disableBeautification: false, - handleDrift: true, - }); - - let thisObject = { - getTicker: getTicker, - getOpenPositions: getOpenPositions, - getExecutedTrades: getExecutedTrades, - buy: buy, - sell: sell, - movePosition: movePosition, - getPublicTradeHistory: getPublicTradeHistory, - getExchangeProperties: getExchangeProperties, - isValidPrice: isValidPrice, - isValidLot: isValidLot - }; - - return thisObject; - - function joinCurrencies(currencyA, currencyB) { - // If only one arg, then return the first - if (typeof currencyB !== 'string') { - return currencyA; - } - - return currencyB + '' + currencyA; - } - - /* - * Returns the properties for this exchange - */ - function getExchangeProperties() { - return exchangeProperties; - } - - function truncDecimals(pFloatValue) { - - let decimals = 6; - - return parseFloat(parseFloat(pFloatValue).toFixed(decimals)); - - } - - /* - * Returns the price for a given pair of assets. - * The object returned is an array of trades: - * ticker = { - * bid, Number - * ask, Number - * last Number - * }; - */ - function getTicker(pMarket, callBack) { - - let market = joinCurrencies(pMarket.assetA, pMarket.assetB); - const handle = (err, response) => { - let ticker; - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - ticker = { - bid: Number(response.bidPrice), - ask: Number(response.askPrice), - last: Number(response.lastPrice) - }; - } - callBack(err, ticker); - }; - - const fetch = next => API.ticker24hr(market, analizeResponse(next)); - - retry(null, fetch, handle); - } - - /* - * Returns the open positions ath the exchange for a given market and user account. - * The object returned is an array of positions: - * position = { - * id, - * type, - * rate, Number - * amountA, Number - * amountB, Number - * fee, (not required) Number - * datetime - * }; - */ - function getOpenPositions(pMarket, callBack) { - - let market = joinCurrencies(pMarket.assetA, pMarket.assetB); - const handle = (err, response) => { - let exchangePositions = []; - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - for (let i = 0; i < response.length; i++) { - let openPosition = { - id: response[i].orderId, - type: response[i].side.toLowerCase(), - rate: Number(response[i].price), - amountA: truncDecimals(response[i].origQty * response[i].price), - amountB: Number(response[i].origQty), - date: (new Date(response[i].time)).valueOf() - }; - exchangePositions.push(openPosition); - } - } - callBack(err, exchangePositions); - }; - - const fetch = next => API.openOrders(market, analizeResponse(next)); - - retry(null, fetch, handle); - } - - /* - * Returns the trades for a given order number. - * The object returned is an array of positions: - * position = { - * id, - * type, - * rate, Number - * amountA, Number - * amountB, Number - * fee, Number - * datetime - * }; - */ - function getExecutedTrades(pPositionId, callBack) { - - let market = joinCurrencies(global.MARKET.assetA, global.MARKET.assetB); - const handle = (err, response) => { - let exchangeTrades = []; - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - for (let i = 0; i < response.length; i++) { - if (response[i].orderId === pPositionId) { - let type = "sell" - if (response[i].isBuyer === true) { - type = "buy"; - } - let trade = { - id: response[i].orderId, - type: type, - rate: Number(response[i].price), - amountA: truncDecimals(response[i].qty * response[i].price), - amountB: Number(response[i].qty), - fee: Number(response[i].commission), - date: (new Date(response[i].time)).valueOf() - }; - exchangeTrades.push(trade); - break; - } - } - } - callBack(err, exchangeTrades); - }; - - const fetch = next => API.myTrades(market, analizeResponse(next)); - - retry(null, fetch, handle); - } - - /* - * Creates a new buy order. - * The orderNumber is returned. - */ - function buy(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) { - - var parameters = { - symbol: joinCurrencies(pCurrencyA, pCurrencyB), - side: 'BUY', - type: 'LIMIT', - quantity: pAmount, - price: pRate, - timeInForce: 'GTC' - }; - const handle = (err, response) => { - let orderNumber; - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - orderNumber = response.orderId; - } - callBack(err, orderNumber); - }; - - const fetch = next => API.newOrder(parameters, analizeResponse(next)); - - retry(null, fetch, handle); - - } - - /* - * Creates a new sell order. - * The orderNumber is returned. String - */ - function sell(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) { - - var parameters = { - symbol: joinCurrencies(pCurrencyA, pCurrencyB), - side: 'SELL', - type: 'LIMIT', - quantity: pAmount, - price: pRate, - timeInForce: 'GTC' - }; - const handle = (err, response) => { - let orderNumber; - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - orderNumber = response.orderId; - } - callBack(err, orderNumber); - }; - - const fetch = next => API.newOrder(parameters, analizeResponse(next)); - - retry(null, fetch, handle); - } - - /* //TODO Complete partial orders - * Move an existing position to the new rate. - * The new orderNumber is returned. String - */ - function movePosition(pPosition, pNewRate, pNewAmountB, callBack) { - - var parameters = { - symbol: joinCurrencies(global.MARKET.assetA, global.MARKET.assetB), - orderId: pPosition.id - }; - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] moveOrder -> Step1 - Cancelling Position: " + JSON.stringify(pPosition)); } - - const handle = (err, response) => { - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] moveOrder -> Step1 Complete - Position Cancelled. Proceeding to put the new position."); } - - if (position.type === "buy") - thisObject.buy(global.MARKET.assetA, global.MARKET.assetB, pNewRate, pNewAmountB, callBack); - else - thisObject.sell(global.MARKET.assetA, global.MARKET.assetB, pNewRate, pNewAmountB, callBack); - } else { - callBack(err); - } - }; - - const fetch = next => API.cancelOrder(parameters, analizeResponse(next)); - - retry(null, fetch, handle); - } - - /* //TODO Pending Review - * Returns all the trade history from the Exchange since startTime to endTime orderd by tradeId. - * It's possible that the exchange doesn't support this method. - * The object returned is an array of trades: - * trade = { - * tradeIdAtExchange, - * marketIdAtExchange, - * type, - * rate, Number - * amountA, Number - * amountB, Number - * datetime - * }; - */ - function getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack) { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] getPublicTradeHistory -> Not implemented yet."); } - callBack(global.DEFAULT_FAIL_RESPONSE); - } - - function isValidPrice(price) { - return price >= market.minimalOrder.price; - } - - function isValidLot(price, amount) { - return amount * price >= market.minimalOrder.order; - } - - function analizeResponse(callBack) { - - return (exchangeErr, exchangeResponse) => { - let error; - - /* This function analizes the different situations we might encounter trying to access Poloniex and returns appropiate standard errors. */ - - let stringExchangeErr = JSON.stringify(exchangeErr); - let stringExchangeResponse = JSON.stringify(exchangeResponse); - - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeErr = " + stringExchangeErr); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeResponse = " + stringExchangeResponse); } - - if (exchangeErr) { - error = global.DEFAULT_FAIL_RESPONSE; - } else if (!exchangeResponse) { - error = { - result: global.DEFAULT_FAIL_RESPONSE.result, - message: 'Empty response' - }; - } else if (includes(exchangeResponse.error, [''])) { - error = { - result: global.DEFAULT_FAIL_RESPONSE.result, - message: exchangeResponse - }; - } else if (includes(exchangeResponse.error, ['Order does not exist.'])) { - error = { - result: global.CUSTOM_OK_RESPONSE.result, - message: exchangeResponse.error - }; - } else if (exchangeResponse.error) { - error = { - result: global.DEFAULT_FAIL_RESPONSE.result, - message: exchangeResponse.error - }; - } - - if (error) { - if (includes(error.message, recoverableErrors)) { - error.notFatal = true; - } - } - - return callBack(error, exchangeResponse); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] analizeResponse -> err.message = " + err.message); - return callBack(global.DEFAULT_FAIL_RESPONSE, exchangeResponse); - } - } - } - -} diff --git a/exchange/wrappers/binanceProperties.json b/exchange/wrappers/binanceProperties.json deleted file mode 100644 index ad4438de0..000000000 --- a/exchange/wrappers/binanceProperties.json +++ /dev/null @@ -1,4594 +0,0 @@ -{ - "assets": [ - "NULS", - "VEN", - "BNB", - "NEO", - "LINK", - "SALT", - "IOTA", - "ETC", - "AST", - "KNC", - "WTC", - "SNGLS", - "EOS", - "SNT", - "MCO", - "BTC", - "OAX", - "OMG", - "GAS", - "BQX", - "QTUM", - "BNT", - "DNT", - "ICN", - "SNM", - "STRAT", - "ZRX", - "FUN", - "LTC", - "ETH", - "XVG", - "BCC", - "ADA", - "ADX", - "AE", - "AGI", - "AION", - "AMB", - "APPC", - "ARK", - "ARN", - "BAT", - "BCD", - "BCN", - "BCPT", - "BLZ", - "BRD", - "BTG", - "BTS", - "CDT", - "CHAT", - "CLOAK", - "CMT", - "CND", - "CVC", - "DASH", - "DATA", - "DENT", - "DGD", - "DLT", - "EDO", - "ELF", - "ENG", - "ENJ", - "EVX", - "FUEL", - "GNT", - "GRS", - "GTO", - "GVT", - "GXS", - "HSR", - "ICX", - "INS", - "IOST", - "IOTX", - "KEY", - "KMD", - "LEND", - "LOOM", - "LRC", - "LSK", - "LUN", - "MANA", - "MDA", - "MFT", - "MOD", - "MTH", - "MTL", - "NANO", - "NAS", - "NAV", - "NCASH", - "NEBL", - "NPXS", - "NXS", - "ONT", - "OST", - "PIVX", - "POA", - "POE", - "POWR", - "PPT", - "QKC", - "QLC", - "QSP", - "RCN", - "RDN", - "REP", - "REQ", - "RLC", - "RPX", - "SC", - "SKY", - "STEEM", - "STORJ", - "STORM", - "SUB", - "SYS", - "THETA", - "TNB", - "TNT", - "TRIG", - "TRX", - "TUSD", - "VIA", - "VIB", - "VIBE", - "WABI", - "WAN", - "WAVES", - "WINGS", - "WPR", - "XEM", - "XLM", - "XMR", - "XRP", - "XZC", - "YOYO", - "ZEC", - "ZEN", - "ZIL" - ], - "currencies": [ - "BNB", - "BTC", - "ETH", - "USDT" - ], - "markets": [ - { - "pair": [ - "BNB", - "NULS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BNB", - "VEN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.0001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "BNB" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "BTC", - "NULS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "BTC", - "NEO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "NULS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "LINK" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "BTC", - "SALT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "BTC", - "IOTA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "BTC", - "ETC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "AST" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-7, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "KNC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "BTC", - "WTC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "BTC", - "SNGLS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "EOS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "ETH", - "SNT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "ETH", - "MCO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "USDT", - "BTC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.000001, - "price": 0.01, - "order": 10 - } - }, - { - "pair": [ - "ETH", - "OAX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-7, - "order": 0.01 - } - }, - { - "pair": [ - "ETH", - "OMG" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "GAS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "BQX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-7, - "order": 0.01 - } - }, - { - "pair": [ - "ETH", - "WTC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "ETH", - "QTUM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "ETH", - "BNT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "ETH", - "DNT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "ETH", - "ICN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-7, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "SNM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "SNM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "ETH", - "SNGLS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "BQX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "NEO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "ETH", - "KNC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-7, - "order": 0.01 - } - }, - { - "pair": [ - "ETH", - "STRAT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "ETH", - "ZRX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "QTUM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "FUN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "LTC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "LINK" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "ETH" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "XVG" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "STRAT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "BTC", - "ZRX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "IOTA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "BCC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "BTC", - "OMG" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "BTC", - "MCO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "SALT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "ADA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "ADA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "ADA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "USDT", - "ADA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.1, - "price": 0.00001, - "order": 10 - } - }, - { - "pair": [ - "BNB", - "ADX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "ADX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "ADX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-7, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "AE" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "AE" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "AE" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "AGI" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "AGI" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "AGI" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "AION" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "AION" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "AION" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "AMB" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "AMB" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "AMB" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "APPC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "APPC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "APPC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-7, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "ARK" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "ARK" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "ARN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "ARN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "AST" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "BNB", - "BAT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "BAT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "BAT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "BCC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.00001, - "price": 0.01, - "order": 1 - } - }, - { - "pair": [ - "ETH", - "BCC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.00001, - "order": 0.01 - } - }, - { - "pair": [ - "USDT", - "BCC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.00001, - "price": 0.01, - "order": 10 - } - }, - { - "pair": [ - "BTC", - "BCD" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "BCD" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.00001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "BCN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 0.000001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "BCN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "BCN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "BCPT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "BCPT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "BCPT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "BLZ" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "BLZ" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "BLZ" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "ETH", - "BNB" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "BNT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "BNB", - "BRD" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "BRD" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "BRD" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-7, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "BTG" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "BTG" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "BTS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "BTS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "BTS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "CDT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "CDT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "CHAT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "CHAT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "CLOAK" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "CLOAK" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "CMT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "CMT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "CMT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "CND" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 0.000001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "CND" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "CND" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "CVC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "CVC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "CVC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "DASH" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "DASH" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.00001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "DATA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "DATA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "DENT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "DENT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "DGD" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "DGD" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.00001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "DLT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "DLT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "DLT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "DNT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "BTC", - "EDO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "EDO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "ELF" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "ELF" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "ENG" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "ENG" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-7, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "ENJ" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 0.000001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "ENJ" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "ENJ" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "EOS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.0001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "EOS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "USDT", - "EOS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.0001, - "order": 10 - } - }, - { - "pair": [ - "BNB", - "ETC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.0001, - "order": 1 - } - }, - { - "pair": [ - "ETH", - "ETC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "USDT", - "ETC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.0001, - "order": 10 - } - }, - { - "pair": [ - "BTC", - "EVX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "EVX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-7, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "FUEL" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "FUEL" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "FUN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "BNB", - "GNT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "GNT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "GNT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "GRS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "GRS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "GTO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "GTO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "GTO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "GVT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "GVT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "GXS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "GXS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "HSR" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "HSR" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "ICN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "BNB", - "ICX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "ICX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "ICX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "USDT", - "ICX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.0001, - "order": 10 - } - }, - { - "pair": [ - "BTC", - "INS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "INS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "IOST" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "IOST" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "IOTA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "USDT", - "IOTA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.0001, - "order": 10 - } - }, - { - "pair": [ - "BTC", - "IOTX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "IOTX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "KEY" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "KEY" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "KMD" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "KMD" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "LEND" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "LEND" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "LOOM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "LOOM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "LOOM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "LRC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "LRC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "LSK" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.0001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "LSK" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "LSK" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "LTC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.00001, - "price": 0.01, - "order": 1 - } - }, - { - "pair": [ - "ETH", - "LTC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.00001, - "order": 0.01 - } - }, - { - "pair": [ - "USDT", - "LTC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.00001, - "price": 0.01, - "order": 10 - } - }, - { - "pair": [ - "BTC", - "LUN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "LUN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "MANA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "MANA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "MCO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "MDA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "MDA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-7, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "MFT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 0.000001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "MFT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "MFT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "MOD" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "MOD" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "MTH" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "MTH" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "MTL" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "MTL" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "NANO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.0001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "NANO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "NANO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "NAS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "NAS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "NAS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "NAV" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "NAV" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "NAV" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "NCASH" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 0.000001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "NCASH" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "NCASH" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "NEBL" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "NEBL" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "NEBL" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "NEO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.001, - "order": 1 - } - }, - { - "pair": [ - "USDT", - "NEO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.001, - "order": 10 - } - }, - { - "pair": [ - "BTC", - "NPXS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "NPXS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "NXS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.0001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "NXS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "NXS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "OAX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "BNB", - "ONT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "ONT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "ONT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "USDT", - "ONT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.001, - "order": 10 - } - }, - { - "pair": [ - "BNB", - "OST" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 0.000001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "OST" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "OST" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "PIVX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "PIVX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "PIVX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "POA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "POA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "POA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "POE" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "POE" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "POWR" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "POWR" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "POWR" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "PPT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "PPT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "QKC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "QKC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "QLC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 0.000001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "QLC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "QLC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "QSP" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 0.000001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "QSP" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "QSP" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "QTUM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "USDT", - "QTUM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.001, - "order": 10 - } - }, - { - "pair": [ - "BNB", - "RCN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 0.000001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "RCN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "RCN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "RDN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "RDN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "RDN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-7, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "REP" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "REP" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "REP" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.00001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "REQ" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "REQ" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "RLC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "RLC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "RLC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "RPX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 0.000001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "RPX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "RPX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "SC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 0.000001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "SC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "SC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "SKY" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "SKY" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "SKY" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.00001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "SNT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "BNB", - "STEEM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "STEEM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "STEEM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "STORJ" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "STORJ" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-7, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "STORM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 0.000001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "STORM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "STORM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "SUB" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "SUB" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "SYS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "SYS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "SYS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "THETA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "THETA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "THETA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "TNB" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "TNB" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "TNT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "TNT" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "TRIG" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "TRIG" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "TRIG" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "TRX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "TRX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "USDT", - "TRX" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.1, - "price": 0.00001, - "order": 10 - } - }, - { - "pair": [ - "BNB", - "TUSD" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "TUSD" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "TUSD" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "USDT", - "TUSD" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.0001, - "order": 10 - } - }, - { - "pair": [ - "BTC", - "VEN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "VEN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "USDT", - "VEN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.0001, - "order": 10 - } - }, - { - "pair": [ - "BNB", - "VIA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "VIA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "VIA" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "VIB" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "BTC", - "VIBE" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "VIBE" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-7, - "order": 0.01 - } - }, - { - "pair": [ - "ETH", - "VIB" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "WABI" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "WABI" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "WABI" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "WAN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "WAN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "WAN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "WAVES" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.0001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "WAVES" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 1e-7, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "WAVES" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "WINGS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "WINGS" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-7, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "WPR" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "WPR" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "WTC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.0001, - "order": 1 - } - }, - { - "pair": [ - "BNB", - "XEM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "XEM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "XEM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "XLM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "XLM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "XLM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "USDT", - "XLM" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 10 - } - }, - { - "pair": [ - "BTC", - "XMR" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "XMR" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.00001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "XRP" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.00001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "XRP" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "XRP" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "USDT", - "XRP" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.1, - "price": 0.00001, - "order": 10 - } - }, - { - "pair": [ - "BTC", - "XVG" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "BNB", - "XZC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "XZC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "XZC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.000001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "YOYO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 0.000001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "YOYO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "YOYO" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "BTC", - "ZEC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "ZEC" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.00001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "ZEN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "ZEN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.000001, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "ZEN" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.001, - "price": 0.00001, - "order": 0.01 - } - }, - { - "pair": [ - "BNB", - "ZIL" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 0.000001, - "order": 1 - } - }, - { - "pair": [ - "BTC", - "ZIL" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.001 - } - }, - { - "pair": [ - "ETH", - "ZIL" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 1, - "price": 1e-8, - "order": 0.01 - } - }, - { - "pair": [ - "USDT", - "BNB" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.01, - "price": 0.0001, - "order": 10 - } - }, - { - "pair": [ - "USDT", - "ETH" - ], - "maxDecimals": 6, - "minimalOrder": { - "amount": 0.00001, - "price": 0.01, - "order": 10 - } - } - ] -} \ No newline at end of file diff --git a/exchange/wrappers/poloniex.js b/exchange/wrappers/poloniex.js deleted file mode 100644 index 9a1a32b41..000000000 --- a/exchange/wrappers/poloniex.js +++ /dev/null @@ -1,440 +0,0 @@ -// Source: https://github.com/premasagar/poloniex.js -// Documentation: https://poloniex.com/support/api/ - -module.exports = (function () { - 'use strict'; - - // Module dependencies - var request = require('request'), - nonce = require('nonce')(); - - // Constants - var version = '0.0.9', - PUBLIC_API_URL = 'https://poloniex.com/public', - PRIVATE_API_URL = 'https://poloniex.com/tradingApi', - USER_AGENT = 'poloniex.js ' + version; - //USER_AGENT = 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0' - - // Helper methods - function joinCurrencies(currencyA, currencyB) { - // If only one arg, then return the first - if (typeof currencyB !== 'string') { - return currencyA; - } - - return currencyA + '_' + currencyB; - } - - // Constructor - function Poloniex(keyVaultAPI) { - // Generate headers signed by this user's key and secret. - // The secret is encapsulated and never exposed - this._getPrivateHeaders = function (parameters, next) { - var paramString, signature; - - // Convert to `arg1=foo&arg2=bar` - paramString = Object.keys(parameters).map(function (param) { - return encodeURIComponent(param) + '=' + encodeURIComponent(parameters[param]); - }).join('&'); - - keyVaultAPI.signTransaction(paramString, next); - }; - } - - // Currently, this fails with `Error: CERT_UNTRUSTED` - // Poloniex.STRICT_SSL can be set to `false` to avoid this. Use with caution. - // Will be removed in future, once this is resolved. - Poloniex.STRICT_SSL = true; - - // Customisable user agent string - Poloniex.USER_AGENT = USER_AGENT; - - // Prototype - Poloniex.prototype = { - constructor: Poloniex, - - // Make an API request - _request: function (options, callback) { - if (!('headers' in options)) { - options.headers = {}; - } - - options.json = true; - options.headers['User-Agent'] = Poloniex.USER_AGENT; - options.strictSSL = Poloniex.STRICT_SSL; - options.timeout = 60 * 1000; - - request(options, function (err, response, body) { - // Empty response - if (!err && (typeof body === 'undefined' || body === null)) { - err = 'Empty response'; - } - - callback(err, body); - }); - - return this; - }, - - // Make a public API request - _public: function (command, parameters, callback) { - var options; - - if (typeof parameters === 'function') { - callback = parameters; - parameters = {}; - } - - parameters || (parameters = {}); - parameters.command = command; - options = { - method: 'GET', - url: PUBLIC_API_URL, - qs: parameters - }; - - options.qs.command = command; - return this._request(options, callback); - }, - - // Make a private API request - _private: function (command, parameters, callback) { - var options; - - if (typeof parameters === 'function') { - callback = parameters; - parameters = {}; - } - - parameters || (parameters = {}); - parameters.command = command; - parameters.nonce = nonce(); - - options = { - method: 'POST', - url: PRIVATE_API_URL, - form: parameters - }; - - let headers = this._getPrivateHeaders(parameters, next) - - let thisObject = this - - function next(pHeaders, error) { - if (!error) { - options.headers = pHeaders; - return thisObject._request(options, callback); - } else { - callback(error); - } - - } - }, - - ///// - // PUBLIC METHODS - - returnTicker: function (callback) { - return this._public('returnTicker', callback); - }, - - return24hVolume: function (callback) { - return this._public('return24hVolume', callback); - }, - - returnOrderBook: function (currencyA, currencyB, callback) { - var currencyPair; - - if (typeof currencyB === 'function') { - currencyPair = currencyA; - callback = currencyB; - currencyB = null; - } - - else { - currencyPair = joinCurrencies(currencyA, currencyB); - } - - var parameters = { - currencyPair: currencyPair - }; - - return this._public('returnOrderBook', parameters, callback); - }, - - returnChartData: function (currencyA, currencyB, period, start, end, callback) { - var parameters = { - currencyPair: joinCurrencies(currencyA, currencyB), - period: period, - start: start, - end: end - }; - - return this._public('returnChartData', parameters, callback); - }, - - returnCurrencies: function (callback) { - return this._public('returnCurrencies', callback); - }, - - returnLoanOrders: function (currency, callback) { - return this._public('returnLoanOrders', { currency: currency }, callback); - }, - - returnTradeHistory: function (currencyA, currencyB, start, end, callback) { - if (arguments.length < 5) { - callback = start; - start = Date.now() / 1000 - 60 * 60; - end = Date.now() / 1000 + 60 * 60; // Some buffer in case of client/server time out of sync. - } - - var parameters = { - currencyPair: joinCurrencies(currencyA, currencyB), - start: start, - end: end - }; - - return this._public('returnTradeHistory', parameters, callback); - }, - - ///// - // PRIVATE METHODS - - returnBalances: function (callback) { - return this._private('returnBalances', {}, callback); - }, - - returnCompleteBalances: function (account, callback) { - var parameters = {}; - - if (typeof account === 'function') { - callback = account; - } - - else if (typeof account === 'string' && !!account) { - parameters.account = account; - } - - return this._private('returnCompleteBalances', parameters, callback); - }, - - returnDepositAddresses: function (callback) { - return this._private('returnDepositAddresses', {}, callback); - }, - - generateNewAddress: function (currency, callback) { - return this._private('generateNewAddress', { currency: currency }, callback); - }, - - returnDepositsWithdrawals: function (start, end, callback) { - return this._private('returnDepositsWithdrawals', { start: start, end: end }, callback); - }, - - // can be called with `returnOpenOrders('all', callback)` - returnOpenOrders: function (currencyA, currencyB, callback) { - var currencyPair; - - if (typeof currencyB === 'function') { - currencyPair = currencyA; - callback = currencyB; - currencyB = null; - } - - else { - currencyPair = joinCurrencies(currencyA, currencyB); - } - - var parameters = { - currencyPair: currencyPair - }; - - return this._private('returnOpenOrders', parameters, callback); - }, - - returnOrderTrades: function (orderNumber, callback) { - var parameters = { - orderNumber: orderNumber - }; - - return this._private('returnOrderTrades', parameters, callback); - }, - - buy: function (currencyA, currencyB, rate, amount, callback) { - var parameters = { - currencyPair: joinCurrencies(currencyA, currencyB), - rate: rate, - amount: amount - }; - - return this._private('buy', parameters, callback); - }, - - sell: function (currencyA, currencyB, rate, amount, callback) { - var parameters = { - currencyPair: joinCurrencies(currencyA, currencyB), - rate: rate, - amount: amount - }; - - return this._private('sell', parameters, callback); - }, - - cancelOrder: function (currencyA, currencyB, orderNumber, callback) { - var parameters = { - currencyPair: joinCurrencies(currencyA, currencyB), - orderNumber: orderNumber - }; - - return this._private('cancelOrder', parameters, callback); - }, - - moveOrder: function (orderNumber, rate, amount, callback) { - var parameters = { - orderNumber: orderNumber, - rate: rate, - amount: amount ? amount : null - }; - - return this._private('moveOrder', parameters, callback); - }, - - withdraw: function (currency, amount, address, callback) { - var parameters = { - currency: currency, - amount: amount, - address: address - }; - - return this._private('withdraw', parameters, callback); - }, - - returnFeeInfo: function (callback) { - return this._private('returnFeeInfo', {}, callback); - }, - - returnAvailableAccountBalances: function (account, callback) { - var parameters = {}; - - if (typeof account === 'function') { - callback = account; - } - - else if (typeof account === 'string' && !!account) { - parameters.account = account; - } - - return this._private('returnAvailableAccountBalances', parameters, callback); - }, - - returnTradableBalances: function (callback) { - return this._private('returnTradableBalances', {}, callback); - }, - - transferBalance: function (currency, amount, fromAccount, toAccount, callback) { - var parameters = { - currency: currency, - amount: amount, - fromAccount: fromAccount, - toAccount: toAccount - }; - - return this._private('transferBalance', parameters, callback); - }, - - returnMarginAccountSummary: function (callback) { - return this._private('returnMarginAccountSummary', {}, callback); - }, - - marginBuy: function (currencyA, currencyB, rate, amount, lendingRate, callback) { - var parameters = { - currencyPair: joinCurrencies(currencyA, currencyB), - rate: rate, - amount: amount, - lendingRate: lendingRate ? lendingRate : null - }; - - return this._private('marginBuy', parameters, callback); - }, - - marginSell: function (currencyA, currencyB, rate, amount, lendingRate, callback) { - var parameters = { - currencyPair: joinCurrencies(currencyA, currencyB), - rate: rate, - amount: amount, - lendingRate: lendingRate ? lendingRate : null - }; - - return this._private('marginSell', parameters, callback); - }, - - getMarginPosition: function (currencyA, currencyB, callback) { - var parameters = { - currencyPair: joinCurrencies(currencyA, currencyB) - }; - - return this._private('getMarginPosition', parameters, callback); - }, - - closeMarginPosition: function (currencyA, currencyB, callback) { - var parameters = { - currencyPair: joinCurrencies(currencyA, currencyB) - }; - - return this._private('closeMarginPosition', parameters, callback); - }, - - createLoanOffer: function (currency, amount, duration, autoRenew, lendingRate, callback) { - var parameters = { - currency: currency, - amount: amount, - duration: duration, - autoRenew: autoRenew, - lendingRate: lendingRate - }; - - return this._private('createLoanOffer', parameters, callback); - }, - - cancelLoanOffer: function (orderNumber, callback) { - var parameters = { - orderNumber: orderNumber - }; - - return this._private('cancelLoanOffer', parameters, callback); - }, - - returnOpenLoanOffers: function (callback) { - return this._private('returnOpenLoanOffers', {}, callback); - }, - - returnActiveLoans: function (callback) { - return this._private('returnActiveLoans', {}, callback); - }, - - returnLendingHistory: function (start, end, limit, callback) { - var parameters = { - start: start, - end: end, - limit: limit - }; - - return this._private('returnLendingHistory', parameters, callback); - }, - - toggleAutoRenew: function (orderNumber, callback) { - return this._private('toggleAutoRenew', { orderNumber: orderNumber }, callback); - } - - }; - - // Backwards Compatibility - Poloniex.prototype.getTicker = Poloniex.prototype.returnTicker; - Poloniex.prototype.get24hVolume = Poloniex.prototype.return24hVolume; - Poloniex.prototype.getOrderBook = Poloniex.prototype.returnOrderBook; - Poloniex.prototype.getTradeHistory = Poloniex.prototype.returnChartData; - Poloniex.prototype.myBalances = Poloniex.prototype.returnBalances; - Poloniex.prototype.myOpenOrders = Poloniex.prototype.returnOpenOrders; - Poloniex.prototype.myTradeHistory = Poloniex.prototype.returnTradeHistory; - - return Poloniex; -})(); diff --git a/exchange/wrappers/poloniexClient.js b/exchange/wrappers/poloniexClient.js deleted file mode 100644 index 7476728c1..000000000 --- a/exchange/wrappers/poloniexClient.js +++ /dev/null @@ -1,353 +0,0 @@ -exports.newAPIClient = function newAPIClient(keyVaultAPI, logger) { - - /* - /* ATENTION: This Library is used both a the cloud (AACloud) and also at the AAWeb on the server side without any modifications. - /* There is a second version, stripped of all the inner functionality that runs at AAWeb browser side, which channels the requests to the server side one. - */ - - const FULL_LOG = true; - const LOG_FILE_CONTENT = true; - const MODULE_NAME = "poloniexClient"; - - const retry = require('../exchangeUtils').retry; - const includes = require('../exchangeUtils').includes; - const _ = require('lodash'); - const Poloniex = require("./poloniex"); - const exchangeProperties = require('./poloniexProperties.json'); - - const recoverableErrors = [ - 'SOCKETTIMEDOUT', - 'TIMEDOUT', - 'CONNRESET', - 'CONNREFUSED', - 'NOTFOUND', - '429', - '522', - '504', - '503', - '500', - '502', - 'Empty response', - 'Please try again in a few minutes.', - 'Nonce must be greater than', - 'Internal error. Please try again.', - 'Connection timed out. Please try again.', - 'ENOTFOUND', - 'ECONNREFUSED', - 'CONNREFUSED', - 'NOTFOUND', - 'ESOCKETTIMEDOUT', - 'ECONNRESET', - 'Connection timed out', - 'Connection Error', - 'Order not found, or you are not the person who placed it.', - 'ETIMEDOUT' - ]; - - let API = new Poloniex(keyVaultAPI); - - let thisObject = { - getTicker: getTicker, - getOpenPositions: getOpenPositions, - getExecutedTrades: getExecutedTrades, - buy: buy, - sell: sell, - movePosition: movePosition, - getPublicTradeHistory: getPublicTradeHistory, - getExchangeProperties: getExchangeProperties, - isValidLot: isValidLot - }; - - return thisObject; - - function joinCurrencies(currencyA, currencyB) { - // If only one arg, then return the first - if (typeof currencyB !== 'string') { - return currencyA; - } - - return currencyA + '_' + currencyB; - } - - - /* - * Returns the properties for this exchange - */ - function getExchangeProperties() { - return exchangeProperties; - } - - /* - * Returns the price for a given pair of assets. - * The object returned is an array of trades: - * ticker = { - * bid, Number - * ask, Number - * last Number - * }; - */ - function getTicker(pMarket, callBack) { - - const handle = (err, response) => { - let ticker; - let market = joinCurrencies(pMarket.assetA, pMarket.assetB); - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - ticker = { - bid: Number(response[market].highestBid), - ask: Number(response[market].lowestAsk), - last: Number(response[market].last) - }; - } - callBack(err, ticker); - }; - - const fetch = next => API.getTicker(analizeResponse(next)); - - retry(null, fetch, handle); - } - - /* - * Returns the open positions ath the exchange for a given market and user account. - * The object returned is an array of positions: - * position = { - * id, - * type, - * rate, Number - * amountA, Number - * amountB, Number - * fee, (not required) Number - * datetime - * }; - */ - function getOpenPositions(pMarket, callBack) { - - const handle = (err, response) => { - let exchangePositions = []; - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - for (let i = 0; i < response.length; i++) { - let openPosition = { - id: response[i].orderNumber, - type: response[i].type, - rate: Number(response[i].rate), - amountA: Number(response[i].total), - amountB: Number(response[i].amount), - date: (new Date(response[i].time)).valueOf() - }; - exchangePositions.push(openPosition); - } - } - callBack(err, exchangePositions); - }; - - const fetch = next => API.returnOpenOrders(pMarket.assetA, pMarket.assetB, analizeResponse(next)); - - retry(null, fetch, handle); - } - - /* - * Returns the trades for a given order number. - * The object returned is an array of positions: - * position = { - * id, - * type, - * rate, Number - * amountA, Number - * amountB, Number - * fee, Number - * datetime - * }; - */ - function getExecutedTrades(pPositionId, callBack) { - - const handle = (err, response) => { - let trades = []; - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - for (let i = 0; i < response.length; i++) { - let trade = { - id: response[i].tradeID, - type: response[i].type, - rate: Number(response[i].rate), - amountA: Number(response[i].total), - amountB: Number(response[i].amount), - fee: Number(response[i].fee), - date: (new Date(response[i].date)).valueOf() - } - trades.push(trade); - } - } else if (err.result === global.CUSTOM_OK_RESPONSE.result) { - // No trades found at the exchange for the position, but returning empy trades object. - err = global.DEFAULT_OK_RESPONSE; - } - callBack(err, trades); - }; - - const fetch = next => API.returnOrderTrades(pPositionId, analizeResponse(next)); - - retry(null, fetch, handle); - } - - /* - * Creates a new buy order. - * The orderNumber is returned. String - */ - function buy(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) { - - const handle = (err, response) => { - let orderNumber; - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - orderNumber = response.orderNumber; - } - callBack(err, orderNumber); - }; - - const fetch = next => API.buy(pCurrencyA, pCurrencyB, pRate, pAmount, analizeResponse(next)); - - retry(null, fetch, handle); - - } - - /* - * Creates a new sell order. - * The orderNumber is returned. String - */ - function sell(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) { - - const handle = (err, response) => { - let orderNumber; - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - orderNumber = response.orderNumber; - } - callBack(err, orderNumber); - }; - - const fetch = next => API.sell(pCurrencyA, pCurrencyB, pRate, pAmount, analizeResponse(next)); - - retry(null, fetch, handle); - } - - /* - * Move an existing position to the new rate. - * The orderNumber is returned. String - */ - function movePosition(pPosition, pNewRate, pNewAmountB, callBack) { - - const handle = (err, response) => { - let orderNumber; - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - orderNumber = response.orderNumber; - } - callBack(err, orderNumber); - }; - - const fetch = next => API.moveOrder(pPosition.id, pNewRate, pNewAmountB, analizeResponse(next)); - - retry(null, fetch, handle); - } - - /* - * Returns all the trade history from the Exchange since startTime to endTime orderd by tradeId. - * It's possible that the exchange doesn't support this method. - * The object returned is an array of trades: - * trade = { - * tradeID, String - * globalTradeID, String - * type, String - * rate, Number - * amountA, Number - * amountB, Number - * date Date - * }; - */ - function getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack) { - - const handle = (err, response) => { - let trades = []; - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - for (let i = 0; i < response.length; i++) { - let trade = { - tradeID: response[i].tradeID, - globalTradeID: response[i].globalTradeID, - type: response[i].type, - rate: Number(response[i].rate), - total: Number(response[i].total), - amount: Number(response[i].amount), - date: new Date(response[i].date) - } - trades.push(trade); - } - } - callBack(err, trades); - }; - - const fetch = next => API.returnTradeHistory(assetA, assetB, startTime, endTime, analizeResponse(next)); - - retry(null, fetch, handle); - } - - function isValidLot(price, amount) { - return amount * price >= 0.0001; - } - - function analizeResponse(callBack) { - - return (exchangeErr, exchangeResponse) => { - let error; - - /* This function analizes the different situations we might encounter trying to access Poloniex and returns appropiate standard errors. */ - - let stringExchangeErr = JSON.stringify(exchangeErr); - let stringExchangeResponse = JSON.stringify(exchangeResponse); - - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeErr = " + stringExchangeErr); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeResponse = " + stringExchangeResponse); } - - if (exchangeErr) { - error = global.DEFAULT_FAIL_RESPONSE; - - if (includes(exchangeErr.code, recoverableErrors)) { - error.notFatal = true; - } - } else if (!exchangeResponse || exchangeResponse === undefined) { - error = { - result: global.DEFAULT_FAIL_RESPONSE.result, - message: 'Empty response', - notFatal: true - }; - } else if (includes(exchangeResponse.error, ['Please complete the security check to proceed.'])) { - error = { - result: global.DEFAULT_FAIL_RESPONSE.result, - message: 'The IP has been flagged by CloudFlare.' - }; - } else if (includes(exchangeResponse.error, [''])) { - error = { - result: global.DEFAULT_FAIL_RESPONSE.result, - message: exchangeResponse - }; - } else if (includes(exchangeResponse.error, ['Not enough'])) { - error = { - result: global.DEFAULT_RETRY_RESPONSE.result, - message: exchangeResponse.error - }; - } else if (includes(exchangeResponse.error, ['Order not found, or you are not the person who placed it.'])) { - error = { - result: global.CUSTOM_OK_RESPONSE.result, - message: exchangeResponse.error - }; - } else if (exchangeResponse.error) { - error = { - result: global.DEFAULT_FAIL_RESPONSE.result, - message: exchangeResponse.error - }; - } - - return callBack(error, exchangeResponse); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] analizeResponse -> err.message = " + err.message); - return callBack(global.DEFAULT_FAIL_RESPONSE, exchangeResponse); - } - } - } - -} diff --git a/exchange/wrappers/poloniexProperties.json b/exchange/wrappers/poloniexProperties.json deleted file mode 100644 index a5716ba3b..000000000 --- a/exchange/wrappers/poloniexProperties.json +++ /dev/null @@ -1,3513 +0,0 @@ -{ - "currencies": ["BTC", "ETH", "XMR", "USDT"], - "assets": [ - "1CR", "ABY", "AC", "ACH", "ADN", "AEON", "AERO", "AIR", "AMP", "APH", - "ARCH", "AUR", "AXIS", "BALLS", "BANK", "BBL", "BBR", "BCC", "BCH", "BCN", - "BCY", "BDC", "BDG", "BELA", "BITCNY", "BITS", "BITUSD", "BLK", "BLOCK", - "BLU", "BNS", "BONES", "BOST", "BTC", "BTCD", "BTCS", "BTM", "BTS", - "BURN", "BURST", "C2", "CACH", "CAI", "CC", "CCN", "CGA", "CHA", "CINNI", - "CLAM", "CNL", "CNMT", "CNOTE", "COMM", "CON", "CORG", "CRYPT", "CURE", - "CVC", "CYC", "DAO", "DASH", "DCR", "DGB", "DICE", "DIEM", "DIME", "DIS", "DNS", - "DOGE", "DRKC", "DRM", "DSH", "DVK", "EAC", "EBT", "ECC", "EFL", "EMC2", - "EMO", "ENC", "ETC", "ETH", "eTOK", "EXE", "EXP", "FAC", "FCN", "FCT", - "FIBRE", "FLAP", "FLDC", "FLO", "FLT", "FOX", "FRAC", "FRK", "FRQ", "GNO", - "FVZ", "FZ", "FZN", "GAME", "GAP", "GAS", "GDN", "GEMZ", "GEO", "GIAR", "GLB", - "GML", "GNS", "GNT", "GOLD", "GPC", "GPUC", "GRC", "GRCX", "GRS", "GUE", "H2O", - "HIRO", "HOT", "HUC", "HUGE", "HVC", "HYP", "HZ", "IFC", "INDEX", "IOC", - "ITC", "IXC", "JLH", "JPC", "JUG", "KDC", "KEY", "LBC", "LC", "LCL", - "LEAF", "LGC", "LOL", "LOVE", "LQD", "LSK", "LTBC", "LTC", "LTCX", - "MAID", "MAST", "MAX", "MCN", "MEC", "METH", "MIL", "MIN", "MINT", "MMC", - "MMNXT", "MMXIV", "MNTA", "MON", "MRC", "MRS", "MTS", "MUN", "MYR", - "MZC", "N5X", "NAS", "NAUT", "NAV", "NBT", "NEOS", "NL", "NMC", "NOBL", - "NOTE", "NOXT", "NRS", "NSR", "NTX", "NXT", "NXTI", "OMG", "OMNI", "OPAL", - "PAND", "PASC", "PAWN", "PIGGY", "PINK", "PLX", "PMC", "POT", "PPC", "PRC", - "PRT", "PTS", "Q2C", "QBK", "QCN", "QORA", "QTL", "RADS", "RBY", "RDD", "REP", - "RIC", "RZR", "SBD", "SC", "SDC", "SHIBE", "SHOPX", "SILK", "SJCX", - "SLR", "SMC", "SOC", "SPA", "SQL", "SRCC", "SRG", "SSD", "STEEM", "STR", - "SUM", "SUN", "SWARM", "SXC", "SYNC", "SYS", "TAC", "TOR", "TRUST", - "TWE", "UIS", "ULTC", "UNITY", "URO", "USDE", "USDT", "UTC", "UTIL", - "UVC", "VIA", "VOOT", "VOX", "VRC", "VTC", "WC", "WDC", "WIKI", "WOLF", - "X13", "XAI", "XAP", "XBC", "XC", "XCH", "XCN", "XCP", "XCR", "XDN", - "XDP", "XEM", "XHC", "XLB", "XMG", "XMR", "XPB", "XPM", "XRP", "XSI", - "XST", "XSV", "XUSD", "XVC", "XXC", "BCH", "YACC", "YANG", "YC", "YIN", "ZEC", - "ZRX" - ], - "markets": [ - { - "pair": [ - "BTC", - "1CR" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "ABY" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "AC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "ACH" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "ADN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "AEON" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "AERO" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "AIR" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "AMP" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "APH" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "ARCH" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "AUR" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "AXIS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BALLS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BANK" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BBL" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BBR" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BCC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BCN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BCH" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BCY" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BDC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BDG" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BELA" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BITCNY" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BITS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BITUSD" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BLK" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BLOCK" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BLU" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BNS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BONES" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BOST" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BTCD" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BTCS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BTM" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BTS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BURN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "BURST" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "C2" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CACH" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CAI" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CCN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CGA" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CHA" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CINNI" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CLAM" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CNL" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CNMT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CNOTE" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "COMM" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CON" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CORG" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CRYPT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CURE" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CVC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "CYC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "DAO" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "DASH" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "DCR" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "DGB" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "DICE" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "DIEM" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "DIME" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "DIS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "DNS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "DOGE" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "DRKC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "DRM" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "DSH" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "DVK" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "EAC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "EBT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "ECC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "EFL" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "EMC2" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "EMO" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "ENC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "ETC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "ETH" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "eTOK" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "EXE" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "EXP" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "FAC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "FCN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "FCT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "FIBRE" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "FLAP" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "FLDC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "FLO" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "FLT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "FOX" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "FRAC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "FRK" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "FRQ" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "FVZ" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "FZ" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "FZN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GAME" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GAP" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GAS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GDN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GEMZ" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GEO" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GIAR" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GLB" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GML" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GNS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GOLD" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GPC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GPUC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GRC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GRCX" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GRS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "GUE" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "H2O" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "HIRO" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "HOT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "HUC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "HUGE" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "HVC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "HYP" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "HZ" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "IFC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "INDEX" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "IOC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "ITC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "IXC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "JLH" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "JPC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "JUG" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "KDC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "KEY" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "LBC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "LC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "LCL" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "LEAF" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "LGC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "LOL" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "LOVE" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "LQD" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "LSK" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "LTBC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "LTC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "LTCX" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MAID" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MAST" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MAX" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MCN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MEC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "METH" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MIL" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MIN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MINT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MMC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MMNXT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MMXIV" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MNTA" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MON" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MRC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MRS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MTS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MUN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MYR" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "MZC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "N5X" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "NAS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "NAUT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "NAV" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "NBT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "NEOS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "NL" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "NMC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "NOBL" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "NOTE" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "NOXT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "NRS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "NSR" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "NTX" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "NXT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "NXTI" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "OMG" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "OMNI" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "OPAL" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "PAND" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "PASC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "PAWN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "PIGGY" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "PINK" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "PLX" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "PMC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "POT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "PPC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "PRC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "PRT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "PTS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "Q2C" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "QBK" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "QCN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "QORA" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "QTL" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "RADS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "RBY" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "RDD" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "REP" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "RIC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "RZR" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SBD" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SDC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SHIBE" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SHOPX" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SILK" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SJCX" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SLR" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SMC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SOC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SPA" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SQL" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SRCC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SRG" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SSD" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "STEEM" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "STR" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SUM" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SUN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SWARM" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SXC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SYNC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "SYS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "TAC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "TOR" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "TRUST" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "TWE" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "UIS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "ULTC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "UNITY" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "URO" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "USDE" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "USDT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "UTC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "UTIL" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "UVC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "VIA" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "VOOT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "VOX" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "VRC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "VTC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "WC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "WDC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "WIKI" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "WOLF" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "X13" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XAI" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XAP" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XBC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XCH" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XCN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XCP" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XCR" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XDN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XDP" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XEM" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XHC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XLB" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XMG" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XMR" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XPB" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XPM" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XRP" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XSI" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XST" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XSV" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XUSD" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XVC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "XXC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "YACC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "YANG" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "YC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "YIN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "ZEC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "BTC", - "ZRX" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "USDT", - "BTC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "USDT", - "BCH" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "USDT", - "DASH" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "USDT", - "ETC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "USDT", - "ETH" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "USDT", - "LTC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "USDT", - "NXT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "USDT", - "REP" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "USDT", - "STR" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "USDT", - "XMR" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "USDT", - "XRP" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "USDT", - "ZEC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "ETH", - "CVC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "ETH", - "ETC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "ETH", - "BCH" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "ETH", - "GAS" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "ETH", - "GNO" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "ETH", - "GNT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "ETH", - "LSK" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "ETH", - "OMG" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "ETH", - "REP" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "ETH", - "STEEM" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "ETH", - "ZEC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "ETH", - "ZRX" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "XMR", - "BCN" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "XMR", - "BLK" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "XMR", - "BTCD" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "XMR", - "DASH" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "XMR", - "LTC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "XMR", - "MAID" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "XMR", - "NXT" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - }, - { - "pair": [ - "XMR", - "ZEC" - ], - "maxDecimals": 8, - "minimalOrder": { - "amount": 0.0001, - "unit": "asset" - } - } - ] -} \ No newline at end of file From fd006adc6716cf6d5ecd9a01eb85014fae5b07c2 Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Sun, 10 Feb 2019 18:08:36 -0300 Subject: [PATCH 21/76] Upercase Exchange Folder --- Exchange/ExchangeAPI.js | 301 ++ Exchange/exchangeUtils.js | 100 + Exchange/wrappers/beautifier.js | 183 + Exchange/wrappers/binance.js | 368 ++ Exchange/wrappers/binanceClient.js | 360 ++ Exchange/wrappers/binanceProperties.json | 4594 +++++++++++++++++++++ Exchange/wrappers/poloniex.js | 440 ++ Exchange/wrappers/poloniexClient.js | 353 ++ Exchange/wrappers/poloniexProperties.json | 3513 ++++++++++++++++ 9 files changed, 10212 insertions(+) create mode 100644 Exchange/ExchangeAPI.js create mode 100644 Exchange/exchangeUtils.js create mode 100644 Exchange/wrappers/beautifier.js create mode 100644 Exchange/wrappers/binance.js create mode 100644 Exchange/wrappers/binanceClient.js create mode 100644 Exchange/wrappers/binanceProperties.json create mode 100644 Exchange/wrappers/poloniex.js create mode 100644 Exchange/wrappers/poloniexClient.js create mode 100644 Exchange/wrappers/poloniexProperties.json diff --git a/Exchange/ExchangeAPI.js b/Exchange/ExchangeAPI.js new file mode 100644 index 000000000..2ad5eddfd --- /dev/null +++ b/Exchange/ExchangeAPI.js @@ -0,0 +1,301 @@ +exports.newExchangeAPI = function newExchangeAPI(bot, logger) { + + /* + + This module allows trading bots to connect to the exchange and do trading operations on it. So far it can only work with Poloniex. + + */ + const _ = require('lodash') + const isValidOrder = require('./exchangeUtils').isValidOrder + const graphqlClient = require('graphql-client') + const appRoot = require('app-root-path') + const auth = require(`${appRoot}/utils/auth`) + + let MODULE_NAME = "Exchange API"; + + let thisObject = { + initialize: initialize, + getTicker: getTicker, + getOpenPositions: getOpenPositions, + getExecutedTrades: getExecutedTrades, + putPosition: putPosition, + movePosition: movePosition, + getPublicTradeHistory: getPublicTradeHistory, + getExchangeProperties: getExchangeProperties, + getMaxDecimalPositions: getMaxDecimalPositions + }; + + let apiClient; + + return thisObject; + + async function initialize(callBackFunction) { + try { + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } + + // TODO integrate with financial beings module to get the exchange + let botExchange = 'Poloniex'; + let exchange = botExchange.toLowerCase() + 'Client.js'; + let api = require('./wrappers/' + exchange); + + const accessToken = await auth.authenticate() + + let keyVaultAPI = createKeyVaultAPIClient(accessToken) + apiClient = api.newAPIClient(keyVaultAPI, logger); + + callBackFunction(global.DEFAULT_OK_RESPONSE); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function createKeyVaultAPIClient(authToken) { + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createKeyVaultAPIClient -> Entering function."); } + + const keyVaultAPI = graphqlClient({ + url: global.GATEWAY_ENDPOINT, + headers: { + Authorization: 'Bearer ' + authToken + } + }); + + keyVaultAPI.signTransaction = function (transaction, next) { + let variables = { + botId: bot.codeName, + transaction: transaction + } + + keyVaultAPI.query(` + mutation($botId: String, $transaction: String!){ + keyVault_SignTransaction(botId: $botId, transaction: $transaction){ + key, + signature, + date + } + }`, variables, function (req, res) { + if (res.status === 401) { + next(undefined, 'Error from graphql: Not authorized'); + } + }).then(res => { + if (res.errors) { + next(undefined, 'Error from graphql: ' + res.errors); + } else { + let signature = { + Key: res.data.keyVault_SignTransaction.key, + Sign: res.data.keyVault_SignTransaction.signature + } + next(signature) + } + }).catch(error => { + next(undefined, 'Error signing the message on the key vault: ' + error.message); + }); + } + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createKeyVaultAPIClient -> Returning graphql client."); } + + return keyVaultAPI; + } + + /* + * Position Object = { + * id, String + * type, String + * rate, Number + * amountA, Number + * amountB, Number + * fee, Number + * datetime Date + * }; + */ + function truncDecimals(pFloatValue) { + let decimals = getMaxDecimalPositions(); + return parseFloat(parseFloat(pFloatValue).toFixed(decimals)); + } + + /* + * Return number of decimals for the current market + */ + function getMaxDecimalPositions() { + return getMarketConfig().maxDecimals; + } + + /* + * Return number of decimals for the current market + */ + function getMarketConfig() { + return _.find(getExchangeProperties().markets, (p) => { + return _.first(p.pair) === global.MARKET.assetA.toUpperCase() && + _.last(p.pair) === global.MARKET.assetB.toUpperCase(); + }); + } + + /* + * Return number of decimals for the current market + */ + function getExchangeProperties() { + try { + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getExchangeProperties -> Entering function."); } + + return apiClient.getExchangeProperties(); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] getExchangeProperties -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } + + /* + * Returns the price for a given pair of assets. + * The object returned is an array of trades: + * ticker = { + * bid, Number + * ask, Number + * last Number + * }; + */ + function getTicker(pMarket, callBack) { + try { + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getTicker -> Entering function."); } + + apiClient.getTicker(pMarket, callBack); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] getTicker -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } + + /* + * Returns the open positions ath the exchange for a given market and user account. + * The object returned is an array of positions + * + */ + function getOpenPositions(pMarket, callBack) { + try { + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getOpenPositions -> Entering function."); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getOpenPositions -> pMarket = " + JSON.stringify(pMarket)); } + + apiClient.getOpenPositions(pMarket, callBack); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] getOpenPositions -> Error = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } + + /* + * Returns the trades for a given order number. + * The object returned is an array of positions + */ + function getExecutedTrades(pPositionId, callBack) { + try { + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getExecutedTrades -> Entering function."); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getExecutedTrades -> pPositionId = " + pPositionId); } + + apiClient.getExecutedTrades(pPositionId, callBack); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] getExecutedTrades -> Error = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } + + /* + * Creates a new buy or sell order. + * The orderNumber is returned. String + */ + function putPosition(pMarket, pType, pRate, pAmountA, pAmountB, callBack) { + try { + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> Entering function."); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pMarket = " + JSON.stringify(pMarket)); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pType = " + pType); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pRate = " + truncDecimals(pRate)); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pAmountA = " + truncDecimals(pAmountA)); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pAmountB = " + truncDecimals(pAmountB)); } + + let check = isValidOrder({ + market: getMarketConfig(), + api: apiClient, + amount: truncDecimals(pAmountB), + price: truncDecimals(pRate) + }); + + if (check.valid) { + if (pType === "buy") { + apiClient.buy(pMarket.assetA, pMarket.assetB, truncDecimals(pRate), truncDecimals(pAmountB), callBack); + return; + } + + if (pType === "sell") { + apiClient.sell(pMarket.assetA, pMarket.assetB, truncDecimals(pRate), truncDecimals(pAmountB), callBack); + return; + } + + logger.write(MODULE_NAME, "[ERROR] putPosition -> pType must be either 'buy' or 'sell'."); + callBack(global.DEFAULT_FAIL_RESPONSE); + + } else { + logger.write(MODULE_NAME, "[ERROR] putPosition -> The order is invalid: " + check.reason); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] putPosition -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } + + /* + * Move an existing position to the new rate. + * The new orderNumber is returned. + */ + function movePosition(pPosition, pNewRate, pNewAmountB, callBack) { + try { + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] movePosition -> Entering function."); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] movePosition -> pPosition = " + JSON.stringify(pPosition)); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] movePosition -> pNewRate = " + truncDecimals(pNewRate)); } + + apiClient.movePosition(pPosition, truncDecimals(pNewRate), truncDecimals(pNewAmountB), callBack); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] movePosition -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } + + /* + * Returns all the trade history from the Exchange since startTime to endTime orderd by tradeId. + * It's possible that the exchange doesn't support this method. + * The object returned is an array of trades: + * trade = { + * tradeID, String + * globalTradeID, String + * type, String + * rate, Number + * amountA, Number + * amountB, Number + * date Date + * }; + */ + function getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack) { + try { + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getTradeHistory -> Entering function."); } + + apiClient.getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] getTradeHistory -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } +}; diff --git a/Exchange/exchangeUtils.js b/Exchange/exchangeUtils.js new file mode 100644 index 000000000..853d6d825 --- /dev/null +++ b/Exchange/exchangeUtils.js @@ -0,0 +1,100 @@ +// generic low level reusuable utils for interacting with exchanges. + +const retry = require('retry'); +const _ = require('lodash'); + +const retryInstance = (options, checkFn, callback) => { + if(!options) { + options = { + retries: 100, + factor: 1.2, + minTimeout: 1 * 1000, + maxTimeout: 4 * 1000 + }; + } + + let attempt = 0; + + const operation = retry.operation(options); + operation.attempt(function(currentAttempt) { + checkFn((err, result) => { + if (!err) { + return callback(global.DEFAULT_OK_RESPONSE, result); + } else { + if (err.result === global.CUSTOM_OK_RESPONSE.result) { + return callback(err, result); + } + } + + let maxAttempts = err.retry; + if(maxAttempts === true) + maxAttempts = 10; + + if(err.retry && attempt++ < maxAttempts) { + return operation.retry(err); + } + + if(err.notFatal) { + if(err.backoffDelay) { + return setTimeout(() => operation.retry(err), err.backoffDelay); + } + + return operation.retry(err); + } + + callback(err, result); + }); + }); +} + +const isValidOrder = ({api, market, amount, price}) => { + let reason = false; + + // Check amount + if(amount < market.minimalOrder.amount) { + reason = 'Amount is too small'; + } + + // Some exchanges have restrictions on prices + if( + _.isFunction(api.isValidPrice) && + !api.isValidPrice(price) + ) { + reason = 'Price is not valid'; + } + + if( + _.isFunction(api.isValidLot) && + !api.isValidLot(price, amount) + ) { + reason = 'Lot size is too small'; + } + + return { + reason, + valid: !reason + } +} + +const includes = function(str, list) { + if (!_.isString(str)) + return false; + + return _.some(list, item => str.includes(item)); +} + + +const getMarketConfig = function(exchangeProperties) { + return _.find(exchangeProperties.markets, (p) => { + return _.first(p.pair) === global.MARKET.assetA.toUpperCase() && + _.last(p.pair) === global.MARKET.assetB.toUpperCase(); + }); +} + +module.exports = { + retry: retryInstance, + includes: includes, + isValidOrder, + getMarketConfig + +} \ No newline at end of file diff --git a/Exchange/wrappers/beautifier.js b/Exchange/wrappers/beautifier.js new file mode 100644 index 000000000..5e5e6a051 --- /dev/null +++ b/Exchange/wrappers/beautifier.js @@ -0,0 +1,183 @@ +const _ = require('underscore'); + +class Beautifier { + + constructor() { + this._beautifications = { + aggTrades: { + a: 'aggTradeId', + p: 'price', + q: 'quantity', + f: 'firstTradeId', + l: 'lastTradeId', + T: 'timestamp', + m: 'maker', + M: 'bestPriceMatch' + }, + klines: { + 0: 'openTime', + 1: 'open', + 2: 'high', + 3: 'low', + 4: 'close', + 5: 'volume', + 6: 'closeTime', + 7: 'quoteAssetVolume', + 8: 'trades', + 9: 'takerBaseAssetVolume', + 10: 'takerQuoteAssetVolume', + 11: 'ignored' + }, + bids: [ + { + 0: 'price', + 1: 'quantity', + 2: 'ignored' + } + ], + asks: [ + { + 0: 'price', + 1: 'quantity', + 2: 'ignored' + } + ], + depthUpdateEvent: { + e: 'eventType', + E: 'eventTime', + s: 'symbol', + u: 'updateId', + b: 'bidDepthDelta', + a: 'askDepthDelta' + }, + bidDepthDelta: [ + { + 0: 'price', + 1: 'quantity', + 2: 'ignored' + } + ], + askDepthDelta: [ + { + 0: 'price', + 1: 'quantity', + 2: 'ignored' + } + ], + klineEvent: { + e: 'eventType', + E: 'eventTime', + s: 'symbol', + k: 'kline' + }, + kline: { + t: 'startTime', + T: 'endTime', + s: 'symbol', + i: 'interval', + f: 'firstTradeId', + L: 'lastTradeId', + o: 'open', + c: 'close', + h: 'high', + l: 'low', + v: 'volume', + n: 'trades', + x: 'final', + q: 'quoteVolume', + V: 'volumeActive', + Q: 'quoteVolumeActive', + B: 'ignored' + }, + aggTradeEvent: { + e: 'eventType', + E: 'eventTime', + s: 'symbol', + a: 'tradeId', + p: 'price', + q: 'quantity', + f: 'firstTradeId', + l: 'lastTradeId', + T: 'time', + m: 'maker', + M: 'ignored' + }, + outboundAccountInfoEvent: { + e: 'eventType', + E: 'eventTime', + m: 'makerCommission', + t: 'takerCommission', + b: 'buyerCommission', + s: 'sellerCommission', + T: 'canTrade', + W: 'canWithdraw', + D: 'canDeposit', + B: 'balances' + }, + balances: [ + { + a: 'asset', + f: 'availableBalance', + l: 'onOrderBalance' + } + ], + executionReportEvent: { + e: 'eventType', + E: 'eventTime', + s: 'symbol', + c: 'newClientOrderId', + S: 'side', + o: 'orderType', + f: 'cancelType', // GTC 'Good till Cancel', IOC: 'Immediate or Cancel' + q: 'quantity', + p: 'price', + x: 'executionType', + X: 'orderStatus', + r: 'rejectReason', + i: 'orderId', + l: 'lastTradeQuantity', + z: 'accumulatedQuantity', + L: 'lastTradePrice', + n: 'commission', + N: 'commissionAsset', + m: 'maker', + T: 'tradeTime', + t: 'tradeId' + } + } + } + + beautify(object, type) { + const beautifications = _.isObject(type) ? type : this._beautifications[type]; + if (!beautifications) { + return object; + } + let newItem = {}; + _.each(object, (value, key) => { + if (_.isArray(value)) { + const newArray = []; + if (_.isArray(this._beautifications[beautifications[key]])) { + _.each(value, arrayValue => { + newArray.push(this.beautify(arrayValue, this._beautifications[beautifications[key]][0])); + }); + } else { + _.each(value, (value, key) => { + newItem.push(this.beautify(value, beautifications[key])) + }); + } + const newKey = beautifications[key] || key; + newItem[newKey] = newArray; + } else if (_.isObject(value)) { + const newKey = beautifications[key] || key; + newItem[newKey] = this.beautify(value, beautifications[key]); + } else { + const newKey = beautifications[key] || key; + newItem[newKey] = value; + } + }); + return newItem; + } + +} + +module.exports = Beautifier; \ No newline at end of file diff --git a/Exchange/wrappers/binance.js b/Exchange/wrappers/binance.js new file mode 100644 index 000000000..624c0fc06 --- /dev/null +++ b/Exchange/wrappers/binance.js @@ -0,0 +1,368 @@ +// Source: https://github.com/zoeyg/binance/blob/master/lib/rest.js + +const request = require('request'); +const qs = require('querystring'); +const _ = require('underscore'); +const crypto = require('crypto'); +const Beautifier = require('./beautifier.js'); +const assert = require('assert'); + +class BinanceRest { + + constructor({ + key, + secret, + recvWindow = false, + timeout = 15000, + disableBeautification = false, + handleDrift = false + }) { + this.key = key; + this.secret = secret; + this.recvWindow = recvWindow; + this.timeout = timeout; + this.disableBeautification = disableBeautification; + this.handleDrift = handleDrift; + + this._beautifier = new Beautifier(); + this._baseUrl = 'https://api.binance.com/'; + this._drift = 0; + this._syncInterval = 0; + } + + _makeRequest(query, callback, route, security, method, attempt = 0) { + assert(_.isUndefined(callback) || _.isFunction(callback), 'callback must be a function or undefined'); + assert(_.isObject(query), 'query must be an object'); + + let queryString; + const type = _.last(route.split('/')), + options = { + url: `${this._baseUrl}${route}`, + timeout: this.timeout + }; + + if (security === 'SIGNED') { + if (this.recvWindow) { + query.recvWindow = this.recvWindow; + } + queryString = qs.stringify(query); + options.url += '?' + queryString; + if (options.url.substr(options.url.length - 1) !== '?') { + options.url += '&'; + } + options.url += `signature=${this._sign(queryString)}`; + } else { + queryString = qs.stringify(query); + if (queryString) { + options.url += '?' + queryString; + } + } + if (security === 'API-KEY' || security === 'SIGNED') { + options.headers = { 'X-MBX-APIKEY': this.key }; + } + if (method) { + options.method = method; + } + + const action = cb => { + request(options, (err, response, body) => { + let payload; + try { + payload = JSON.parse(body); + } catch (e) { + payload = body; + } + if (err) { + cb(err, payload); + } else if (response.statusCode < 200 || response.statusCode > 299) { + /* + * If we get a response that the timestamp is ahead of the server, + * calculate the drift and then attempt the request again + */ + if (response.statusCode === 400 && payload.code === -1021 && + this.handleDrift && attempt === 0) { + + this.calculateDrift() + .then(() => { + query.timestamp = this._getTime() + this._drift; + return this._makeRequest(query, cb, route, security, method, + ++attempt); + }); + } else { + cb(new Error(`Response code ${response.statusCode}`), payload); + } + } else { + if (_.isArray(payload)) { + payload = _.map(payload, (item) => { + return this._doBeautifications(item, type); + }); + } else { + payload = this._doBeautifications(payload); + } + cb(err, payload); + } + }); + }; + if (callback) { + action(callback); + } else { + return new Promise((resolve, reject) => action((err, payload) => { + if (err) { + if (payload === undefined) { + reject(err); + } else { + reject(payload); + } + } else { + resolve(payload); + } + })); + } + } + + _doBeautifications(response, route) { + if (this.disableBeautification) { + return response; + } + return this._beautifier.beautify(response, route); + } + + _sign(queryString) { + return crypto.createHmac('sha256', this.secret) + .update(queryString) + .digest('hex'); + } + + _setTimestamp(query) { + if (!query.timestamp) { + query.timestamp = this._getTime() + this._drift; + } + } + + _getTime() { + return new Date().getTime(); + } + + calculateDrift() { + const systemTime = this._getTime(); + return this.time() + .then((response) => { + // Calculate the approximate trip time from here to binance + const transitTime = parseInt((this._getTime() - systemTime) / 2); + this._drift = response.serverTime - (systemTime + transitTime); + }); + } + + startTimeSync(interval = 300000, onRecalculateDriftCb) { + return new Promise((resolve, reject) => { + // If there's already an interval running, clear it and reset values + if (this._syncInterval !== 0) { + this.endTimeSync(); + return resolve(); + } + + // Calculate initial drift value and setup interval to periodically update it + this.calculateDrift() + .then(resolve) + .catch(reject); + + this._syncInterval = setInterval(() => { + const promise = this.calculateDrift(); + + if (_.isFunction(onRecalculateDriftCb)) { + onRecalculateDriftCb(promise); + } + }, interval); + }); + } + + endTimeSync() { + clearInterval(this._syncInterval); + this._drift = 0; + this._syncInterval = 0; + } + + // Public APIs + ping(callback) { + return this._makeRequest({}, callback, 'api/v1/ping'); + } + + time(callback) { + return this._makeRequest({}, callback, 'api/v1/time'); + } + + depth(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + + return this._makeRequest(query, callback, 'api/v1/depth'); + } + + trades(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + + return this._makeRequest(query, callback, 'api/v1/trades'); + } + + historicalTrades(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + + return this._makeRequest(query, callback, 'api/v1/historicalTrades', 'API-KEY'); + } + + aggTrades(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + + return this._makeRequest(query, callback, 'api/v1/aggTrades'); + } + + exchangeInfo(callback) { + return this._makeRequest({}, callback, 'api/v1/exchangeInfo'); + } + + klines(query = {}, callback) { + return this._makeRequest(query, callback, 'api/v1/klines'); + } + + ticker24hr(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + + return this._makeRequest(query, callback, 'api/v1/ticker/24hr'); + } + + tickerPrice(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + + return this._makeRequest(query, callback, 'api/v3/ticker/price'); + } + + bookTicker(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + + return this._makeRequest(query, callback, 'api/v3/ticker/bookTicker'); + } + + allBookTickers(callback) { + return this._makeRequest({}, callback, 'api/v1/ticker/allBookTickers'); + } + + allPrices(callback) { + return this._makeRequest({}, callback, 'api/v1/ticker/allPrices'); + } + + // Private APIs + newOrder(query = {}, callback) { + this._setTimestamp(query); + return this._makeRequest(query, callback, 'api/v3/order', 'SIGNED', 'POST'); + } + + testOrder(query = {}, callback) { + this._setTimestamp(query); + return this._makeRequest(query, callback, 'api/v3/order/test', 'SIGNED', 'POST'); + } + + queryOrder(query = {}, callback) { + this._setTimestamp(query); + return this._makeRequest(query, callback, 'api/v3/order', 'SIGNED'); + } + + cancelOrder(query = {}, callback) { + this._setTimestamp(query); + return this._makeRequest(query, callback, 'api/v3/order', 'SIGNED', 'DELETE'); + } + + openOrders(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + this._setTimestamp(query); + return this._makeRequest(query, callback, 'api/v3/openOrders', 'SIGNED'); + } + + allOrders(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + this._setTimestamp(query); + return this._makeRequest(query, callback, 'api/v3/allOrders', 'SIGNED'); + } + + account(query = {}, callback) { + if (_.isFunction(query)) { + callback = query; + query = {}; + } + this._setTimestamp(query); + return this._makeRequest(query, callback, 'api/v3/account', 'SIGNED'); + } + + myTrades(query = {}, callback) { + if (_.isString(query)) { + query = { symbol: query }; + } + this._setTimestamp(query); + return this._makeRequest(query, callback, 'api/v3/myTrades', 'SIGNED'); + } + + withdraw(query = {}, callback) { + this._setTimestamp(query); + return this._makeRequest(query, callback, 'wapi/v3/withdraw.html', 'SIGNED', 'POST'); + } + + depositHistory(query = {}, callback) { + if (_.isString(query)) { + query = { asset: query }; + } + this._setTimestamp(query); + return this._makeRequest(query, callback, 'wapi/v3/depositHistory.html', 'SIGNED'); + } + + withdrawHistory(query = {}, callback) { + if (_.isString(query)) { + query = { asset: query }; + } + this._setTimestamp(query); + return this._makeRequest(query, callback, 'wapi/v3/withdrawHistory.html', 'SIGNED'); + } + + depositAddress(query = {}, callback) { + if (_.isString(query)) { + query = { asset: query }; + } + this._setTimestamp(query); + return this._makeRequest(query, callback, 'wapi/v3/depositAddress.html', 'SIGNED'); + } + + accountStatus(callback) { + const query = {}; + this._setTimestamp(query); + return this._makeRequest(query, callback, 'wapi/v3/accountStatus.html', 'SIGNED'); + } + + startUserDataStream(callback) { + return this._makeRequest({}, callback, 'api/v1/userDataStream', 'API-KEY', 'POST'); + } + + keepAliveUserDataStream(query = {}, callback) { + return this._makeRequest(query, callback, 'api/v1/userDataStream', 'API-KEY', 'PUT'); + } + + closeUserDataStream(query = {}, callback) { + return this._makeRequest(query, callback, 'api/v1/userDataStream', 'API-KEY', 'DELETE'); + } +} + +module.exports = BinanceRest; \ No newline at end of file diff --git a/Exchange/wrappers/binanceClient.js b/Exchange/wrappers/binanceClient.js new file mode 100644 index 000000000..a46ca7d24 --- /dev/null +++ b/Exchange/wrappers/binanceClient.js @@ -0,0 +1,360 @@ +exports.newAPIClient = function newAPIClient(pKey, pSecret, logger) { + + /* + /* ATENTION: This Library is used both a the cloud (AACloud) and also at the AAWeb on the server side without any modifications. + /* There is a second version, stripped of all the inner functionality that runs at AAWeb browser side, which channels the requests to the server side one. + */ + + const FULL_LOG = true; + const LOG_FILE_CONTENT = true; + const MODULE_NAME = "binanceClient"; + + const retry = require('../exchangeUtils').retry; + const includes = require('../exchangeUtils').includes; + const _ = require('lodash'); + const Binance = require("./binance"); + const exchangeProperties = require('./poloniexProperties.json'); + + const recoverableErrors = [ + 'SOCKETTIMEDOUT', + 'TIMEDOUT', + 'CONNRESET', + 'CONNREFUSED', + 'NOTFOUND', + 'Error -1021', + 'Response code 429', + 'Response code 5', + 'ETIMEDOUT' + ]; + + let API = new Binance({ + key: pKey, + secret: pSecret, + timeout: 15000, + recvWindow: 60000, + disableBeautification: false, + handleDrift: true, + }); + + let thisObject = { + getTicker: getTicker, + getOpenPositions: getOpenPositions, + getExecutedTrades: getExecutedTrades, + buy: buy, + sell: sell, + movePosition: movePosition, + getPublicTradeHistory: getPublicTradeHistory, + getExchangeProperties: getExchangeProperties, + isValidPrice: isValidPrice, + isValidLot: isValidLot + }; + + return thisObject; + + function joinCurrencies(currencyA, currencyB) { + // If only one arg, then return the first + if (typeof currencyB !== 'string') { + return currencyA; + } + + return currencyB + '' + currencyA; + } + + /* + * Returns the properties for this exchange + */ + function getExchangeProperties() { + return exchangeProperties; + } + + function truncDecimals(pFloatValue) { + + let decimals = 6; + + return parseFloat(parseFloat(pFloatValue).toFixed(decimals)); + + } + + /* + * Returns the price for a given pair of assets. + * The object returned is an array of trades: + * ticker = { + * bid, Number + * ask, Number + * last Number + * }; + */ + function getTicker(pMarket, callBack) { + + let market = joinCurrencies(pMarket.assetA, pMarket.assetB); + const handle = (err, response) => { + let ticker; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + ticker = { + bid: Number(response.bidPrice), + ask: Number(response.askPrice), + last: Number(response.lastPrice) + }; + } + callBack(err, ticker); + }; + + const fetch = next => API.ticker24hr(market, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* + * Returns the open positions ath the exchange for a given market and user account. + * The object returned is an array of positions: + * position = { + * id, + * type, + * rate, Number + * amountA, Number + * amountB, Number + * fee, (not required) Number + * datetime + * }; + */ + function getOpenPositions(pMarket, callBack) { + + let market = joinCurrencies(pMarket.assetA, pMarket.assetB); + const handle = (err, response) => { + let exchangePositions = []; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + for (let i = 0; i < response.length; i++) { + let openPosition = { + id: response[i].orderId, + type: response[i].side.toLowerCase(), + rate: Number(response[i].price), + amountA: truncDecimals(response[i].origQty * response[i].price), + amountB: Number(response[i].origQty), + date: (new Date(response[i].time)).valueOf() + }; + exchangePositions.push(openPosition); + } + } + callBack(err, exchangePositions); + }; + + const fetch = next => API.openOrders(market, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* + * Returns the trades for a given order number. + * The object returned is an array of positions: + * position = { + * id, + * type, + * rate, Number + * amountA, Number + * amountB, Number + * fee, Number + * datetime + * }; + */ + function getExecutedTrades(pPositionId, callBack) { + + let market = joinCurrencies(global.MARKET.assetA, global.MARKET.assetB); + const handle = (err, response) => { + let exchangeTrades = []; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + for (let i = 0; i < response.length; i++) { + if (response[i].orderId === pPositionId) { + let type = "sell" + if (response[i].isBuyer === true) { + type = "buy"; + } + let trade = { + id: response[i].orderId, + type: type, + rate: Number(response[i].price), + amountA: truncDecimals(response[i].qty * response[i].price), + amountB: Number(response[i].qty), + fee: Number(response[i].commission), + date: (new Date(response[i].time)).valueOf() + }; + exchangeTrades.push(trade); + break; + } + } + } + callBack(err, exchangeTrades); + }; + + const fetch = next => API.myTrades(market, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* + * Creates a new buy order. + * The orderNumber is returned. + */ + function buy(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) { + + var parameters = { + symbol: joinCurrencies(pCurrencyA, pCurrencyB), + side: 'BUY', + type: 'LIMIT', + quantity: pAmount, + price: pRate, + timeInForce: 'GTC' + }; + const handle = (err, response) => { + let orderNumber; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + orderNumber = response.orderId; + } + callBack(err, orderNumber); + }; + + const fetch = next => API.newOrder(parameters, analizeResponse(next)); + + retry(null, fetch, handle); + + } + + /* + * Creates a new sell order. + * The orderNumber is returned. String + */ + function sell(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) { + + var parameters = { + symbol: joinCurrencies(pCurrencyA, pCurrencyB), + side: 'SELL', + type: 'LIMIT', + quantity: pAmount, + price: pRate, + timeInForce: 'GTC' + }; + const handle = (err, response) => { + let orderNumber; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + orderNumber = response.orderId; + } + callBack(err, orderNumber); + }; + + const fetch = next => API.newOrder(parameters, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* //TODO Complete partial orders + * Move an existing position to the new rate. + * The new orderNumber is returned. String + */ + function movePosition(pPosition, pNewRate, pNewAmountB, callBack) { + + var parameters = { + symbol: joinCurrencies(global.MARKET.assetA, global.MARKET.assetB), + orderId: pPosition.id + }; + + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] moveOrder -> Step1 - Cancelling Position: " + JSON.stringify(pPosition)); } + + const handle = (err, response) => { + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] moveOrder -> Step1 Complete - Position Cancelled. Proceeding to put the new position."); } + + if (position.type === "buy") + thisObject.buy(global.MARKET.assetA, global.MARKET.assetB, pNewRate, pNewAmountB, callBack); + else + thisObject.sell(global.MARKET.assetA, global.MARKET.assetB, pNewRate, pNewAmountB, callBack); + } else { + callBack(err); + } + }; + + const fetch = next => API.cancelOrder(parameters, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* //TODO Pending Review + * Returns all the trade history from the Exchange since startTime to endTime orderd by tradeId. + * It's possible that the exchange doesn't support this method. + * The object returned is an array of trades: + * trade = { + * tradeIdAtExchange, + * marketIdAtExchange, + * type, + * rate, Number + * amountA, Number + * amountB, Number + * datetime + * }; + */ + function getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] getPublicTradeHistory -> Not implemented yet."); } + callBack(global.DEFAULT_FAIL_RESPONSE); + } + + function isValidPrice(price) { + return price >= market.minimalOrder.price; + } + + function isValidLot(price, amount) { + return amount * price >= market.minimalOrder.order; + } + + function analizeResponse(callBack) { + + return (exchangeErr, exchangeResponse) => { + let error; + + /* This function analizes the different situations we might encounter trying to access Poloniex and returns appropiate standard errors. */ + + let stringExchangeErr = JSON.stringify(exchangeErr); + let stringExchangeResponse = JSON.stringify(exchangeResponse); + + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeErr = " + stringExchangeErr); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeResponse = " + stringExchangeResponse); } + + if (exchangeErr) { + error = global.DEFAULT_FAIL_RESPONSE; + } else if (!exchangeResponse) { + error = { + result: global.DEFAULT_FAIL_RESPONSE.result, + message: 'Empty response' + }; + } else if (includes(exchangeResponse.error, [''])) { + error = { + result: global.DEFAULT_FAIL_RESPONSE.result, + message: exchangeResponse + }; + } else if (includes(exchangeResponse.error, ['Order does not exist.'])) { + error = { + result: global.CUSTOM_OK_RESPONSE.result, + message: exchangeResponse.error + }; + } else if (exchangeResponse.error) { + error = { + result: global.DEFAULT_FAIL_RESPONSE.result, + message: exchangeResponse.error + }; + } + + if (error) { + if (includes(error.message, recoverableErrors)) { + error.notFatal = true; + } + } + + return callBack(error, exchangeResponse); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] analizeResponse -> err.message = " + err.message); + return callBack(global.DEFAULT_FAIL_RESPONSE, exchangeResponse); + } + } + } + +} diff --git a/Exchange/wrappers/binanceProperties.json b/Exchange/wrappers/binanceProperties.json new file mode 100644 index 000000000..ad4438de0 --- /dev/null +++ b/Exchange/wrappers/binanceProperties.json @@ -0,0 +1,4594 @@ +{ + "assets": [ + "NULS", + "VEN", + "BNB", + "NEO", + "LINK", + "SALT", + "IOTA", + "ETC", + "AST", + "KNC", + "WTC", + "SNGLS", + "EOS", + "SNT", + "MCO", + "BTC", + "OAX", + "OMG", + "GAS", + "BQX", + "QTUM", + "BNT", + "DNT", + "ICN", + "SNM", + "STRAT", + "ZRX", + "FUN", + "LTC", + "ETH", + "XVG", + "BCC", + "ADA", + "ADX", + "AE", + "AGI", + "AION", + "AMB", + "APPC", + "ARK", + "ARN", + "BAT", + "BCD", + "BCN", + "BCPT", + "BLZ", + "BRD", + "BTG", + "BTS", + "CDT", + "CHAT", + "CLOAK", + "CMT", + "CND", + "CVC", + "DASH", + "DATA", + "DENT", + "DGD", + "DLT", + "EDO", + "ELF", + "ENG", + "ENJ", + "EVX", + "FUEL", + "GNT", + "GRS", + "GTO", + "GVT", + "GXS", + "HSR", + "ICX", + "INS", + "IOST", + "IOTX", + "KEY", + "KMD", + "LEND", + "LOOM", + "LRC", + "LSK", + "LUN", + "MANA", + "MDA", + "MFT", + "MOD", + "MTH", + "MTL", + "NANO", + "NAS", + "NAV", + "NCASH", + "NEBL", + "NPXS", + "NXS", + "ONT", + "OST", + "PIVX", + "POA", + "POE", + "POWR", + "PPT", + "QKC", + "QLC", + "QSP", + "RCN", + "RDN", + "REP", + "REQ", + "RLC", + "RPX", + "SC", + "SKY", + "STEEM", + "STORJ", + "STORM", + "SUB", + "SYS", + "THETA", + "TNB", + "TNT", + "TRIG", + "TRX", + "TUSD", + "VIA", + "VIB", + "VIBE", + "WABI", + "WAN", + "WAVES", + "WINGS", + "WPR", + "XEM", + "XLM", + "XMR", + "XRP", + "XZC", + "YOYO", + "ZEC", + "ZEN", + "ZIL" + ], + "currencies": [ + "BNB", + "BTC", + "ETH", + "USDT" + ], + "markets": [ + { + "pair": [ + "BNB", + "NULS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BNB", + "VEN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "BNB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "NULS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "NEO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NULS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "LINK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "SALT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "IOTA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "ETC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "AST" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "KNC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "WTC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "SNGLS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "EOS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "SNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "MCO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "BTC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.000001, + "price": 0.01, + "order": 10 + } + }, + { + "pair": [ + "ETH", + "OAX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "OMG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "GAS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BQX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "WTC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "QTUM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "BNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "DNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "ICN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "SNM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "SNM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "SNGLS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "BQX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NEO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "KNC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "STRAT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "ZRX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "QTUM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "FUN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "LTC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "LINK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "ETH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "XVG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "STRAT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "ZRX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "IOTA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "BCC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "OMG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "MCO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "SALT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "ADA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "ADA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ADA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "ADA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.1, + "price": 0.00001, + "order": 10 + } + }, + { + "pair": [ + "BNB", + "ADX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "ADX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ADX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "AE" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "AE" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "AE" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "AGI" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "AGI" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "AGI" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "AION" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "AION" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "AION" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "AMB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "AMB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "AMB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "APPC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "APPC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "APPC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "ARK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ARK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "ARN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ARN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "AST" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BNB", + "BAT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "BAT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BAT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "BCC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.00001, + "price": 0.01, + "order": 1 + } + }, + { + "pair": [ + "ETH", + "BCC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "BCC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.00001, + "price": 0.01, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "BCD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BCD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "BCN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "BCN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BCN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "BCPT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "BCPT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BCPT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "BLZ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "BLZ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BLZ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "BNB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "BNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BNB", + "BRD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "BRD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BRD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "BTG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BTG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "BTS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "BTS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "BTS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "CDT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "CDT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "CHAT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "CHAT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "CLOAK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "CLOAK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "CMT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "CMT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "CMT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "CND" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "CND" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "CND" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "CVC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "CVC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "CVC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "DASH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "DASH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "DATA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "DATA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "DENT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "DENT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "DGD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "DGD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "DLT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "DLT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "DLT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "DNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "EDO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "EDO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "ELF" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ELF" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "ENG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ENG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "ENJ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "ENJ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ENJ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "EOS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "EOS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "USDT", + "EOS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 10 + } + }, + { + "pair": [ + "BNB", + "ETC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 1 + } + }, + { + "pair": [ + "ETH", + "ETC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "ETC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "EVX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "EVX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "FUEL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "FUEL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "FUN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BNB", + "GNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "GNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "GNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "GRS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "GRS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "GTO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "GTO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "GTO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "GVT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "GVT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "GXS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "GXS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "HSR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "HSR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "ICN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BNB", + "ICX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "ICX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ICX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "ICX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "INS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "INS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "IOST" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "IOST" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "IOTA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "USDT", + "IOTA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "IOTX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "IOTX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "KEY" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "KEY" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "KMD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "KMD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "LEND" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "LEND" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "LOOM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "LOOM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "LOOM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "LRC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "LRC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "LSK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "LSK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "LSK" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "LTC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.00001, + "price": 0.01, + "order": 1 + } + }, + { + "pair": [ + "ETH", + "LTC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "LTC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.00001, + "price": 0.01, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "LUN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "LUN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "MANA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "MANA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "MCO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "MDA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "MDA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "MFT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "MFT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "MFT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "MOD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "MOD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "MTH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "MTH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "MTL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "MTL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "NANO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "NANO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NANO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "NAS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "NAS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NAS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "NAV" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "NAV" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NAV" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "NCASH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "NCASH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NCASH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "NEBL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "NEBL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NEBL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "NEO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.001, + "order": 1 + } + }, + { + "pair": [ + "USDT", + "NEO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.001, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "NPXS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NPXS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "NXS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "NXS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "NXS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "OAX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BNB", + "ONT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "ONT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ONT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "ONT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.001, + "order": 10 + } + }, + { + "pair": [ + "BNB", + "OST" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "OST" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "OST" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "PIVX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "PIVX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "PIVX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "POA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "POA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "POA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "POE" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "POE" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "POWR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "POWR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "POWR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "PPT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "PPT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "QKC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "QKC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "QLC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "QLC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "QLC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "QSP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "QSP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "QSP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "QTUM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "USDT", + "QTUM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.001, + "order": 10 + } + }, + { + "pair": [ + "BNB", + "RCN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "RCN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "RCN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "RDN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "RDN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "RDN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "REP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "REP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "REP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "REQ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "REQ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "RLC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "RLC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "RLC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "RPX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "RPX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "RPX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "SC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "SC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "SC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "SKY" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "SKY" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "SKY" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "SNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BNB", + "STEEM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "STEEM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "STEEM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "STORJ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "STORJ" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "STORM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "STORM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "STORM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "SUB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "SUB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "SYS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "SYS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "SYS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "THETA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "THETA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "THETA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "TNB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "TNB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "TNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "TNT" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "TRIG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "TRIG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "TRIG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "TRX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "TRX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "TRX" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.1, + "price": 0.00001, + "order": 10 + } + }, + { + "pair": [ + "BNB", + "TUSD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "TUSD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "TUSD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "TUSD" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "VEN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "VEN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "VEN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 10 + } + }, + { + "pair": [ + "BNB", + "VIA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "VIA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "VIA" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "VIB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BTC", + "VIBE" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "VIBE" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "ETH", + "VIB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "WABI" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "WABI" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "WABI" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "WAN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "WAN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "WAN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "WAVES" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "WAVES" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 1e-7, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "WAVES" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "WINGS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "WINGS" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-7, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "WPR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "WPR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "WTC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 1 + } + }, + { + "pair": [ + "BNB", + "XEM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "XEM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "XEM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "XLM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "XLM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "XLM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "XLM" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "XMR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "XMR" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "XRP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.00001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "XRP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "XRP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "XRP" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.1, + "price": 0.00001, + "order": 10 + } + }, + { + "pair": [ + "BTC", + "XVG" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "BNB", + "XZC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "XZC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "XZC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.000001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "YOYO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "YOYO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "YOYO" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "BTC", + "ZEC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ZEC" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "ZEN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "ZEN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.000001, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ZEN" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.001, + "price": 0.00001, + "order": 0.01 + } + }, + { + "pair": [ + "BNB", + "ZIL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 0.000001, + "order": 1 + } + }, + { + "pair": [ + "BTC", + "ZIL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.001 + } + }, + { + "pair": [ + "ETH", + "ZIL" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 1, + "price": 1e-8, + "order": 0.01 + } + }, + { + "pair": [ + "USDT", + "BNB" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.01, + "price": 0.0001, + "order": 10 + } + }, + { + "pair": [ + "USDT", + "ETH" + ], + "maxDecimals": 6, + "minimalOrder": { + "amount": 0.00001, + "price": 0.01, + "order": 10 + } + } + ] +} \ No newline at end of file diff --git a/Exchange/wrappers/poloniex.js b/Exchange/wrappers/poloniex.js new file mode 100644 index 000000000..9a1a32b41 --- /dev/null +++ b/Exchange/wrappers/poloniex.js @@ -0,0 +1,440 @@ +// Source: https://github.com/premasagar/poloniex.js +// Documentation: https://poloniex.com/support/api/ + +module.exports = (function () { + 'use strict'; + + // Module dependencies + var request = require('request'), + nonce = require('nonce')(); + + // Constants + var version = '0.0.9', + PUBLIC_API_URL = 'https://poloniex.com/public', + PRIVATE_API_URL = 'https://poloniex.com/tradingApi', + USER_AGENT = 'poloniex.js ' + version; + //USER_AGENT = 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0' + + // Helper methods + function joinCurrencies(currencyA, currencyB) { + // If only one arg, then return the first + if (typeof currencyB !== 'string') { + return currencyA; + } + + return currencyA + '_' + currencyB; + } + + // Constructor + function Poloniex(keyVaultAPI) { + // Generate headers signed by this user's key and secret. + // The secret is encapsulated and never exposed + this._getPrivateHeaders = function (parameters, next) { + var paramString, signature; + + // Convert to `arg1=foo&arg2=bar` + paramString = Object.keys(parameters).map(function (param) { + return encodeURIComponent(param) + '=' + encodeURIComponent(parameters[param]); + }).join('&'); + + keyVaultAPI.signTransaction(paramString, next); + }; + } + + // Currently, this fails with `Error: CERT_UNTRUSTED` + // Poloniex.STRICT_SSL can be set to `false` to avoid this. Use with caution. + // Will be removed in future, once this is resolved. + Poloniex.STRICT_SSL = true; + + // Customisable user agent string + Poloniex.USER_AGENT = USER_AGENT; + + // Prototype + Poloniex.prototype = { + constructor: Poloniex, + + // Make an API request + _request: function (options, callback) { + if (!('headers' in options)) { + options.headers = {}; + } + + options.json = true; + options.headers['User-Agent'] = Poloniex.USER_AGENT; + options.strictSSL = Poloniex.STRICT_SSL; + options.timeout = 60 * 1000; + + request(options, function (err, response, body) { + // Empty response + if (!err && (typeof body === 'undefined' || body === null)) { + err = 'Empty response'; + } + + callback(err, body); + }); + + return this; + }, + + // Make a public API request + _public: function (command, parameters, callback) { + var options; + + if (typeof parameters === 'function') { + callback = parameters; + parameters = {}; + } + + parameters || (parameters = {}); + parameters.command = command; + options = { + method: 'GET', + url: PUBLIC_API_URL, + qs: parameters + }; + + options.qs.command = command; + return this._request(options, callback); + }, + + // Make a private API request + _private: function (command, parameters, callback) { + var options; + + if (typeof parameters === 'function') { + callback = parameters; + parameters = {}; + } + + parameters || (parameters = {}); + parameters.command = command; + parameters.nonce = nonce(); + + options = { + method: 'POST', + url: PRIVATE_API_URL, + form: parameters + }; + + let headers = this._getPrivateHeaders(parameters, next) + + let thisObject = this + + function next(pHeaders, error) { + if (!error) { + options.headers = pHeaders; + return thisObject._request(options, callback); + } else { + callback(error); + } + + } + }, + + ///// + // PUBLIC METHODS + + returnTicker: function (callback) { + return this._public('returnTicker', callback); + }, + + return24hVolume: function (callback) { + return this._public('return24hVolume', callback); + }, + + returnOrderBook: function (currencyA, currencyB, callback) { + var currencyPair; + + if (typeof currencyB === 'function') { + currencyPair = currencyA; + callback = currencyB; + currencyB = null; + } + + else { + currencyPair = joinCurrencies(currencyA, currencyB); + } + + var parameters = { + currencyPair: currencyPair + }; + + return this._public('returnOrderBook', parameters, callback); + }, + + returnChartData: function (currencyA, currencyB, period, start, end, callback) { + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB), + period: period, + start: start, + end: end + }; + + return this._public('returnChartData', parameters, callback); + }, + + returnCurrencies: function (callback) { + return this._public('returnCurrencies', callback); + }, + + returnLoanOrders: function (currency, callback) { + return this._public('returnLoanOrders', { currency: currency }, callback); + }, + + returnTradeHistory: function (currencyA, currencyB, start, end, callback) { + if (arguments.length < 5) { + callback = start; + start = Date.now() / 1000 - 60 * 60; + end = Date.now() / 1000 + 60 * 60; // Some buffer in case of client/server time out of sync. + } + + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB), + start: start, + end: end + }; + + return this._public('returnTradeHistory', parameters, callback); + }, + + ///// + // PRIVATE METHODS + + returnBalances: function (callback) { + return this._private('returnBalances', {}, callback); + }, + + returnCompleteBalances: function (account, callback) { + var parameters = {}; + + if (typeof account === 'function') { + callback = account; + } + + else if (typeof account === 'string' && !!account) { + parameters.account = account; + } + + return this._private('returnCompleteBalances', parameters, callback); + }, + + returnDepositAddresses: function (callback) { + return this._private('returnDepositAddresses', {}, callback); + }, + + generateNewAddress: function (currency, callback) { + return this._private('generateNewAddress', { currency: currency }, callback); + }, + + returnDepositsWithdrawals: function (start, end, callback) { + return this._private('returnDepositsWithdrawals', { start: start, end: end }, callback); + }, + + // can be called with `returnOpenOrders('all', callback)` + returnOpenOrders: function (currencyA, currencyB, callback) { + var currencyPair; + + if (typeof currencyB === 'function') { + currencyPair = currencyA; + callback = currencyB; + currencyB = null; + } + + else { + currencyPair = joinCurrencies(currencyA, currencyB); + } + + var parameters = { + currencyPair: currencyPair + }; + + return this._private('returnOpenOrders', parameters, callback); + }, + + returnOrderTrades: function (orderNumber, callback) { + var parameters = { + orderNumber: orderNumber + }; + + return this._private('returnOrderTrades', parameters, callback); + }, + + buy: function (currencyA, currencyB, rate, amount, callback) { + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB), + rate: rate, + amount: amount + }; + + return this._private('buy', parameters, callback); + }, + + sell: function (currencyA, currencyB, rate, amount, callback) { + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB), + rate: rate, + amount: amount + }; + + return this._private('sell', parameters, callback); + }, + + cancelOrder: function (currencyA, currencyB, orderNumber, callback) { + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB), + orderNumber: orderNumber + }; + + return this._private('cancelOrder', parameters, callback); + }, + + moveOrder: function (orderNumber, rate, amount, callback) { + var parameters = { + orderNumber: orderNumber, + rate: rate, + amount: amount ? amount : null + }; + + return this._private('moveOrder', parameters, callback); + }, + + withdraw: function (currency, amount, address, callback) { + var parameters = { + currency: currency, + amount: amount, + address: address + }; + + return this._private('withdraw', parameters, callback); + }, + + returnFeeInfo: function (callback) { + return this._private('returnFeeInfo', {}, callback); + }, + + returnAvailableAccountBalances: function (account, callback) { + var parameters = {}; + + if (typeof account === 'function') { + callback = account; + } + + else if (typeof account === 'string' && !!account) { + parameters.account = account; + } + + return this._private('returnAvailableAccountBalances', parameters, callback); + }, + + returnTradableBalances: function (callback) { + return this._private('returnTradableBalances', {}, callback); + }, + + transferBalance: function (currency, amount, fromAccount, toAccount, callback) { + var parameters = { + currency: currency, + amount: amount, + fromAccount: fromAccount, + toAccount: toAccount + }; + + return this._private('transferBalance', parameters, callback); + }, + + returnMarginAccountSummary: function (callback) { + return this._private('returnMarginAccountSummary', {}, callback); + }, + + marginBuy: function (currencyA, currencyB, rate, amount, lendingRate, callback) { + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB), + rate: rate, + amount: amount, + lendingRate: lendingRate ? lendingRate : null + }; + + return this._private('marginBuy', parameters, callback); + }, + + marginSell: function (currencyA, currencyB, rate, amount, lendingRate, callback) { + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB), + rate: rate, + amount: amount, + lendingRate: lendingRate ? lendingRate : null + }; + + return this._private('marginSell', parameters, callback); + }, + + getMarginPosition: function (currencyA, currencyB, callback) { + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB) + }; + + return this._private('getMarginPosition', parameters, callback); + }, + + closeMarginPosition: function (currencyA, currencyB, callback) { + var parameters = { + currencyPair: joinCurrencies(currencyA, currencyB) + }; + + return this._private('closeMarginPosition', parameters, callback); + }, + + createLoanOffer: function (currency, amount, duration, autoRenew, lendingRate, callback) { + var parameters = { + currency: currency, + amount: amount, + duration: duration, + autoRenew: autoRenew, + lendingRate: lendingRate + }; + + return this._private('createLoanOffer', parameters, callback); + }, + + cancelLoanOffer: function (orderNumber, callback) { + var parameters = { + orderNumber: orderNumber + }; + + return this._private('cancelLoanOffer', parameters, callback); + }, + + returnOpenLoanOffers: function (callback) { + return this._private('returnOpenLoanOffers', {}, callback); + }, + + returnActiveLoans: function (callback) { + return this._private('returnActiveLoans', {}, callback); + }, + + returnLendingHistory: function (start, end, limit, callback) { + var parameters = { + start: start, + end: end, + limit: limit + }; + + return this._private('returnLendingHistory', parameters, callback); + }, + + toggleAutoRenew: function (orderNumber, callback) { + return this._private('toggleAutoRenew', { orderNumber: orderNumber }, callback); + } + + }; + + // Backwards Compatibility + Poloniex.prototype.getTicker = Poloniex.prototype.returnTicker; + Poloniex.prototype.get24hVolume = Poloniex.prototype.return24hVolume; + Poloniex.prototype.getOrderBook = Poloniex.prototype.returnOrderBook; + Poloniex.prototype.getTradeHistory = Poloniex.prototype.returnChartData; + Poloniex.prototype.myBalances = Poloniex.prototype.returnBalances; + Poloniex.prototype.myOpenOrders = Poloniex.prototype.returnOpenOrders; + Poloniex.prototype.myTradeHistory = Poloniex.prototype.returnTradeHistory; + + return Poloniex; +})(); diff --git a/Exchange/wrappers/poloniexClient.js b/Exchange/wrappers/poloniexClient.js new file mode 100644 index 000000000..7476728c1 --- /dev/null +++ b/Exchange/wrappers/poloniexClient.js @@ -0,0 +1,353 @@ +exports.newAPIClient = function newAPIClient(keyVaultAPI, logger) { + + /* + /* ATENTION: This Library is used both a the cloud (AACloud) and also at the AAWeb on the server side without any modifications. + /* There is a second version, stripped of all the inner functionality that runs at AAWeb browser side, which channels the requests to the server side one. + */ + + const FULL_LOG = true; + const LOG_FILE_CONTENT = true; + const MODULE_NAME = "poloniexClient"; + + const retry = require('../exchangeUtils').retry; + const includes = require('../exchangeUtils').includes; + const _ = require('lodash'); + const Poloniex = require("./poloniex"); + const exchangeProperties = require('./poloniexProperties.json'); + + const recoverableErrors = [ + 'SOCKETTIMEDOUT', + 'TIMEDOUT', + 'CONNRESET', + 'CONNREFUSED', + 'NOTFOUND', + '429', + '522', + '504', + '503', + '500', + '502', + 'Empty response', + 'Please try again in a few minutes.', + 'Nonce must be greater than', + 'Internal error. Please try again.', + 'Connection timed out. Please try again.', + 'ENOTFOUND', + 'ECONNREFUSED', + 'CONNREFUSED', + 'NOTFOUND', + 'ESOCKETTIMEDOUT', + 'ECONNRESET', + 'Connection timed out', + 'Connection Error', + 'Order not found, or you are not the person who placed it.', + 'ETIMEDOUT' + ]; + + let API = new Poloniex(keyVaultAPI); + + let thisObject = { + getTicker: getTicker, + getOpenPositions: getOpenPositions, + getExecutedTrades: getExecutedTrades, + buy: buy, + sell: sell, + movePosition: movePosition, + getPublicTradeHistory: getPublicTradeHistory, + getExchangeProperties: getExchangeProperties, + isValidLot: isValidLot + }; + + return thisObject; + + function joinCurrencies(currencyA, currencyB) { + // If only one arg, then return the first + if (typeof currencyB !== 'string') { + return currencyA; + } + + return currencyA + '_' + currencyB; + } + + + /* + * Returns the properties for this exchange + */ + function getExchangeProperties() { + return exchangeProperties; + } + + /* + * Returns the price for a given pair of assets. + * The object returned is an array of trades: + * ticker = { + * bid, Number + * ask, Number + * last Number + * }; + */ + function getTicker(pMarket, callBack) { + + const handle = (err, response) => { + let ticker; + let market = joinCurrencies(pMarket.assetA, pMarket.assetB); + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + ticker = { + bid: Number(response[market].highestBid), + ask: Number(response[market].lowestAsk), + last: Number(response[market].last) + }; + } + callBack(err, ticker); + }; + + const fetch = next => API.getTicker(analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* + * Returns the open positions ath the exchange for a given market and user account. + * The object returned is an array of positions: + * position = { + * id, + * type, + * rate, Number + * amountA, Number + * amountB, Number + * fee, (not required) Number + * datetime + * }; + */ + function getOpenPositions(pMarket, callBack) { + + const handle = (err, response) => { + let exchangePositions = []; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + for (let i = 0; i < response.length; i++) { + let openPosition = { + id: response[i].orderNumber, + type: response[i].type, + rate: Number(response[i].rate), + amountA: Number(response[i].total), + amountB: Number(response[i].amount), + date: (new Date(response[i].time)).valueOf() + }; + exchangePositions.push(openPosition); + } + } + callBack(err, exchangePositions); + }; + + const fetch = next => API.returnOpenOrders(pMarket.assetA, pMarket.assetB, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* + * Returns the trades for a given order number. + * The object returned is an array of positions: + * position = { + * id, + * type, + * rate, Number + * amountA, Number + * amountB, Number + * fee, Number + * datetime + * }; + */ + function getExecutedTrades(pPositionId, callBack) { + + const handle = (err, response) => { + let trades = []; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + for (let i = 0; i < response.length; i++) { + let trade = { + id: response[i].tradeID, + type: response[i].type, + rate: Number(response[i].rate), + amountA: Number(response[i].total), + amountB: Number(response[i].amount), + fee: Number(response[i].fee), + date: (new Date(response[i].date)).valueOf() + } + trades.push(trade); + } + } else if (err.result === global.CUSTOM_OK_RESPONSE.result) { + // No trades found at the exchange for the position, but returning empy trades object. + err = global.DEFAULT_OK_RESPONSE; + } + callBack(err, trades); + }; + + const fetch = next => API.returnOrderTrades(pPositionId, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* + * Creates a new buy order. + * The orderNumber is returned. String + */ + function buy(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) { + + const handle = (err, response) => { + let orderNumber; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + orderNumber = response.orderNumber; + } + callBack(err, orderNumber); + }; + + const fetch = next => API.buy(pCurrencyA, pCurrencyB, pRate, pAmount, analizeResponse(next)); + + retry(null, fetch, handle); + + } + + /* + * Creates a new sell order. + * The orderNumber is returned. String + */ + function sell(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) { + + const handle = (err, response) => { + let orderNumber; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + orderNumber = response.orderNumber; + } + callBack(err, orderNumber); + }; + + const fetch = next => API.sell(pCurrencyA, pCurrencyB, pRate, pAmount, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* + * Move an existing position to the new rate. + * The orderNumber is returned. String + */ + function movePosition(pPosition, pNewRate, pNewAmountB, callBack) { + + const handle = (err, response) => { + let orderNumber; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + orderNumber = response.orderNumber; + } + callBack(err, orderNumber); + }; + + const fetch = next => API.moveOrder(pPosition.id, pNewRate, pNewAmountB, analizeResponse(next)); + + retry(null, fetch, handle); + } + + /* + * Returns all the trade history from the Exchange since startTime to endTime orderd by tradeId. + * It's possible that the exchange doesn't support this method. + * The object returned is an array of trades: + * trade = { + * tradeID, String + * globalTradeID, String + * type, String + * rate, Number + * amountA, Number + * amountB, Number + * date Date + * }; + */ + function getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack) { + + const handle = (err, response) => { + let trades = []; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + for (let i = 0; i < response.length; i++) { + let trade = { + tradeID: response[i].tradeID, + globalTradeID: response[i].globalTradeID, + type: response[i].type, + rate: Number(response[i].rate), + total: Number(response[i].total), + amount: Number(response[i].amount), + date: new Date(response[i].date) + } + trades.push(trade); + } + } + callBack(err, trades); + }; + + const fetch = next => API.returnTradeHistory(assetA, assetB, startTime, endTime, analizeResponse(next)); + + retry(null, fetch, handle); + } + + function isValidLot(price, amount) { + return amount * price >= 0.0001; + } + + function analizeResponse(callBack) { + + return (exchangeErr, exchangeResponse) => { + let error; + + /* This function analizes the different situations we might encounter trying to access Poloniex and returns appropiate standard errors. */ + + let stringExchangeErr = JSON.stringify(exchangeErr); + let stringExchangeResponse = JSON.stringify(exchangeResponse); + + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeErr = " + stringExchangeErr); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeResponse = " + stringExchangeResponse); } + + if (exchangeErr) { + error = global.DEFAULT_FAIL_RESPONSE; + + if (includes(exchangeErr.code, recoverableErrors)) { + error.notFatal = true; + } + } else if (!exchangeResponse || exchangeResponse === undefined) { + error = { + result: global.DEFAULT_FAIL_RESPONSE.result, + message: 'Empty response', + notFatal: true + }; + } else if (includes(exchangeResponse.error, ['Please complete the security check to proceed.'])) { + error = { + result: global.DEFAULT_FAIL_RESPONSE.result, + message: 'The IP has been flagged by CloudFlare.' + }; + } else if (includes(exchangeResponse.error, [''])) { + error = { + result: global.DEFAULT_FAIL_RESPONSE.result, + message: exchangeResponse + }; + } else if (includes(exchangeResponse.error, ['Not enough'])) { + error = { + result: global.DEFAULT_RETRY_RESPONSE.result, + message: exchangeResponse.error + }; + } else if (includes(exchangeResponse.error, ['Order not found, or you are not the person who placed it.'])) { + error = { + result: global.CUSTOM_OK_RESPONSE.result, + message: exchangeResponse.error + }; + } else if (exchangeResponse.error) { + error = { + result: global.DEFAULT_FAIL_RESPONSE.result, + message: exchangeResponse.error + }; + } + + return callBack(error, exchangeResponse); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] analizeResponse -> err.message = " + err.message); + return callBack(global.DEFAULT_FAIL_RESPONSE, exchangeResponse); + } + } + } + +} diff --git a/Exchange/wrappers/poloniexProperties.json b/Exchange/wrappers/poloniexProperties.json new file mode 100644 index 000000000..a5716ba3b --- /dev/null +++ b/Exchange/wrappers/poloniexProperties.json @@ -0,0 +1,3513 @@ +{ + "currencies": ["BTC", "ETH", "XMR", "USDT"], + "assets": [ + "1CR", "ABY", "AC", "ACH", "ADN", "AEON", "AERO", "AIR", "AMP", "APH", + "ARCH", "AUR", "AXIS", "BALLS", "BANK", "BBL", "BBR", "BCC", "BCH", "BCN", + "BCY", "BDC", "BDG", "BELA", "BITCNY", "BITS", "BITUSD", "BLK", "BLOCK", + "BLU", "BNS", "BONES", "BOST", "BTC", "BTCD", "BTCS", "BTM", "BTS", + "BURN", "BURST", "C2", "CACH", "CAI", "CC", "CCN", "CGA", "CHA", "CINNI", + "CLAM", "CNL", "CNMT", "CNOTE", "COMM", "CON", "CORG", "CRYPT", "CURE", + "CVC", "CYC", "DAO", "DASH", "DCR", "DGB", "DICE", "DIEM", "DIME", "DIS", "DNS", + "DOGE", "DRKC", "DRM", "DSH", "DVK", "EAC", "EBT", "ECC", "EFL", "EMC2", + "EMO", "ENC", "ETC", "ETH", "eTOK", "EXE", "EXP", "FAC", "FCN", "FCT", + "FIBRE", "FLAP", "FLDC", "FLO", "FLT", "FOX", "FRAC", "FRK", "FRQ", "GNO", + "FVZ", "FZ", "FZN", "GAME", "GAP", "GAS", "GDN", "GEMZ", "GEO", "GIAR", "GLB", + "GML", "GNS", "GNT", "GOLD", "GPC", "GPUC", "GRC", "GRCX", "GRS", "GUE", "H2O", + "HIRO", "HOT", "HUC", "HUGE", "HVC", "HYP", "HZ", "IFC", "INDEX", "IOC", + "ITC", "IXC", "JLH", "JPC", "JUG", "KDC", "KEY", "LBC", "LC", "LCL", + "LEAF", "LGC", "LOL", "LOVE", "LQD", "LSK", "LTBC", "LTC", "LTCX", + "MAID", "MAST", "MAX", "MCN", "MEC", "METH", "MIL", "MIN", "MINT", "MMC", + "MMNXT", "MMXIV", "MNTA", "MON", "MRC", "MRS", "MTS", "MUN", "MYR", + "MZC", "N5X", "NAS", "NAUT", "NAV", "NBT", "NEOS", "NL", "NMC", "NOBL", + "NOTE", "NOXT", "NRS", "NSR", "NTX", "NXT", "NXTI", "OMG", "OMNI", "OPAL", + "PAND", "PASC", "PAWN", "PIGGY", "PINK", "PLX", "PMC", "POT", "PPC", "PRC", + "PRT", "PTS", "Q2C", "QBK", "QCN", "QORA", "QTL", "RADS", "RBY", "RDD", "REP", + "RIC", "RZR", "SBD", "SC", "SDC", "SHIBE", "SHOPX", "SILK", "SJCX", + "SLR", "SMC", "SOC", "SPA", "SQL", "SRCC", "SRG", "SSD", "STEEM", "STR", + "SUM", "SUN", "SWARM", "SXC", "SYNC", "SYS", "TAC", "TOR", "TRUST", + "TWE", "UIS", "ULTC", "UNITY", "URO", "USDE", "USDT", "UTC", "UTIL", + "UVC", "VIA", "VOOT", "VOX", "VRC", "VTC", "WC", "WDC", "WIKI", "WOLF", + "X13", "XAI", "XAP", "XBC", "XC", "XCH", "XCN", "XCP", "XCR", "XDN", + "XDP", "XEM", "XHC", "XLB", "XMG", "XMR", "XPB", "XPM", "XRP", "XSI", + "XST", "XSV", "XUSD", "XVC", "XXC", "BCH", "YACC", "YANG", "YC", "YIN", "ZEC", + "ZRX" + ], + "markets": [ + { + "pair": [ + "BTC", + "1CR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ABY" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "AC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ACH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ADN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "AEON" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "AERO" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "AIR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "AMP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "APH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ARCH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "AUR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "AXIS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BALLS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BANK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BBL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BBR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BCC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BCN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BCH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BCY" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BDC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BDG" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BELA" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BITCNY" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BITS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BITUSD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BLK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BLOCK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BLU" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BNS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BONES" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BOST" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BTCD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BTCS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BTM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BTS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BURN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "BURST" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "C2" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CACH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CAI" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CCN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CGA" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CHA" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CINNI" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CLAM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CNL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CNMT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CNOTE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "COMM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CON" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CORG" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CRYPT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CURE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CVC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "CYC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DAO" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DASH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DCR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DGB" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DICE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DIEM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DIME" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DIS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DNS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DOGE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DRKC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DRM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DSH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "DVK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "EAC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "EBT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ECC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "EFL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "EMC2" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "EMO" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ENC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ETC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ETH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "eTOK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "EXE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "EXP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FAC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FCN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FCT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FIBRE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FLAP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FLDC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FLO" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FLT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FOX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FRAC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FRK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FRQ" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FVZ" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FZ" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "FZN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GAME" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GAP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GAS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GDN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GEMZ" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GEO" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GIAR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GLB" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GML" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GNS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GOLD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GPC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GPUC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GRC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GRCX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GRS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "GUE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "H2O" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "HIRO" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "HOT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "HUC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "HUGE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "HVC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "HYP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "HZ" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "IFC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "INDEX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "IOC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ITC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "IXC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "JLH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "JPC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "JUG" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "KDC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "KEY" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LBC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LCL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LEAF" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LGC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LOL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LOVE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LQD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LSK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LTBC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LTC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "LTCX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MAID" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MAST" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MAX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MCN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MEC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "METH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MIL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MIN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MINT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MMC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MMNXT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MMXIV" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MNTA" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MON" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MRC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MRS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MTS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MUN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MYR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "MZC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "N5X" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NAS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NAUT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NAV" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NBT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NEOS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NMC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NOBL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NOTE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NOXT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NRS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NSR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NTX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NXT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "NXTI" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "OMG" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "OMNI" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "OPAL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PAND" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PASC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PAWN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PIGGY" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PINK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PLX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PMC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "POT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PPC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PRC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PRT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "PTS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "Q2C" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "QBK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "QCN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "QORA" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "QTL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "RADS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "RBY" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "RDD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "REP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "RIC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "RZR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SBD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SDC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SHIBE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SHOPX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SILK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SJCX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SLR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SMC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SOC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SPA" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SQL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SRCC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SRG" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SSD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "STEEM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "STR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SUM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SUN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SWARM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SXC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SYNC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "SYS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "TAC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "TOR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "TRUST" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "TWE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "UIS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ULTC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "UNITY" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "URO" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "USDE" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "USDT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "UTC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "UTIL" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "UVC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "VIA" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "VOOT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "VOX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "VRC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "VTC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "WC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "WDC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "WIKI" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "WOLF" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "X13" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XAI" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XAP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XBC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XCH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XCN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XCP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XCR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XDN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XDP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XEM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XHC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XLB" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XMG" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XMR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XPB" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XPM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XRP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XSI" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XST" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XSV" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XUSD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XVC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "XXC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "YACC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "YANG" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "YC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "YIN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ZEC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "BTC", + "ZRX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "BTC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "BCH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "DASH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "ETC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "ETH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "LTC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "NXT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "REP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "STR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "XMR" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "XRP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "USDT", + "ZEC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "CVC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "ETC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "BCH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "GAS" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "GNO" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "GNT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "LSK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "OMG" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "REP" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "STEEM" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "ZEC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "ETH", + "ZRX" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "XMR", + "BCN" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "XMR", + "BLK" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "XMR", + "BTCD" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "XMR", + "DASH" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "XMR", + "LTC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "XMR", + "MAID" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "XMR", + "NXT" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + }, + { + "pair": [ + "XMR", + "ZEC" + ], + "maxDecimals": 8, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + } + ] +} \ No newline at end of file From f5620d8b0d1c0de380b9b677b4ab6d3742a74c35 Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Sun, 10 Feb 2019 18:51:59 -0300 Subject: [PATCH 22/76] Uppercase Exchange folder --- TradingBotProcessMainLoop.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TradingBotProcessMainLoop.js b/TradingBotProcessMainLoop.js index b31cc9492..31e20790b 100644 --- a/TradingBotProcessMainLoop.js +++ b/TradingBotProcessMainLoop.js @@ -181,7 +181,7 @@ /* We define here all the modules that the rest of the infraestructure, including the bots themselves can consume. */ const UTILITIES = require(ROOT_DIR + 'CloudUtilities'); - const EXCHANGE_API = require(ROOT_DIR + 'exchange/ExchangeAPI'); + const EXCHANGE_API = require(ROOT_DIR + 'Exchange/ExchangeAPI'); const CONTEXT = require(ROOT_DIR + 'Context'); const ASSISTANT = require(ROOT_DIR + 'Assistant'); const STATUS_REPORT = require(ROOT_DIR + 'StatusReport'); From 08be48ba08834aa22fa75006c7364d2ea699777e Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Mon, 11 Feb 2019 19:54:27 -0300 Subject: [PATCH 23/76] Temporary fix for market rate not available --- Assistant.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Assistant.js b/Assistant.js index f5e86c857..d4fbb4346 100644 --- a/Assistant.js +++ b/Assistant.js @@ -182,7 +182,9 @@ end: candleArray[i][5] }; - if (bot.processDatetime.valueOf() >= candle.begin && bot.processDatetime.valueOf() < candle.end) { + // TODO condition added for when there is no market rate available. + if ((bot.processDatetime.valueOf() >= candle.begin && bot.processDatetime.valueOf() < candle.end) + || (i + 1) === candleArray.length) { marketRate = (candle.open + candle.close) / 2; marketRate = thisObject.truncDecimals(marketRate); @@ -198,7 +200,6 @@ return; } } - } catch (err) { logger.write(MODULE_NAME, "[ERROR] initialize -> getMarketRateFromIndicator -> onFileReceived -> err = " + err.message); logger.write(MODULE_NAME, "[ERROR] initialize -> getMarketRateFromIndicator -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry."); From f64c92ef555b1c4d6eccdd66c70c0ea79222d0a7 Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Wed, 13 Feb 2019 17:24:17 -0300 Subject: [PATCH 24/76] Updating to axios and new sing method on key vault --- Exchange/ExchangeAPI.js | 51 +++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/Exchange/ExchangeAPI.js b/Exchange/ExchangeAPI.js index 2ad5eddfd..3dde860f9 100644 --- a/Exchange/ExchangeAPI.js +++ b/Exchange/ExchangeAPI.js @@ -7,7 +7,7 @@ */ const _ = require('lodash') const isValidOrder = require('./exchangeUtils').isValidOrder - const graphqlClient = require('graphql-client') + const axios = require('axios') const appRoot = require('app-root-path') const auth = require(`${appRoot}/utils/auth`) @@ -55,37 +55,38 @@ function createKeyVaultAPIClient(authToken) { if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createKeyVaultAPIClient -> Entering function."); } - const keyVaultAPI = graphqlClient({ - url: global.GATEWAY_ENDPOINT, - headers: { - Authorization: 'Bearer ' + authToken - } - }); - + const keyVaultAPI = {} keyVaultAPI.signTransaction = function (transaction, next) { - let variables = { - botId: bot.codeName, - transaction: transaction - } + axios({ + url: global.GATEWAY_ENDPOINT, + method: 'post', + data: { + query: ` + mutation keyVault_SignTransaction($keyId: String!, $cloneId: String!, $transaction: String!){ + keyVault_SignTransaction(keyId: $keyId, cloneId: $cloneId, transaction: $transaction){ + key, + signature, + date + } + } + `, + variables: { + keyId: process.env.KEY_ID, + cloneId: process.env.CLONE_ID, + transaction: transaction + } + }, + headers: { + authorization: 'Bearer ' + authToken + } - keyVaultAPI.query(` - mutation($botId: String, $transaction: String!){ - keyVault_SignTransaction(botId: $botId, transaction: $transaction){ - key, - signature, - date - } - }`, variables, function (req, res) { - if (res.status === 401) { - next(undefined, 'Error from graphql: Not authorized'); - } }).then(res => { if (res.errors) { next(undefined, 'Error from graphql: ' + res.errors); } else { let signature = { - Key: res.data.keyVault_SignTransaction.key, - Sign: res.data.keyVault_SignTransaction.signature + Key: res.data.data.keyVault_SignTransaction.key, + Sign: res.data.data.keyVault_SignTransaction.signature } next(signature) } From 4d040981541e5bffdd07d6f5495b0ff260cae353 Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Wed, 13 Feb 2019 17:25:06 -0300 Subject: [PATCH 25/76] Not loging all the response from the exchanges --- Exchange/wrappers/poloniexClient.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Exchange/wrappers/poloniexClient.js b/Exchange/wrappers/poloniexClient.js index 7476728c1..368ce01cc 100644 --- a/Exchange/wrappers/poloniexClient.js +++ b/Exchange/wrappers/poloniexClient.js @@ -6,7 +6,7 @@ */ const FULL_LOG = true; - const LOG_FILE_CONTENT = true; + const LOG_FILE_CONTENT = false; const MODULE_NAME = "poloniexClient"; const retry = require('../exchangeUtils').retry; @@ -300,7 +300,7 @@ try { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeErr = " + stringExchangeErr); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeResponse = " + stringExchangeResponse); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeResponse = " + stringExchangeResponse); } if (exchangeErr) { error = global.DEFAULT_FAIL_RESPONSE; From e9e4d6456f551a13da64e5ac8b956eb53fab6583 Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Wed, 13 Feb 2019 17:25:31 -0300 Subject: [PATCH 26/76] Removing graphql-client lib --- package-lock.json | 377 ++++++++++++++++++++-------------------------- package.json | 1 - 2 files changed, 165 insertions(+), 213 deletions(-) diff --git a/package-lock.json b/package-lock.json index fb0afbaa8..81321f1c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,10 +20,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "apollo-boost": { @@ -31,14 +31,14 @@ "resolved": "https://registry.npmjs.org/apollo-boost/-/apollo-boost-0.1.16.tgz", "integrity": "sha512-ppnQr90n2cn0ZMveEbqxW6NxmskIpThiLziLlRpRLy4keoAICg1NZecxJQmeaBLMtyhf5UholAjpS2SLmEJeHg==", "requires": { - "apollo-cache": "1.1.17", - "apollo-cache-inmemory": "1.2.10", - "apollo-client": "2.4.2", - "apollo-link": "1.2.3", - "apollo-link-error": "1.1.1", - "apollo-link-http": "1.5.5", - "apollo-link-state": "0.4.2", - "graphql-tag": "2.10.0" + "apollo-cache": "^1.1.17", + "apollo-cache-inmemory": "^1.2.10", + "apollo-client": "^2.4.2", + "apollo-link": "^1.0.6", + "apollo-link-error": "^1.0.3", + "apollo-link-http": "^1.3.1", + "apollo-link-state": "^0.4.0", + "graphql-tag": "^2.4.2" } }, "apollo-cache": { @@ -46,7 +46,7 @@ "resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.1.17.tgz", "integrity": "sha512-7sp24n2HZO4vXgTaKNomLyIfGxG4gDdDkBB0jkRzRi7HhnKmfwhiF/RCiKNbgLdrPX151INdls0KwIVliD0dHQ==", "requires": { - "apollo-utilities": "1.0.21" + "apollo-utilities": "^1.0.21" } }, "apollo-cache-inmemory": { @@ -54,9 +54,9 @@ "resolved": "https://registry.npmjs.org/apollo-cache-inmemory/-/apollo-cache-inmemory-1.2.10.tgz", "integrity": "sha512-eBusPFVtYIuo+PIfJdAwUCQ4cs7AJ4mB7sTdXxNQCXToYw8mzE6EfHnV37kdVfBXSaa82BzE2rb/YUq/duuamw==", "requires": { - "apollo-cache": "1.1.17", - "apollo-utilities": "1.0.21", - "graphql-anywhere": "4.1.19" + "apollo-cache": "^1.1.17", + "apollo-utilities": "^1.0.21", + "graphql-anywhere": "^4.1.19" } }, "apollo-client": { @@ -65,13 +65,13 @@ "integrity": "sha512-g1z23umaVSoKLj9xNl0aAnk2KBF4JeBi7MeKFc9CGTixH7TkqeQUQtxcjrC7j2h4KmDbuhOAHOFUGf8YshN+ag==", "requires": { "@types/async": "2.0.49", - "@types/zen-observable": "0.8.0", + "@types/zen-observable": "^0.8.0", "apollo-cache": "1.1.17", - "apollo-link": "1.2.3", - "apollo-link-dedup": "1.0.10", + "apollo-link": "^1.0.0", + "apollo-link-dedup": "^1.0.0", "apollo-utilities": "1.0.21", - "symbol-observable": "1.2.0", - "zen-observable": "0.8.9" + "symbol-observable": "^1.0.2", + "zen-observable": "^0.8.0" } }, "apollo-link": { @@ -79,8 +79,8 @@ "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.3.tgz", "integrity": "sha512-iL9yS2OfxYhigme5bpTbmRyC+Htt6tyo2fRMHT3K1XRL/C5IQDDz37OjpPy4ndx7WInSvfSZaaOTKFja9VWqSw==", "requires": { - "apollo-utilities": "1.0.21", - "zen-observable-ts": "0.8.10" + "apollo-utilities": "^1.0.0", + "zen-observable-ts": "^0.8.10" } }, "apollo-link-dedup": { @@ -88,7 +88,7 @@ "resolved": "https://registry.npmjs.org/apollo-link-dedup/-/apollo-link-dedup-1.0.10.tgz", "integrity": "sha512-tpUI9lMZsidxdNygSY1FxflXEkUZnvKRkMUsXXuQUNoSLeNtEvUX7QtKRAl4k9ubLl8JKKc9X3L3onAFeGTK8w==", "requires": { - "apollo-link": "1.2.3" + "apollo-link": "^1.2.3" } }, "apollo-link-error": { @@ -96,7 +96,7 @@ "resolved": "https://registry.npmjs.org/apollo-link-error/-/apollo-link-error-1.1.1.tgz", "integrity": "sha512-/yPcaQWcBdB94vpJ4FsiCJt1dAGGRm+6Tsj3wKwP+72taBH+UsGRQQZk7U/1cpZwl1yqhHZn+ZNhVOebpPcIlA==", "requires": { - "apollo-link": "1.2.3" + "apollo-link": "^1.2.3" } }, "apollo-link-http": { @@ -104,8 +104,8 @@ "resolved": "https://registry.npmjs.org/apollo-link-http/-/apollo-link-http-1.5.5.tgz", "integrity": "sha512-C5N6N/mRwmepvtzO27dgMEU3MMtRKSqcljBkYNZmWwH11BxkUQ5imBLPM3V4QJXNE7NFuAQAB5PeUd4ligivTQ==", "requires": { - "apollo-link": "1.2.3", - "apollo-link-http-common": "0.2.5" + "apollo-link": "^1.2.3", + "apollo-link-http-common": "^0.2.5" } }, "apollo-link-http-common": { @@ -113,7 +113,7 @@ "resolved": "https://registry.npmjs.org/apollo-link-http-common/-/apollo-link-http-common-0.2.5.tgz", "integrity": "sha512-6FV1wr5AqAyJ64Em1dq5hhGgiyxZE383VJQmhIoDVc3MyNcFL92TkhxREOs4rnH2a9X2iJMko7nodHSGLC6d8w==", "requires": { - "apollo-link": "1.2.3" + "apollo-link": "^1.2.3" } }, "apollo-link-state": { @@ -121,8 +121,8 @@ "resolved": "https://registry.npmjs.org/apollo-link-state/-/apollo-link-state-0.4.2.tgz", "integrity": "sha512-xMPcAfuiPVYXaLwC6oJFIZrKgV3GmdO31Ag2eufRoXpvT0AfJZjdaPB4450Nu9TslHRePN9A3quxNueILlQxlw==", "requires": { - "apollo-utilities": "1.0.21", - "graphql-anywhere": "4.1.19" + "apollo-utilities": "^1.0.8", + "graphql-anywhere": "^4.1.0-alpha.0" } }, "apollo-utilities": { @@ -130,8 +130,8 @@ "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.0.21.tgz", "integrity": "sha512-ZcxELlEl+sDCYBgEMdNXJAsZtRVm8wk4HIA58bMsqYfd1DSAJQEtZ93F0GZgYNAGy3QyaoBeZtbb0/01++G8JQ==", "requires": { - "fast-json-stable-stringify": "2.0.0", - "fclone": "1.0.11" + "fast-json-stable-stringify": "^2.0.0", + "fclone": "^1.0.11" } }, "app-root-path": { @@ -144,7 +144,7 @@ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": "~2.1.0" } }, "assert": { @@ -165,7 +165,7 @@ "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", "requires": { - "lodash": "4.17.11" + "lodash": "^4.17.10" } }, "asynckit": { @@ -188,8 +188,8 @@ "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", "requires": { - "follow-redirects": "1.6.1", - "is-buffer": "1.1.6" + "follow-redirects": "^1.3.0", + "is-buffer": "^1.1.5" } }, "azure-storage": { @@ -197,17 +197,17 @@ "resolved": "https://registry.npmjs.org/azure-storage/-/azure-storage-2.10.2.tgz", "integrity": "sha512-pOyGPya9+NDpAfm5YcFfklo57HfjDbYLXxs4lomPwvRxmb0Di/A+a+RkUmEFzaQ8S13CqxK40bRRB0sjj2ZQxA==", "requires": { - "browserify-mime": "1.2.9", - "extend": "3.0.2", + "browserify-mime": "~1.2.9", + "extend": "^3.0.2", "json-edm-parser": "0.1.2", "md5.js": "1.3.4", - "readable-stream": "2.0.6", - "request": "2.88.0", - "underscore": "1.8.3", - "uuid": "3.3.2", - "validator": "9.4.1", + "readable-stream": "~2.0.0", + "request": "^2.86.0", + "underscore": "~1.8.3", + "uuid": "^3.0.0", + "validator": "~9.4.1", "xml2js": "0.2.8", - "xmlbuilder": "9.0.7" + "xmlbuilder": "^9.0.7" }, "dependencies": { "underscore": { @@ -223,7 +223,7 @@ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "optional": true, "requires": { - "tweetnacl": "0.14.5" + "tweetnacl": "^0.14.3" } }, "browserify-mime": { @@ -251,8 +251,8 @@ "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", "requires": { - "color-convert": "1.9.3", - "color-string": "1.5.3" + "color-convert": "^1.9.1", + "color-string": "^1.5.2" } }, "color-convert": { @@ -273,8 +273,8 @@ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", "requires": { - "color-name": "1.1.3", - "simple-swizzle": "0.2.2" + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" } }, "colornames": { @@ -292,8 +292,8 @@ "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.1.tgz", "integrity": "sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw==", "requires": { - "color": "3.0.0", - "text-hex": "1.0.0" + "color": "3.0.x", + "text-hex": "1.0.x" } }, "combined-stream": { @@ -301,7 +301,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "core-util-is": { @@ -314,7 +314,7 @@ "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" } }, "debug": { @@ -335,9 +335,9 @@ "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", "requires": { - "colorspace": "1.1.1", - "enabled": "1.0.2", - "kuler": "1.0.1" + "colorspace": "1.1.x", + "enabled": "1.0.x", + "kuler": "1.0.x" } }, "dotenv": { @@ -351,8 +351,8 @@ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "optional": true, "requires": { - "jsbn": "0.1.1", - "safer-buffer": "2.1.2" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "ecdsa-sig-formatter": { @@ -360,7 +360,7 @@ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz", "integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.0.1" } }, "enabled": { @@ -368,15 +368,7 @@ "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", "requires": { - "env-variable": "0.0.5" - } - }, - "encoding": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "requires": { - "iconv-lite": "0.4.24" + "env-variable": "0.0.x" } }, "env-variable": { @@ -424,7 +416,7 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.1.tgz", "integrity": "sha512-t2JCjbzxQpWvbhts3l6SH1DKzSrx8a+SsaVf4h6bG4kOXUuPYS/kg2Lr4gQSb7eemaHqJkOThF1BGyjlUkO1GQ==", "requires": { - "debug": "3.1.0" + "debug": "=3.1.0" } }, "forever-agent": { @@ -437,9 +429,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "requires": { - "asynckit": "0.4.0", + "asynckit": "^0.4.0", "combined-stream": "1.0.6", - "mime-types": "2.1.20" + "mime-types": "^2.1.12" }, "dependencies": { "combined-stream": { @@ -447,7 +439,7 @@ "resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } } } @@ -457,7 +449,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" } }, "graphql": { @@ -465,7 +457,7 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.0.2.tgz", "integrity": "sha512-gUC4YYsaiSJT1h40krG3J+USGlwhzNTXSb4IOZljn9ag5Tj+RkoXrWp+Kh7WyE3t1NCfab5kzCuxBIvOMERMXw==", "requires": { - "iterall": "1.2.2" + "iterall": "^1.2.2" } }, "graphql-anywhere": { @@ -473,15 +465,7 @@ "resolved": "https://registry.npmjs.org/graphql-anywhere/-/graphql-anywhere-4.1.19.tgz", "integrity": "sha512-mQlvbECzYPBcgBC9JsdM4v+DSvNmcIP+8Vwr+ij3gktbaLSE0Iza30mztuz40Jlf7ooMs+0emBZucNjLzqz7tA==", "requires": { - "apollo-utilities": "1.0.21" - } - }, - "graphql-client": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/graphql-client/-/graphql-client-2.0.1.tgz", - "integrity": "sha512-XXdjUD3mwsBDcUB7g+iXQeRt+3gmIbvA/Yx1nE5aq2RQmaJwiH4hEoYw27AW8cDR90pCrPlHJAb1jJq3zUMbZA==", - "requires": { - "isomorphic-fetch": "2.2.1" + "apollo-utilities": "^1.0.21" } }, "graphql-tag": { @@ -499,8 +483,8 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", "requires": { - "ajv": "5.5.2", - "har-schema": "2.0.0" + "ajv": "^5.3.0", + "har-schema": "^2.0.0" } }, "hash-base": { @@ -508,8 +492,8 @@ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "requires": { - "inherits": "2.0.1", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "http-signature": { @@ -517,17 +501,9 @@ "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.14.2" - } - }, - "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" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "inherits": { @@ -560,15 +536,6 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, - "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.7.3", - "whatwg-fetch": "3.0.0" - } - }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -590,7 +557,7 @@ "resolved": "https://registry.npmjs.org/json-edm-parser/-/json-edm-parser-0.1.2.tgz", "integrity": "sha1-HmCw/vG8CvZ7wNFG393lSGzWFbQ=", "requires": { - "jsonparse": "1.2.0" + "jsonparse": "~1.2.0" } }, "json-schema": { @@ -618,15 +585,15 @@ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.4.0.tgz", "integrity": "sha512-coyXjRTCy0pw5WYBpMvWOMN+Kjaik2MwTUIq9cna/W7NpO9E+iYbumZONAz3hcr+tXFJECoQVrtmIoC3Oz0gvg==", "requires": { - "jws": "3.2.1", - "lodash.includes": "4.3.0", - "lodash.isboolean": "3.0.3", - "lodash.isinteger": "4.0.4", - "lodash.isnumber": "3.0.3", - "lodash.isplainobject": "4.0.6", - "lodash.isstring": "4.0.1", - "lodash.once": "4.1.1", - "ms": "2.1.1" + "jws": "^3.1.5", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1" }, "dependencies": { "ms": { @@ -654,7 +621,7 @@ "requires": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.10", - "safe-buffer": "5.1.2" + "safe-buffer": "^5.0.1" } }, "jws": { @@ -662,8 +629,8 @@ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.1.tgz", "integrity": "sha512-bGA2omSrFUkd72dhh05bIAN832znP4wOU3lfuXtRBuGTbsmNmDXMQg28f0Vsxaxgk4myF5YkKQpz6qeRpMgX9g==", "requires": { - "jwa": "1.2.0", - "safe-buffer": "5.1.2" + "jwa": "^1.2.0", + "safe-buffer": "^5.0.1" } }, "kuler": { @@ -671,7 +638,7 @@ "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", "requires": { - "colornames": "1.1.1" + "colornames": "^1.1.1" } }, "lodash": { @@ -719,11 +686,11 @@ "resolved": "https://registry.npmjs.org/logform/-/logform-1.10.0.tgz", "integrity": "sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg==", "requires": { - "colors": "1.3.3", - "fast-safe-stringify": "2.0.6", - "fecha": "2.3.3", - "ms": "2.1.1", - "triple-beam": "1.3.0" + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^2.3.3", + "ms": "^2.1.1", + "triple-beam": "^1.2.0" }, "dependencies": { "ms": { @@ -738,8 +705,8 @@ "resolved": "http://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.1" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, "mime-db": { @@ -752,7 +719,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", "requires": { - "mime-db": "1.36.0" + "mime-db": "~1.36.0" } }, "ms": { @@ -760,15 +727,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "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.12", - "is-stream": "1.1.0" - } - }, "nodemailer": { "version": "4.6.8", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.6.8.tgz", @@ -824,12 +782,12 @@ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.1", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" } }, "request": { @@ -837,26 +795,26 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.8.0", - "caseless": "0.12.0", - "combined-stream": "1.0.7", - "extend": "3.0.2", - "forever-agent": "0.6.1", - "form-data": "2.3.2", - "har-validator": "5.1.0", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.20", - "oauth-sign": "0.9.0", - "performance-now": "2.1.0", - "qs": "6.5.2", - "safe-buffer": "5.1.2", - "tough-cookie": "2.4.3", - "tunnel-agent": "0.6.0", - "uuid": "3.3.2" + "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.0", + "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.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" } }, "retry": { @@ -884,7 +842,7 @@ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", "requires": { - "is-arrayish": "0.3.2" + "is-arrayish": "^0.3.1" } }, "sshpk": { @@ -892,15 +850,15 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", "requires": { - "asn1": "0.2.4", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.2", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.2", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "safer-buffer": "2.1.2", - "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", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" } }, "stack-trace": { @@ -928,8 +886,8 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "requires": { - "psl": "1.1.29", - "punycode": "1.4.1" + "psl": "^1.1.24", + "punycode": "^1.4.1" } }, "triple-beam": { @@ -942,7 +900,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { @@ -984,30 +942,25 @@ "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" } }, - "whatwg-fetch": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", - "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" - }, "winston": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/winston/-/winston-3.1.0.tgz", "integrity": "sha512-FsQfEE+8YIEeuZEYhHDk5cILo1HOcWkGwvoidLrDgPog0r4bser1lEIOco2dN9zpDJ1M88hfDgZvxe5z4xNcwg==", "requires": { - "async": "2.6.1", - "diagnostics": "1.1.1", - "is-stream": "1.1.0", - "logform": "1.10.0", + "async": "^2.6.0", + "diagnostics": "^1.1.1", + "is-stream": "^1.1.0", + "logform": "^1.9.1", "one-time": "0.0.4", - "readable-stream": "2.3.6", - "stack-trace": "0.0.10", - "triple-beam": "1.3.0", - "winston-transport": "4.3.0" + "readable-stream": "^2.3.6", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.2.0" }, "dependencies": { "inherits": { @@ -1025,13 +978,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -1039,7 +992,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -1049,8 +1002,8 @@ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", "requires": { - "readable-stream": "2.3.6", - "triple-beam": "1.3.0" + "readable-stream": "^2.3.6", + "triple-beam": "^1.2.0" }, "dependencies": { "inherits": { @@ -1068,13 +1021,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -1082,7 +1035,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -1092,7 +1045,7 @@ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.2.8.tgz", "integrity": "sha1-m4FpCTFjH/CdGVdUn69U9PmAs8I=", "requires": { - "sax": "0.5.8" + "sax": "0.5.x" } }, "xmlbuilder": { @@ -1110,7 +1063,7 @@ "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.10.tgz", "integrity": "sha512-5vqMtRggU/2GhePC9OU4sYEWOdvmayp2k3gjPf4F0mXwB3CSbbNznfDUvDJx9O2ZTa1EIXdJhPchQveFKwNXPQ==", "requires": { - "zen-observable": "0.8.9" + "zen-observable": "^0.8.0" } } } diff --git a/package.json b/package.json index fa8757b2c..76efddcc2 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,6 @@ "azure-storage": "^2.8.2", "dotenv": "^6.0.0", "graphql": "^14.0.2", - "graphql-client": "^2.0.1", "jsonwebtoken": "^8.4.0", "lodash": "^4.17.11", "nodemailer": "^4.6.8", From 49602bf12f9b44b5d1c4fad5684320312d93374a Mon Sep 17 00:00:00 2001 From: "mati108@gmail.com" <34651529+matbenitez@users.noreply.github.com> Date: Wed, 13 Feb 2019 17:25:59 -0300 Subject: [PATCH 27/76] Moving execution update to each execution --- Root.js | 21 ++------------------- TradingBotProcessMainLoop.js | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/Root.js b/Root.js index 86486ae54..aed6d7383 100644 --- a/Root.js +++ b/Root.js @@ -1,7 +1,4 @@ -const appRoot = require('app-root-path') -const operationsIntegration = require(`${appRoot}/Integrations/OperationsModuleIntegration`) - -exports.newRoot = function newRoot() { +exports.newRoot = function newRoot() { /* Callbacks default responses. */ @@ -917,21 +914,7 @@ exports.newRoot = function newRoot() { logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot execution finished with errors. Please check the logs."); logger.persist(); - } - - // Update operations module with latest context - if (context !== undefined) { - let lastExecution = context.executionHistory[context.executionHistory.length - 1] - let date = lastExecution[0] / 1000 | 0 - let buyAvgRate = lastExecution[1] - let sellAvgRate = lastExecution[2] - let marketRate = lastExecution[7] - let combinedProfitsA = lastExecution[13] - let combinedProfitsB = lastExecution[14] - - operationsIntegration.updateExecutionResults(date, buyAvgRate, sellAvgRate, - marketRate, combinedProfitsA, combinedProfitsB) - } + } } } else { diff --git a/TradingBotProcessMainLoop.js b/TradingBotProcessMainLoop.js index 31e20790b..e134dd36f 100644 --- a/TradingBotProcessMainLoop.js +++ b/TradingBotProcessMainLoop.js @@ -8,8 +8,9 @@ let USER_BOT_MODULE; let COMMONS_MODULE; - const BLOB_STORAGE = require(ROOT_DIR + 'BlobStorage'); + const operationsIntegration = require('./Integrations/OperationsModuleIntegration') + const BLOB_STORAGE = require(ROOT_DIR + 'BlobStorage'); const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog'); let logger; // We need this here in order for the loopHealth function to work and be able to rescue the loop when it gets in trouble. @@ -907,12 +908,26 @@ } } - function saveContext() { + async function saveContext() { try { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> saveContext -> Entering function."); } + // Update operations module with latest context + let lastExecution = context.newHistoryRecord + let date = lastExecution.date / 1000 | 0 + let buyAvgRate = lastExecution.buyAvgRate + let sellAvgRate = lastExecution.sellAvgRate + let marketRate = lastExecution.marketRate + let combinedProfitsA = lastExecution.combinedProfitsA + let combinedProfitsB = lastExecution.combinedProfitsB + + await operationsIntegration.updateExecutionResults(date, buyAvgRate, sellAvgRate, + marketRate, combinedProfitsA, combinedProfitsB) + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> saveContext -> Execution Results updated."); } + context.saveThemAll(onFinished); function onFinished(err) { From 8bfe11a902b0669738e9659f101781cd42929c7c Mon Sep 17 00:00:00 2001 From: Matias Date: Fri, 15 Feb 2019 10:37:59 -0300 Subject: [PATCH 28/76] Removing logger logs for now --- Integrations/OperationsModuleIntegration.js | 11 +++-------- utils/auth.js | 4 ---- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/Integrations/OperationsModuleIntegration.js b/Integrations/OperationsModuleIntegration.js index b8de71616..efdb623ac 100644 --- a/Integrations/OperationsModuleIntegration.js +++ b/Integrations/OperationsModuleIntegration.js @@ -1,13 +1,10 @@ const axios = require('axios') const appRoot = require('app-root-path') -const { logger } = require(`${appRoot}/utils/logger`) const auth = require(`${appRoot}/utils/auth`) exports.updateExecutionResults = async function (summaryDate, buyAverage, sellAverage, marketRate, combinedProfitsA, combinedProfitsB) { - logger.debug('updateExecutionResults -> Entering Function.') - try { const accessToken = await auth.authenticate() @@ -50,12 +47,10 @@ exports.updateExecutionResults = async function (summaryDate, buyAverage, sellAv } }) - if (!operationsResponse.data.errors) - logger.debug('updateExecutionResults -> Operations Module Response: %s', operationsResponse.data.data.operations_UpdateExecutionSummary) - else throw new Error(operationsResponse.data.errors[0].message) + if (operationsResponse.data.errors) + throw new Error(operationsResponse.data.errors[0].message) } catch (error) { - logger.error('updateExecutionResults -> Error: ' + error.stack) - throw new Error('There has been an error updating the execution report: ' + error) + throw new Error('There has been an error updating the execution on the clone: ' + error) } } \ No newline at end of file diff --git a/utils/auth.js b/utils/auth.js index c7f0b8d87..be0145a1f 100644 --- a/utils/auth.js +++ b/utils/auth.js @@ -1,12 +1,9 @@ const axios = require('axios') -const appRoot = require('app-root-path') -const { logger } = require(`${appRoot}/utils/logger`) exports.authenticate = async function () { try { if (!global.ACCESS_TOKEN) { - logger.debug('authenticate -> Entering Function.') const authBody = '{"client_id":"' + process.env.AUTH_CLIENT_ID + '","client_secret": "' + process.env.AUTH_CLIENT_SECRET @@ -33,7 +30,6 @@ exports.authenticate = async function () { return global.ACCESS_TOKEN } catch (error) { - logger.error('authenticate -> Error: ' + error.stack) throw new Error('There has been an error on the authentication: ' + error) } } \ No newline at end of file From 6bc057d8d493f002db9cf5563b4dfaab65258781 Mon Sep 17 00:00:00 2001 From: Matias Date: Sat, 16 Feb 2019 12:09:08 -0300 Subject: [PATCH 29/76] Removing app root --- Integrations/OperationsModuleIntegration.js | 3 +-- package-lock.json | 5 ----- package.json | 1 - utils/logger.js | 3 +-- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/Integrations/OperationsModuleIntegration.js b/Integrations/OperationsModuleIntegration.js index efdb623ac..43001d62c 100644 --- a/Integrations/OperationsModuleIntegration.js +++ b/Integrations/OperationsModuleIntegration.js @@ -1,6 +1,5 @@ const axios = require('axios') -const appRoot = require('app-root-path') -const auth = require(`${appRoot}/utils/auth`) +const auth = require('../utils/auth') exports.updateExecutionResults = async function (summaryDate, buyAverage, sellAverage, marketRate, combinedProfitsA, combinedProfitsB) { diff --git a/package-lock.json b/package-lock.json index 81321f1c6..72604727b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -134,11 +134,6 @@ "fclone": "^1.0.11" } }, - "app-root-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.1.0.tgz", - "integrity": "sha1-mL9lmTJ+zqGZMJhm6BQDaP0uZGo=" - }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", diff --git a/package.json b/package.json index 76efddcc2..90a19c944 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "license": "ISC", "dependencies": { "apollo-boost": "^0.1.16", - "app-root-path": "^2.1.0", "assert": "^1.4.1", "axios": "^0.18.0", "azure-storage": "^2.8.2", diff --git a/utils/logger.js b/utils/logger.js index 1cc942d0c..da3df770b 100644 --- a/utils/logger.js +++ b/utils/logger.js @@ -1,11 +1,10 @@ const winston = require('winston') -const appRoot = require('app-root-path') const util = require('util') const options = { file: { level: 'info', - filename: `${appRoot}/logs/app.log`, + filename: '../logs/app.log', handleExceptions: true, json: true, maxsize: 5242880, // 5MB From 26df38ea658828ae522d48f3f453d32d1c224cd6 Mon Sep 17 00:00:00 2001 From: Matias Date: Sat, 16 Feb 2019 12:09:36 -0300 Subject: [PATCH 30/76] Update execution only when running a clone in cloud --- TradingBotProcessMainLoop.js | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/TradingBotProcessMainLoop.js b/TradingBotProcessMainLoop.js index e134dd36f..634c1aeff 100644 --- a/TradingBotProcessMainLoop.js +++ b/TradingBotProcessMainLoop.js @@ -295,7 +295,7 @@ clearTimeout(nextLoopTimeoutHandle); clearTimeout(checkLoopHealthHandle); bot.enableCheckLoopHealth = false; - callBackFunction(global.DEFAULT_OK_RESPONSE, context); + callBackFunction(global.DEFAULT_OK_RESPONSE); return; } } @@ -347,7 +347,7 @@ clearTimeout(nextLoopTimeoutHandle); clearTimeout(checkLoopHealthHandle); bot.enableCheckLoopHealth = false; - callBackFunction(global.DEFAULT_OK_RESPONSE, context); + callBackFunction(global.DEFAULT_OK_RESPONSE); return; } } @@ -914,19 +914,21 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> saveContext -> Entering function."); } - // Update operations module with latest context - let lastExecution = context.newHistoryRecord - let date = lastExecution.date / 1000 | 0 - let buyAvgRate = lastExecution.buyAvgRate - let sellAvgRate = lastExecution.sellAvgRate - let marketRate = lastExecution.marketRate - let combinedProfitsA = lastExecution.combinedProfitsA - let combinedProfitsB = lastExecution.combinedProfitsB + if (global.CURRENT_EXECUTION_AT === "Cloud") { + // Update operations module with latest context + let lastExecution = context.newHistoryRecord + let date = lastExecution.date / 1000 | 0 + let buyAvgRate = lastExecution.buyAvgRate + let sellAvgRate = lastExecution.sellAvgRate + let marketRate = lastExecution.marketRate + let combinedProfitsA = lastExecution.combinedProfitsA + let combinedProfitsB = lastExecution.combinedProfitsB - await operationsIntegration.updateExecutionResults(date, buyAvgRate, sellAvgRate, - marketRate, combinedProfitsA, combinedProfitsB) + await operationsIntegration.updateExecutionResults(date, buyAvgRate, sellAvgRate, + marketRate, combinedProfitsA, combinedProfitsB) - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> saveContext -> Execution Results updated."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> saveContext -> Execution Results updated."); } + } context.saveThemAll(onFinished); @@ -1018,7 +1020,7 @@ clearTimeout(nextLoopTimeoutHandle); clearTimeout(checkLoopHealthHandle); bot.enableCheckLoopHealth = false; - callBackFunction(global.DEFAULT_OK_RESPONSE, context); + callBackFunction(global.DEFAULT_OK_RESPONSE); return; } From 2b7a824c814cf9e4ce62184e6677bbac296eb900 Mon Sep 17 00:00:00 2001 From: Matias Date: Sat, 16 Feb 2019 12:10:09 -0300 Subject: [PATCH 31/76] Using exchangeAPI from the browser --- Exchange/ExchangeAPI.js | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/Exchange/ExchangeAPI.js b/Exchange/ExchangeAPI.js index 3dde860f9..d2c1e7071 100644 --- a/Exchange/ExchangeAPI.js +++ b/Exchange/ExchangeAPI.js @@ -8,9 +8,6 @@ const _ = require('lodash') const isValidOrder = require('./exchangeUtils').isValidOrder const axios = require('axios') - const appRoot = require('app-root-path') - const auth = require(`${appRoot}/utils/auth`) - let MODULE_NAME = "Exchange API"; let thisObject = { @@ -34,14 +31,11 @@ if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } - // TODO integrate with financial beings module to get the exchange let botExchange = 'Poloniex'; let exchange = botExchange.toLowerCase() + 'Client.js'; - let api = require('./wrappers/' + exchange); + let api = require('./Wrappers/' + exchange); - const accessToken = await auth.authenticate() - - let keyVaultAPI = createKeyVaultAPIClient(accessToken) + let keyVaultAPI = createKeyVaultAPIClient() apiClient = api.newAPIClient(keyVaultAPI, logger); callBackFunction(global.DEFAULT_OK_RESPONSE); @@ -52,9 +46,23 @@ } } - function createKeyVaultAPIClient(authToken) { + function createKeyVaultAPIClient() { if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createKeyVaultAPIClient -> Entering function."); } + let accessToken + let keyId + let cloneId + if (global.CURRENT_EXECUTION_AT === "Cloud") { + keyId = process.env.KEY_ID + cloneId = process.env.CLONE_ID + + let auth = require('../utils/auth') + let authToken = await auth.authenticate() + accessToken = 'Bearer ' + authToken + } else if (global.CURRENT_EXECUTION_AT === "Browser") { + accessToken = window.localStorage.getItem('access_token') + } + const keyVaultAPI = {} keyVaultAPI.signTransaction = function (transaction, next) { axios({ @@ -62,8 +70,8 @@ method: 'post', data: { query: ` - mutation keyVault_SignTransaction($keyId: String!, $cloneId: String!, $transaction: String!){ - keyVault_SignTransaction(keyId: $keyId, cloneId: $cloneId, transaction: $transaction){ + mutation keyVault_SignTransaction($transaction: String!, $keyId: String, $cloneId: String){ + keyVault_SignTransaction(transaction: $transaction, keyId: $keyId, cloneId: $cloneId){ key, signature, date @@ -71,13 +79,13 @@ } `, variables: { - keyId: process.env.KEY_ID, - cloneId: process.env.CLONE_ID, - transaction: transaction + transaction: transaction, + keyId: keyId, + cloneId: cloneId } }, headers: { - authorization: 'Bearer ' + authToken + authorization: accessToken } }).then(res => { From c05319061f0f577c7e8f94f7b6fe5e6c30c22078 Mon Sep 17 00:00:00 2001 From: Matias Date: Sat, 16 Feb 2019 12:10:49 -0300 Subject: [PATCH 32/76] Updating browser execution configuration --- Root.js | 90 +++++++++++++++++++++++---------------------------------- 1 file changed, 36 insertions(+), 54 deletions(-) diff --git a/Root.js b/Root.js index aed6d7383..54f0992c0 100644 --- a/Root.js +++ b/Root.js @@ -341,53 +341,27 @@ if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> listItem.process = " + listItem.process); } let processConfig = botConfig.processes[i]; - processConfig.startMode = global.EXECUTION_CONFIG.startMode // Override file storage configuration - try { - - /* - - When running at the browser, the endUser can override the configured setting for the bot. In this scenario we use the commands - sent from the User Interface. - - */ - - if (UI_COMMANDS.startMode !== undefined) { - - switch (UI_COMMANDS.startMode) { - - case "Backtest": { - - processConfig.startMode.backtest.run = "true"; - processConfig.startMode.live.run = "false"; - processConfig.startMode.competition.run = "false"; - - break; - } - - case "Live": { - - processConfig.startMode.backtest.run = "false"; - processConfig.startMode.live.run = "true"; - processConfig.startMode.competition.run = "false"; - - break; - } - - case "Competition": { - - processConfig.startMode.backtest.run = "false"; - processConfig.startMode.live.run = "false"; - processConfig.startMode.competition.run = "true"; - - break; - } - } - - if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode Overwritten. "); } - if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> processConfig.startMode = " + processConfig.startMode); } - + + switch (global.CURRENT_EXECUTION_AT) { + case "Cloud": { + processConfig.startMode = global.EXECUTION_CONFIG.startMode // Override file storage configuration + break; } + case "Browser": { + let startMode = { + live: { run: "false" }, + backtest: { run: "false" }, + competition: { run: "false" } + } + let browserStartMode = global.CURRENT_START_MODE.toLowerCase() + startMode[browserStartMode].run = "true" + processConfig.startMode = startMode + break; + } + } + try { + /* We test each type of start Mode to get what to run and how. */ if (processConfig.startMode.allMonths !== undefined) { @@ -525,7 +499,7 @@ if (processConfig.startMode.live !== undefined) { - if (processConfig.startMode.live.run === "true" && global.EXECUTION_CONFIG.startMode.live.run === "true") { + if (processConfig.startMode.live.run === "true") { botConfig.startMode = "Live"; console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode); @@ -533,7 +507,7 @@ let month = pad((new Date()).getUTCMonth() + 1, 2); let year = (new Date()).getUTCFullYear(); - if (processConfig.startMode.live.resumeExecution === "true" && global.EXECUTION_CONFIG.startMode.live.resumeExecution === "true") { + if (processConfig.startMode.live.resumeExecution === "true") { botConfig.hasTheBotJustStarted = false; } else { botConfig.hasTheBotJustStarted = true; @@ -553,7 +527,7 @@ if (processConfig.startMode.backtest !== undefined) { - if (processConfig.startMode.backtest.run === "true" && global.EXECUTION_CONFIG.startMode.backtest.run === "true") { + if (processConfig.startMode.backtest.run === "true") { botConfig.startMode = "Backtest"; console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode); @@ -583,14 +557,14 @@ if (processConfig.startMode.competition !== undefined) { - if (processConfig.startMode.competition.run === "true" && global.EXECUTION_CONFIG.startMode.competition.run === "true") { + if (processConfig.startMode.competition.run === "true") { botConfig.startMode = "Competition"; console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode); botConfig.competition = processConfig.startMode.competition; - if (processConfig.startMode.competition.resumeExecution === "false" && global.EXECUTION_CONFIG.startMode.competition.resumeExecution === "false") { + if (processConfig.startMode.competition.resumeExecution === "false") { botConfig.hasTheBotJustStarted = true; } else { botConfig.hasTheBotJustStarted = false; @@ -838,7 +812,11 @@ } - let clonName = botConfig.codeName + "-" + "Clon" + clonKey + "-" + process.env.CLONE_ID; + let clonName = botConfig.codeName + "-" + "Clon" + clonKey; + + if (global.CURRENT_EXECUTION_AT === "Cloud") { + clonName += "-" + process.env.CLONE_ID; + } botConfig.filePathRoot = botConfig.devTeam + "/" + clonName + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion; @@ -858,8 +836,12 @@ /* If the bot does not have any genes at all */ let genes = {}; - let clonName = botConfig.codeName + "-" + process.env.CLONE_ID; + let clonName = botConfig.codeName; + if (global.CURRENT_EXECUTION_AT === "Cloud") { + clonName += "-" + process.env.CLONE_ID; + } + botConfig.filePathRoot = botConfig.devTeam + "/" + clonName + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion; pBotConfig.instance = clonName; @@ -889,7 +871,7 @@ tradingBotMainLoop.run(pGenes, pTotalInstances, whenRunFinishes); - function whenRunFinishes(err, context) { + function whenRunFinishes(err) { pBotConfig.loopCounter = 0; @@ -937,7 +919,7 @@ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> err.message = " + err.message); return; } - } + } } } } From 4cc17c19f8e7a028ba160a150764ae599bbb3986 Mon Sep 17 00:00:00 2001 From: Matias Date: Sat, 16 Feb 2019 12:27:05 -0300 Subject: [PATCH 33/76] lowercase folder name --- Exchange/ExchangeAPI.js | 2 +- Project.njsproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Exchange/ExchangeAPI.js b/Exchange/ExchangeAPI.js index d2c1e7071..87a951530 100644 --- a/Exchange/ExchangeAPI.js +++ b/Exchange/ExchangeAPI.js @@ -33,7 +33,7 @@ let botExchange = 'Poloniex'; let exchange = botExchange.toLowerCase() + 'Client.js'; - let api = require('./Wrappers/' + exchange); + let api = require('./wrappers/' + exchange); let keyVaultAPI = createKeyVaultAPIClient() apiClient = api.newAPIClient(keyVaultAPI, logger); diff --git a/Project.njsproj b/Project.njsproj index fe4d8f923..9edd19db5 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -91,7 +91,7 @@ - + From fd16e2700c84667b72cdeba8a1b7e9af576b25f8 Mon Sep 17 00:00:00 2001 From: Matias Date: Sat, 16 Feb 2019 19:15:07 -0300 Subject: [PATCH 34/76] Keys integration cloud and browser --- Exchange/ExchangeAPI.js | 36 ++++++++++++++++----------------- ExtractionBotProcessMainLoop.js | 2 +- Root.js | 2 +- TradingBotProcessMainLoop.js | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Exchange/ExchangeAPI.js b/Exchange/ExchangeAPI.js index 87a951530..3129473d6 100644 --- a/Exchange/ExchangeAPI.js +++ b/Exchange/ExchangeAPI.js @@ -1,4 +1,4 @@ -exports.newExchangeAPI = function newExchangeAPI(bot, logger) { +exports.newExchangeAPI = function newExchangeAPI(logger, authToken) { /* @@ -35,7 +35,21 @@ let exchange = botExchange.toLowerCase() + 'Client.js'; let api = require('./wrappers/' + exchange); - let keyVaultAPI = createKeyVaultAPIClient() + let accessToken + let keyId + let cloneId + if (global.CURRENT_EXECUTION_AT === "Cloud") { + keyId = process.env.KEY_ID + cloneId = process.env.CLONE_ID + + let auth = require('../utils/auth') + let authTokenCloud = await auth.authenticate() + accessToken = 'Bearer ' + authTokenCloud + } else if (global.CURRENT_EXECUTION_AT === "Browser") { + accessToken = 'Bearer ' + authToken + } + + let keyVaultAPI = createKeyVaultAPIClient(accessToken, keyId, cloneId) apiClient = api.newAPIClient(keyVaultAPI, logger); callBackFunction(global.DEFAULT_OK_RESPONSE); @@ -46,23 +60,9 @@ } } - function createKeyVaultAPIClient() { + function createKeyVaultAPIClient(accessToken, keyId, cloneId) { if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createKeyVaultAPIClient -> Entering function."); } - - let accessToken - let keyId - let cloneId - if (global.CURRENT_EXECUTION_AT === "Cloud") { - keyId = process.env.KEY_ID - cloneId = process.env.CLONE_ID - - let auth = require('../utils/auth') - let authToken = await auth.authenticate() - accessToken = 'Bearer ' + authToken - } else if (global.CURRENT_EXECUTION_AT === "Browser") { - accessToken = window.localStorage.getItem('access_token') - } - + const keyVaultAPI = {} keyVaultAPI.signTransaction = function (transaction, next) { axios({ diff --git a/ExtractionBotProcessMainLoop.js b/ExtractionBotProcessMainLoop.js index e3caf7318..81b4b90a5 100644 --- a/ExtractionBotProcessMainLoop.js +++ b/ExtractionBotProcessMainLoop.js @@ -275,7 +275,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeExchangeAPI -> Entering function."); } - exchangeAPI = EXCHANGE_API.newExchangeAPI(bot, logger); + exchangeAPI = EXCHANGE_API.newExchangeAPI(logger); exchangeAPI.initialize(onInizialized); diff --git a/Root.js b/Root.js index 54f0992c0..e70a63ece 100644 --- a/Root.js +++ b/Root.js @@ -350,7 +350,7 @@ case "Browser": { let startMode = { live: { run: "false" }, - backtest: { run: "false" }, + backtest: { run: "false", waitTime: 5000 }, competition: { run: "false" } } let browserStartMode = global.CURRENT_START_MODE.toLowerCase() diff --git a/TradingBotProcessMainLoop.js b/TradingBotProcessMainLoop.js index 634c1aeff..4e90cc9de 100644 --- a/TradingBotProcessMainLoop.js +++ b/TradingBotProcessMainLoop.js @@ -617,7 +617,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeExchangeAPI -> Entering function."); } - exchangeAPI = EXCHANGE_API.newExchangeAPI(bot, logger); + exchangeAPI = EXCHANGE_API.newExchangeAPI(logger); exchangeAPI.initialize(onInizialized); From c246f57c7d4c39f3011c9e0dea10b40135d028ec Mon Sep 17 00:00:00 2001 From: Matias Date: Sat, 16 Feb 2019 21:21:05 -0300 Subject: [PATCH 35/76] Removing email notification --- TradingBotProcessMainLoop.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/TradingBotProcessMainLoop.js b/TradingBotProcessMainLoop.js index 4e90cc9de..85ac5cab1 100644 --- a/TradingBotProcessMainLoop.js +++ b/TradingBotProcessMainLoop.js @@ -864,8 +864,7 @@ clearInterval(fixedTimeLoopIntervalHandle); clearTimeout(nextLoopTimeoutHandle); clearTimeout(checkLoopHealthHandle); - bot.enableCheckLoopHealth = false; - assistant.sendEmail("FAIL", "Operation Failed. Aborting the process. err = " + err.message, emailList = global.EMAIL_CONFIG.adminList); + bot.enableCheckLoopHealth = false; callBackFunction(err); return; } @@ -878,7 +877,6 @@ clearTimeout(nextLoopTimeoutHandle); clearTimeout(checkLoopHealthHandle); bot.enableCheckLoopHealth = false; - assistant.sendEmail("FAIL", "Operation Failed. Aborting the process. err = " + err.message, emailList = global.EMAIL_CONFIG.adminList); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return; } @@ -891,7 +889,6 @@ clearTimeout(nextLoopTimeoutHandle); clearTimeout(checkLoopHealthHandle); bot.enableCheckLoopHealth = false; - assistant.sendEmail("FAIL", "Operation Failed. Aborting the process. err = " + err.message, emailList = global.EMAIL_CONFIG.adminList); callBackFunction(err); } } @@ -903,7 +900,6 @@ clearTimeout(nextLoopTimeoutHandle); clearTimeout(checkLoopHealthHandle); bot.enableCheckLoopHealth = false; - assistant.sendEmail("FAIL", "Operation Failed. Aborting the process. err = " + err.message, emailList = global.EMAIL_CONFIG.adminList); callBackFunction(err); } } From 784445bafc740c1047c01880ceb3d238a52189d2 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 18 Feb 2019 14:46:52 +0100 Subject: [PATCH 36/76] Error text improved --- Run.js | 1 + package-lock.json | 330 +++++++++++++++++++++++----------------------- this.config.json | 7 + 3 files changed, 173 insertions(+), 165 deletions(-) diff --git a/Run.js b/Run.js index 2abe7cb4c..1f79b005c 100644 --- a/Run.js +++ b/Run.js @@ -130,6 +130,7 @@ function readExecutionConfiguration() { catch (err) { console.log("[ERROR] readExecutionConfiguration -> err = " + err.message); + console.log("[ERROR] readExecutionConfiguration -> Please verify that the Start Mode for the type of Bot configured applies to that type."); console.log("[ERROR] readExecutionConfiguration -> err = " + err.stack); } } diff --git a/package-lock.json b/package-lock.json index 72604727b..6bba6e4e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,10 +20,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" } }, "apollo-boost": { @@ -31,14 +31,14 @@ "resolved": "https://registry.npmjs.org/apollo-boost/-/apollo-boost-0.1.16.tgz", "integrity": "sha512-ppnQr90n2cn0ZMveEbqxW6NxmskIpThiLziLlRpRLy4keoAICg1NZecxJQmeaBLMtyhf5UholAjpS2SLmEJeHg==", "requires": { - "apollo-cache": "^1.1.17", - "apollo-cache-inmemory": "^1.2.10", - "apollo-client": "^2.4.2", - "apollo-link": "^1.0.6", - "apollo-link-error": "^1.0.3", - "apollo-link-http": "^1.3.1", - "apollo-link-state": "^0.4.0", - "graphql-tag": "^2.4.2" + "apollo-cache": "1.1.17", + "apollo-cache-inmemory": "1.2.10", + "apollo-client": "2.4.2", + "apollo-link": "1.2.3", + "apollo-link-error": "1.1.1", + "apollo-link-http": "1.5.5", + "apollo-link-state": "0.4.2", + "graphql-tag": "2.10.0" } }, "apollo-cache": { @@ -46,7 +46,7 @@ "resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.1.17.tgz", "integrity": "sha512-7sp24n2HZO4vXgTaKNomLyIfGxG4gDdDkBB0jkRzRi7HhnKmfwhiF/RCiKNbgLdrPX151INdls0KwIVliD0dHQ==", "requires": { - "apollo-utilities": "^1.0.21" + "apollo-utilities": "1.0.21" } }, "apollo-cache-inmemory": { @@ -54,9 +54,9 @@ "resolved": "https://registry.npmjs.org/apollo-cache-inmemory/-/apollo-cache-inmemory-1.2.10.tgz", "integrity": "sha512-eBusPFVtYIuo+PIfJdAwUCQ4cs7AJ4mB7sTdXxNQCXToYw8mzE6EfHnV37kdVfBXSaa82BzE2rb/YUq/duuamw==", "requires": { - "apollo-cache": "^1.1.17", - "apollo-utilities": "^1.0.21", - "graphql-anywhere": "^4.1.19" + "apollo-cache": "1.1.17", + "apollo-utilities": "1.0.21", + "graphql-anywhere": "4.1.19" } }, "apollo-client": { @@ -65,13 +65,13 @@ "integrity": "sha512-g1z23umaVSoKLj9xNl0aAnk2KBF4JeBi7MeKFc9CGTixH7TkqeQUQtxcjrC7j2h4KmDbuhOAHOFUGf8YshN+ag==", "requires": { "@types/async": "2.0.49", - "@types/zen-observable": "^0.8.0", + "@types/zen-observable": "0.8.0", "apollo-cache": "1.1.17", - "apollo-link": "^1.0.0", - "apollo-link-dedup": "^1.0.0", + "apollo-link": "1.2.3", + "apollo-link-dedup": "1.0.10", "apollo-utilities": "1.0.21", - "symbol-observable": "^1.0.2", - "zen-observable": "^0.8.0" + "symbol-observable": "1.2.0", + "zen-observable": "0.8.9" } }, "apollo-link": { @@ -79,8 +79,8 @@ "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.3.tgz", "integrity": "sha512-iL9yS2OfxYhigme5bpTbmRyC+Htt6tyo2fRMHT3K1XRL/C5IQDDz37OjpPy4ndx7WInSvfSZaaOTKFja9VWqSw==", "requires": { - "apollo-utilities": "^1.0.0", - "zen-observable-ts": "^0.8.10" + "apollo-utilities": "1.0.21", + "zen-observable-ts": "0.8.10" } }, "apollo-link-dedup": { @@ -88,7 +88,7 @@ "resolved": "https://registry.npmjs.org/apollo-link-dedup/-/apollo-link-dedup-1.0.10.tgz", "integrity": "sha512-tpUI9lMZsidxdNygSY1FxflXEkUZnvKRkMUsXXuQUNoSLeNtEvUX7QtKRAl4k9ubLl8JKKc9X3L3onAFeGTK8w==", "requires": { - "apollo-link": "^1.2.3" + "apollo-link": "1.2.3" } }, "apollo-link-error": { @@ -96,7 +96,7 @@ "resolved": "https://registry.npmjs.org/apollo-link-error/-/apollo-link-error-1.1.1.tgz", "integrity": "sha512-/yPcaQWcBdB94vpJ4FsiCJt1dAGGRm+6Tsj3wKwP+72taBH+UsGRQQZk7U/1cpZwl1yqhHZn+ZNhVOebpPcIlA==", "requires": { - "apollo-link": "^1.2.3" + "apollo-link": "1.2.3" } }, "apollo-link-http": { @@ -104,8 +104,8 @@ "resolved": "https://registry.npmjs.org/apollo-link-http/-/apollo-link-http-1.5.5.tgz", "integrity": "sha512-C5N6N/mRwmepvtzO27dgMEU3MMtRKSqcljBkYNZmWwH11BxkUQ5imBLPM3V4QJXNE7NFuAQAB5PeUd4ligivTQ==", "requires": { - "apollo-link": "^1.2.3", - "apollo-link-http-common": "^0.2.5" + "apollo-link": "1.2.3", + "apollo-link-http-common": "0.2.5" } }, "apollo-link-http-common": { @@ -113,7 +113,7 @@ "resolved": "https://registry.npmjs.org/apollo-link-http-common/-/apollo-link-http-common-0.2.5.tgz", "integrity": "sha512-6FV1wr5AqAyJ64Em1dq5hhGgiyxZE383VJQmhIoDVc3MyNcFL92TkhxREOs4rnH2a9X2iJMko7nodHSGLC6d8w==", "requires": { - "apollo-link": "^1.2.3" + "apollo-link": "1.2.3" } }, "apollo-link-state": { @@ -121,8 +121,8 @@ "resolved": "https://registry.npmjs.org/apollo-link-state/-/apollo-link-state-0.4.2.tgz", "integrity": "sha512-xMPcAfuiPVYXaLwC6oJFIZrKgV3GmdO31Ag2eufRoXpvT0AfJZjdaPB4450Nu9TslHRePN9A3quxNueILlQxlw==", "requires": { - "apollo-utilities": "^1.0.8", - "graphql-anywhere": "^4.1.0-alpha.0" + "apollo-utilities": "1.0.21", + "graphql-anywhere": "4.1.19" } }, "apollo-utilities": { @@ -130,8 +130,8 @@ "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.0.21.tgz", "integrity": "sha512-ZcxELlEl+sDCYBgEMdNXJAsZtRVm8wk4HIA58bMsqYfd1DSAJQEtZ93F0GZgYNAGy3QyaoBeZtbb0/01++G8JQ==", "requires": { - "fast-json-stable-stringify": "^2.0.0", - "fclone": "^1.0.11" + "fast-json-stable-stringify": "2.0.0", + "fclone": "1.0.11" } }, "asn1": { @@ -139,7 +139,7 @@ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "requires": { - "safer-buffer": "~2.1.0" + "safer-buffer": "2.1.2" } }, "assert": { @@ -160,7 +160,7 @@ "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", "requires": { - "lodash": "^4.17.10" + "lodash": "4.17.11" } }, "asynckit": { @@ -183,8 +183,8 @@ "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", "requires": { - "follow-redirects": "^1.3.0", - "is-buffer": "^1.1.5" + "follow-redirects": "1.6.1", + "is-buffer": "1.1.6" } }, "azure-storage": { @@ -192,17 +192,17 @@ "resolved": "https://registry.npmjs.org/azure-storage/-/azure-storage-2.10.2.tgz", "integrity": "sha512-pOyGPya9+NDpAfm5YcFfklo57HfjDbYLXxs4lomPwvRxmb0Di/A+a+RkUmEFzaQ8S13CqxK40bRRB0sjj2ZQxA==", "requires": { - "browserify-mime": "~1.2.9", - "extend": "^3.0.2", + "browserify-mime": "1.2.9", + "extend": "3.0.2", "json-edm-parser": "0.1.2", "md5.js": "1.3.4", - "readable-stream": "~2.0.0", - "request": "^2.86.0", - "underscore": "~1.8.3", - "uuid": "^3.0.0", - "validator": "~9.4.1", + "readable-stream": "2.0.6", + "request": "2.88.0", + "underscore": "1.8.3", + "uuid": "3.3.2", + "validator": "9.4.1", "xml2js": "0.2.8", - "xmlbuilder": "^9.0.7" + "xmlbuilder": "9.0.7" }, "dependencies": { "underscore": { @@ -218,7 +218,7 @@ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "optional": true, "requires": { - "tweetnacl": "^0.14.3" + "tweetnacl": "0.14.5" } }, "browserify-mime": { @@ -246,8 +246,8 @@ "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" + "color-convert": "1.9.3", + "color-string": "1.5.3" } }, "color-convert": { @@ -268,8 +268,8 @@ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "color-name": "1.1.3", + "simple-swizzle": "0.2.2" } }, "colornames": { @@ -287,8 +287,8 @@ "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.1.tgz", "integrity": "sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw==", "requires": { - "color": "3.0.x", - "text-hex": "1.0.x" + "color": "3.0.0", + "text-hex": "1.0.0" } }, "combined-stream": { @@ -296,7 +296,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", "requires": { - "delayed-stream": "~1.0.0" + "delayed-stream": "1.0.0" } }, "core-util-is": { @@ -309,7 +309,7 @@ "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" } }, "debug": { @@ -330,9 +330,9 @@ "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", "requires": { - "colorspace": "1.1.x", - "enabled": "1.0.x", - "kuler": "1.0.x" + "colorspace": "1.1.1", + "enabled": "1.0.2", + "kuler": "1.0.1" } }, "dotenv": { @@ -346,8 +346,8 @@ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "optional": true, "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "jsbn": "0.1.1", + "safer-buffer": "2.1.2" } }, "ecdsa-sig-formatter": { @@ -355,7 +355,7 @@ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz", "integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=", "requires": { - "safe-buffer": "^5.0.1" + "safe-buffer": "5.1.2" } }, "enabled": { @@ -363,7 +363,7 @@ "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", "requires": { - "env-variable": "0.0.x" + "env-variable": "0.0.5" } }, "env-variable": { @@ -411,7 +411,7 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.1.tgz", "integrity": "sha512-t2JCjbzxQpWvbhts3l6SH1DKzSrx8a+SsaVf4h6bG4kOXUuPYS/kg2Lr4gQSb7eemaHqJkOThF1BGyjlUkO1GQ==", "requires": { - "debug": "=3.1.0" + "debug": "3.1.0" } }, "forever-agent": { @@ -424,9 +424,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "requires": { - "asynckit": "^0.4.0", + "asynckit": "0.4.0", "combined-stream": "1.0.6", - "mime-types": "^2.1.12" + "mime-types": "2.1.20" }, "dependencies": { "combined-stream": { @@ -434,7 +434,7 @@ "resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "requires": { - "delayed-stream": "~1.0.0" + "delayed-stream": "1.0.0" } } } @@ -444,7 +444,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" } }, "graphql": { @@ -452,7 +452,7 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.0.2.tgz", "integrity": "sha512-gUC4YYsaiSJT1h40krG3J+USGlwhzNTXSb4IOZljn9ag5Tj+RkoXrWp+Kh7WyE3t1NCfab5kzCuxBIvOMERMXw==", "requires": { - "iterall": "^1.2.2" + "iterall": "1.2.2" } }, "graphql-anywhere": { @@ -460,7 +460,7 @@ "resolved": "https://registry.npmjs.org/graphql-anywhere/-/graphql-anywhere-4.1.19.tgz", "integrity": "sha512-mQlvbECzYPBcgBC9JsdM4v+DSvNmcIP+8Vwr+ij3gktbaLSE0Iza30mztuz40Jlf7ooMs+0emBZucNjLzqz7tA==", "requires": { - "apollo-utilities": "^1.0.21" + "apollo-utilities": "1.0.21" } }, "graphql-tag": { @@ -478,8 +478,8 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", "requires": { - "ajv": "^5.3.0", - "har-schema": "^2.0.0" + "ajv": "5.5.2", + "har-schema": "2.0.0" } }, "hash-base": { @@ -487,8 +487,8 @@ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "2.0.1", + "safe-buffer": "5.1.2" } }, "http-signature": { @@ -496,9 +496,9 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.14.2" } }, "inherits": { @@ -552,7 +552,7 @@ "resolved": "https://registry.npmjs.org/json-edm-parser/-/json-edm-parser-0.1.2.tgz", "integrity": "sha1-HmCw/vG8CvZ7wNFG393lSGzWFbQ=", "requires": { - "jsonparse": "~1.2.0" + "jsonparse": "1.2.0" } }, "json-schema": { @@ -580,15 +580,15 @@ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.4.0.tgz", "integrity": "sha512-coyXjRTCy0pw5WYBpMvWOMN+Kjaik2MwTUIq9cna/W7NpO9E+iYbumZONAz3hcr+tXFJECoQVrtmIoC3Oz0gvg==", "requires": { - "jws": "^3.1.5", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1" + "jws": "3.2.1", + "lodash.includes": "4.3.0", + "lodash.isboolean": "3.0.3", + "lodash.isinteger": "4.0.4", + "lodash.isnumber": "3.0.3", + "lodash.isplainobject": "4.0.6", + "lodash.isstring": "4.0.1", + "lodash.once": "4.1.1", + "ms": "2.1.1" }, "dependencies": { "ms": { @@ -616,7 +616,7 @@ "requires": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.10", - "safe-buffer": "^5.0.1" + "safe-buffer": "5.1.2" } }, "jws": { @@ -624,8 +624,8 @@ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.1.tgz", "integrity": "sha512-bGA2omSrFUkd72dhh05bIAN832znP4wOU3lfuXtRBuGTbsmNmDXMQg28f0Vsxaxgk4myF5YkKQpz6qeRpMgX9g==", "requires": { - "jwa": "^1.2.0", - "safe-buffer": "^5.0.1" + "jwa": "1.2.0", + "safe-buffer": "5.1.2" } }, "kuler": { @@ -633,7 +633,7 @@ "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", "requires": { - "colornames": "^1.1.1" + "colornames": "1.1.1" } }, "lodash": { @@ -681,11 +681,11 @@ "resolved": "https://registry.npmjs.org/logform/-/logform-1.10.0.tgz", "integrity": "sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg==", "requires": { - "colors": "^1.2.1", - "fast-safe-stringify": "^2.0.4", - "fecha": "^2.3.3", - "ms": "^2.1.1", - "triple-beam": "^1.2.0" + "colors": "1.3.3", + "fast-safe-stringify": "2.0.6", + "fecha": "2.3.3", + "ms": "2.1.1", + "triple-beam": "1.3.0" }, "dependencies": { "ms": { @@ -700,8 +700,8 @@ "resolved": "http://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" + "hash-base": "3.0.4", + "inherits": "2.0.1" } }, "mime-db": { @@ -714,7 +714,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", "requires": { - "mime-db": "~1.36.0" + "mime-db": "1.36.0" } }, "ms": { @@ -777,12 +777,12 @@ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.1", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" } }, "request": { @@ -790,26 +790,26 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "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.0", - "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.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" + "aws-sign2": "0.7.0", + "aws4": "1.8.0", + "caseless": "0.12.0", + "combined-stream": "1.0.7", + "extend": "3.0.2", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.1.0", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.20", + "oauth-sign": "0.9.0", + "performance-now": "2.1.0", + "qs": "6.5.2", + "safe-buffer": "5.1.2", + "tough-cookie": "2.4.3", + "tunnel-agent": "0.6.0", + "uuid": "3.3.2" } }, "retry": { @@ -837,7 +837,7 @@ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", "requires": { - "is-arrayish": "^0.3.1" + "is-arrayish": "0.3.2" } }, "sshpk": { @@ -845,15 +845,15 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", "requires": { - "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" + "asn1": "0.2.4", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.2", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.2", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "safer-buffer": "2.1.2", + "tweetnacl": "0.14.5" } }, "stack-trace": { @@ -881,8 +881,8 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" + "psl": "1.1.29", + "punycode": "1.4.1" } }, "triple-beam": { @@ -895,7 +895,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "^5.0.1" + "safe-buffer": "5.1.2" } }, "tweetnacl": { @@ -937,9 +937,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.2.0" + "extsprintf": "1.3.0" } }, "winston": { @@ -947,15 +947,15 @@ "resolved": "https://registry.npmjs.org/winston/-/winston-3.1.0.tgz", "integrity": "sha512-FsQfEE+8YIEeuZEYhHDk5cILo1HOcWkGwvoidLrDgPog0r4bser1lEIOco2dN9zpDJ1M88hfDgZvxe5z4xNcwg==", "requires": { - "async": "^2.6.0", - "diagnostics": "^1.1.1", - "is-stream": "^1.1.0", - "logform": "^1.9.1", + "async": "2.6.1", + "diagnostics": "1.1.1", + "is-stream": "1.1.0", + "logform": "1.10.0", "one-time": "0.0.4", - "readable-stream": "^2.3.6", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.2.0" + "readable-stream": "2.3.6", + "stack-trace": "0.0.10", + "triple-beam": "1.3.0", + "winston-transport": "4.3.0" }, "dependencies": { "inherits": { @@ -973,13 +973,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -987,7 +987,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -997,8 +997,8 @@ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", "requires": { - "readable-stream": "^2.3.6", - "triple-beam": "^1.2.0" + "readable-stream": "2.3.6", + "triple-beam": "1.3.0" }, "dependencies": { "inherits": { @@ -1016,13 +1016,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -1030,7 +1030,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -1040,7 +1040,7 @@ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.2.8.tgz", "integrity": "sha1-m4FpCTFjH/CdGVdUn69U9PmAs8I=", "requires": { - "sax": "0.5.x" + "sax": "0.5.8" } }, "xmlbuilder": { @@ -1058,7 +1058,7 @@ "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.10.tgz", "integrity": "sha512-5vqMtRggU/2GhePC9OU4sYEWOdvmayp2k3gjPf4F0mXwB3CSbbNznfDUvDJx9O2ZTa1EIXdJhPchQveFKwNXPQ==", "requires": { - "zen-observable": "^0.8.0" + "zen-observable": "0.8.9" } } } diff --git a/this.config.json b/this.config.json index d4a37b864..9f33a2962 100644 --- a/this.config.json +++ b/this.config.json @@ -47,6 +47,13 @@ "bot": "AAOlivia", "process": "Multi-Period-Market", "repo": "AAOlivia-Indicator-Bot" + }, + { + "enabled": "true", + "devTeam": "AAMasters", + "bot": "AAChris", + "process": "Multi-Period-Market", + "repo": "AAOlivia-Indicator-Bot" } ], "stopGracefully": false, From db65c47b8d51a536906df61fd92f63401c8f9357 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 21 Feb 2019 14:32:54 +0100 Subject: [PATCH 37/76] Some helper code to load the bot code from the file system for local testing --- CloudRequire.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/CloudRequire.js b/CloudRequire.js index 1597614d5..7bc874962 100644 --- a/CloudRequire.js +++ b/CloudRequire.js @@ -38,7 +38,28 @@ let USER_BOT_MODULE = {}; USER_BOT_MODULE.newUserBot = eval(text); - callBackFunction(global.DEFAULT_OK_RESPONSE, USER_BOT_MODULE); + /* + This following code is to load the bot code from a file on the file system. + It is useful for when you are activelly changing the code and dont wont to upload it to the storage at every run + */ + + /* + let fs = require('fs'); + try { + let fileName = "C:/Users/Luis/source/repos/Bots/AAMasters/AAChris-Indicator-Bot/Multi-Period-Daily/User.Bot.js"; + fs.readFile(fileName, onFileRead); + + function onFileRead(err, file) { + let fileString = file.toString(); + USER_BOT_MODULE.newUserBot = eval(fileString); + callBackFunction(global.DEFAULT_OK_RESPONSE, USER_BOT_MODULE); + } + } + catch(err) { + console.log("ERROR LOADING FILE FROM FILE SYSTEM"); + } + */ + callBackFunction(global.DEFAULT_OK_RESPONSE, USER_BOT_MODULE); // Coment this when loading from file system. } catch (err) { logger.write(MODULE_NAME, "[ERROR] downloadBot -> onFileReceived -> err.message = " + err.message); From 866137040b62d1c713b086aa41059939ba5e4b44 Mon Sep 17 00:00:00 2001 From: Matias Date: Fri, 22 Feb 2019 18:07:03 -0300 Subject: [PATCH 38/76] Hardcoded bot version --- Root.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Root.js b/Root.js index e70a63ece..17ca233a9 100644 --- a/Root.js +++ b/Root.js @@ -813,6 +813,7 @@ } let clonName = botConfig.codeName + "-" + "Clon" + clonKey; + clonName += ".1.0"; if (global.CURRENT_EXECUTION_AT === "Cloud") { clonName += "-" + process.env.CLONE_ID; @@ -842,6 +843,8 @@ clonName += "-" + process.env.CLONE_ID; } + clonName += ".1.0"; + botConfig.filePathRoot = botConfig.devTeam + "/" + clonName + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion; pBotConfig.instance = clonName; From 17036c6cc8b38021a567ff6f59bcdae615d52118 Mon Sep 17 00:00:00 2001 From: Matias Date: Fri, 22 Feb 2019 18:12:52 -0300 Subject: [PATCH 39/76] Ignored files --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7ab8c3a90..d9ffcb1be 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ configs/Email.Config.json configs/User.Profile.json configs/Execution.Config.json configs/Secret.Keys.json -.env +*.env +*.vscode* \ No newline at end of file From a2db8302272fbce59a9f9868216f0b12cec4c458 Mon Sep 17 00:00:00 2001 From: Matias Date: Tue, 5 Mar 2019 18:23:07 -0300 Subject: [PATCH 40/76] Correcting bot type name --- Run.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Run.js b/Run.js index 1f79b005c..0b8d69e0a 100644 --- a/Run.js +++ b/Run.js @@ -80,7 +80,7 @@ function readExecutionConfiguration() { backtest: backtest, competition: competition } - } else if (process.env.TYPE === 'Indicator' || process.env.TYPE === 'Extractor') { + } else if (process.env.TYPE === 'Indicator' || process.env.TYPE === 'Extraction') { let allMonths = { run: "false", minYear: process.env.MIN_YEAR, @@ -136,8 +136,6 @@ function readExecutionConfiguration() { } function readStoragePermissions() { - let filePath; - try { console.log( "[INFO] Run -> readStoragePermissions -> Entering function. "); @@ -187,10 +185,8 @@ function readStoragePermissions() { startRoot(); } - } - catch (err) { + } catch (err) { console.log("[ERROR] Run -> readStoragePermissions -> err = " + err.message); - console.log("[HINT] Run -> readStoragePermissions -> You need to have a file at this path -> " + filePath); } } From fc59aa290cac449b51407c96f3996e6b0e77d034 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 11 Mar 2019 14:11:45 +0100 Subject: [PATCH 41/76] Failure to update Clones Module does not stop trading bot execution. --- TradingBotProcessMainLoop.js | 55 ++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/TradingBotProcessMainLoop.js b/TradingBotProcessMainLoop.js index 85ac5cab1..9d6e6cab5 100644 --- a/TradingBotProcessMainLoop.js +++ b/TradingBotProcessMainLoop.js @@ -904,28 +904,12 @@ } } - async function saveContext() { + function saveContext() { try { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> saveContext -> Entering function."); } - if (global.CURRENT_EXECUTION_AT === "Cloud") { - // Update operations module with latest context - let lastExecution = context.newHistoryRecord - let date = lastExecution.date / 1000 | 0 - let buyAvgRate = lastExecution.buyAvgRate - let sellAvgRate = lastExecution.sellAvgRate - let marketRate = lastExecution.marketRate - let combinedProfitsA = lastExecution.combinedProfitsA - let combinedProfitsB = lastExecution.combinedProfitsB - - await operationsIntegration.updateExecutionResults(date, buyAvgRate, sellAvgRate, - marketRate, combinedProfitsA, combinedProfitsB) - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> saveContext -> Execution Results updated."); } - } - context.saveThemAll(onFinished); function onFinished(err) { @@ -938,7 +922,7 @@ case global.DEFAULT_OK_RESPONSE.result: { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> saveContext -> onFinished -> Execution finished well."); } nextWaitTime = 'Normal'; - loopControl(nextWaitTime); + updateClonesModule(); return; } case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time. @@ -997,6 +981,41 @@ } } + async function updateClonesModule() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> updateClonesModule -> Entering function."); } + + if (global.CURRENT_EXECUTION_AT === "Cloud") { + + // Update clones module with latest context informations + + let lastExecution = context.newHistoryRecord + let date = lastExecution.date / 1000 | 0 + let buyAvgRate = lastExecution.buyAvgRate + let sellAvgRate = lastExecution.sellAvgRate + let marketRate = lastExecution.marketRate + let combinedProfitsA = lastExecution.combinedProfitsA + let combinedProfitsB = lastExecution.combinedProfitsB + + await operationsIntegration.updateExecutionResults(date, buyAvgRate, sellAvgRate, + marketRate, combinedProfitsA, combinedProfitsB) + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> updateClonesModule -> Clones Module Updated."); } + } + + nextWaitTime = 'Normal'; + loopControl(nextWaitTime); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] run -> loop -> updateClonesModule -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> updateClonesModule -> Execution will continue anyways. "); + nextWaitTime = 'Normal'; + loopControl(nextWaitTime); + } + } + function loopControl(nextWaitTime) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Entering function."); } From 1324881882135368f9ed65fbb79010e06e493a96 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 Mar 2019 08:51:30 +0100 Subject: [PATCH 42/76] Data Dependencies implemented on Indicator Loop --- DataDependencies.js | 7 +++ IndicatorBotProcessMainLoop.js | 81 +++++++++++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/DataDependencies.js b/DataDependencies.js index db08c5a77..0660226b9 100644 --- a/DataDependencies.js +++ b/DataDependencies.js @@ -23,6 +23,13 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } + if (pDataDependenciesConfig === undefined) { + + // We allow old indicators not to declare their data dependencies. + + callBackFunction(global.DEFAULT_OK_RESPONSE); + return; + } /* For each dependency declared at the bot config, we will initialize a DataSet as part of this initialization process. diff --git a/IndicatorBotProcessMainLoop.js b/IndicatorBotProcessMainLoop.js index 5ed0969df..88347779d 100644 --- a/IndicatorBotProcessMainLoop.js +++ b/IndicatorBotProcessMainLoop.js @@ -175,6 +175,8 @@ const UTILITIES = require(ROOT_DIR + 'CloudUtilities'); const STATUS_REPORT = require(ROOT_DIR + 'StatusReport'); const STATUS_DEPENDENCIES = require(ROOT_DIR + 'StatusDependencies'); + const DATA_DEPENDENCIES = require(ROOT_DIR + 'DataDependencies'); + const DATA_SET = require(ROOT_DIR + 'DataSet'); /* We define the datetime for the process that we are running now. This will be the official processing time for both the infraestructure and the bot. */ @@ -189,6 +191,7 @@ let userBot; let statusDependencies; + let dataDependencies; let nextWaitTime; @@ -213,7 +216,7 @@ switch (err.result) { case global.DEFAULT_OK_RESPONSE.result: { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeStatusDependencies -> onInizialized -> Execution finished well."); - initializeUserBot(); + initializeDataDependencies(); return; } case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time. @@ -269,6 +272,80 @@ } } + function initializeDataDependencies() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeDataDependencies -> Entering function."); } + + dataDependencies = DATA_DEPENDENCIES.newDataDependencies(bot, logger, DATA_SET, BLOB_STORAGE, UTILITIES); + + dataDependencies.initialize(processConfig.dataDependencies, onInizialized); + + function onInizialized(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeDataDependencies -> onInizialized -> Entering function."); } + + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeDataDependencies -> onInizialized -> Execution finished well."); } + initializeUserBot(); + return; + } + case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time. + logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Retry Later. Requesting Execution Retry."); + nextWaitTime = 'Retry'; + loopControl(nextWaitTime); + return; + } + case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. + logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Operation Failed. Aborting the process."); + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(err); + return; + } + default: { + logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Unhandled err.result received. -> err.message = " + err.message); + + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return; + } + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> err = " + err.message); + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(err); + } + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> err = " + err.message); + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(err); + } + } + function initializeUserBot() { try { @@ -277,7 +354,7 @@ usertBot = USER_BOT_MODULE.newUserBot(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE); - usertBot.initialize(statusDependencies, pMonth, pYear, onInizialized); + usertBot.initialize(statusDependencies, pMonth, pYear, onInizialized, dataDependencies); function onInizialized(err) { From 9c92069b5d07d753dbbcebdc2d6ae7a686950045 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 Mar 2019 09:50:23 +0100 Subject: [PATCH 43/76] Framework for Multi Period Market Processes added. INitializar Function ready --- Multi-Period-Market.js | 924 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 924 insertions(+) create mode 100644 Multi-Period-Market.js diff --git a/Multi-Period-Market.js b/Multi-Period-Market.js new file mode 100644 index 000000000..75e4236c7 --- /dev/null +++ b/Multi-Period-Market.js @@ -0,0 +1,924 @@ +exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, FILE_STORAGE) { + + const FULL_LOG = true; + const LOG_FILE_CONTENT = false; + + const MODULE_NAME = "User Bot"; + + const EXCHANGE_NAME = "Poloniex"; + + const LRC_FOLDER_NAME = "LRC-Points"; + const PERCENTAGE_BANDWIDTH_FOLDER_NAME = "Percentage-Bandwidth"; + const BOLLINGER_BANDS_FOLDER_NAME = "Bollinger-Bands"; + const BOLLINGER_CHANNELS_FOLDER_NAME = "Bollinger-Channels"; + const BOLLINGER_SUB_CHANNELS_FOLDER_NAME = "Bollinger-Sub-Channels"; + const CANDLES_FOLDER_NAME = "Candles"; + const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; + const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; + + const commons = COMMONS.newCommons(bot, logger, UTILITIES); + + thisObject = { + initialize: initialize, + start: start + }; + + let gaussStorage = BLOB_STORAGE.newBlobStorage(bot, logger); + let chrisStorage = BLOB_STORAGE.newBlobStorage(bot, logger); + let oliviaStorage = BLOB_STORAGE.newBlobStorage(bot, logger); + let jasonStorage = BLOB_STORAGE.newBlobStorage(bot, logger); + + let utilities = UTILITIES.newCloudUtilities(bot, logger); + + let statusDependencies; + let dataDependencies; + let storages = []; + + return thisObject; + + function initialize(pStatusDependencies, pDataDependencies, pMonth, pYear, callBackFunction) { + + try { + + logger.fileName = MODULE_NAME; + logger.initialize(); + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } + + statusDependencies = pStatusDependencies; + dataDependencies = pDataDependencies; + + for (let i = 0; i < dataDependencies.length; i++) { + + let key; + let storage; + + key = dataDependencies.devTeam + "-" + + dataDependencies.bot + "-" + + dataDependencies.product + "-" + + dataDependencies.dataSet + "-" + + dataDependencies.dataSetVersion + + storage = dataDependencies.dataSets.get(key); + + storages.push(storage); + + } + + callBackFunction(global.DEFAULT_OK_RESPONSE); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + + + function start(callBackFunction) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); } + + let market = global.MARKET; + + buildRecords(); + + function buildRecords() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> Entering function."); } + + try { + + let n; + + periodsLoop(); + + function periodsLoop() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> periodsLoop -> Entering function."); } + + /* + + We will iterate through all posible periods. + + */ + + n = 0 // loop Variable representing each possible period as defined at the periods array. + + loopBody(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> periodsLoop -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function loopBody() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> Entering function."); } + + const outputPeriod = global.marketFilesPeriods[n][0]; + const timePeriod = global.marketFilesPeriods[n][1]; + + let marketFile; + + + + + + + + let LRCMap = new Map(); + let percentageBandwidthMap = new Map(); + let bollingerBandsMap = new Map(); + let bollingerChannelsArray = []; + let bollingerSubChannelsArray = []; + + let candles = []; + let recordsArray = []; + let conditionsArray = []; + let simulationLogic = {}; + + nextLRC(); + + function nextLRC() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = "AAVikings" + "/" + "AAGauss" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + LRC_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + gaussStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildLRC(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildLRC() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildLRC -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < marketFile.length; i++) { + + let LRC = { + begin: marketFile[i][0], + end: marketFile[i][1], + _15: marketFile[i][2], + _30: marketFile[i][3], + _60: marketFile[i][4] + }; + + if (previous !== undefined) { + + if (previous._15 > LRC._15) { LRC.direction15 = 'down'; } + if (previous._15 < LRC._15) { LRC.direction15 = 'up'; } + if (previous._15 === LRC._15) { LRC.direction15 = 'side'; } + + if (previous._30 > LRC._30) { LRC.direction30 = 'down'; } + if (previous._30 < LRC._30) { LRC.direction30 = 'up'; } + if (previous._30 === LRC._30) { LRC.direction30 = 'side'; } + + if (previous._60 > LRC._60) { LRC.direction60 = 'down'; } + if (previous._60 < LRC._60) { LRC.direction60 = 'up'; } + if (previous._60 === LRC._60) { LRC.direction60 = 'side'; } + + } + + LRC.previous = previous; + + LRCMap.set(LRC.begin, LRC); + + previous = LRC; + } + + nextPercentageBandwidth(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildLRC -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function nextPercentageBandwidth() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + PERCENTAGE_BANDWIDTH_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildPercentageBandwidthMap(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildPercentageBandwidthMap() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildPercentageBandwidthMap -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < marketFile.length; i++) { + + let percentageBandwidth = { + begin: marketFile[i][0], + end: marketFile[i][1], + value: marketFile[i][2], + movingAverage: marketFile[i][3], + bandwidth: marketFile[i][4] + }; + + if (previous !== undefined) { + + if (previous.movingAverage > percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'down'; } + if (previous.movingAverage < percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'up'; } + if (previous.movingAverage === percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'side'; } + + } + + percentageBandwidth.previous = previous; + + percentageBandwidthMap.set(percentageBandwidth.begin, percentageBandwidth); + + previous = percentageBandwidth; + } + + nextBollingerBands(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildPercentageBandwidthMap -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function nextBollingerBands() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + BOLLINGER_BANDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildBollingerBandsMap(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildBollingerBandsMap() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerBandsMap -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < marketFile.length; i++) { + + let bollingerBand = { + begin: marketFile[i][0], + end: marketFile[i][1], + movingAverage: marketFile[i][2], + standardDeviation: marketFile[i][3], + deviation: marketFile[i][4] + }; + + if (previous !== undefined) { + + if (previous.movingAverage > bollingerBand.movingAverage) { bollingerBand.direction = 'down'; } + if (previous.movingAverage < bollingerBand.movingAverage) { bollingerBand.direction = 'up'; } + if (previous.movingAverage === bollingerBand.movingAverage) { bollingerBand.direction = 'side'; } + + } + + bollingerBand.previous = previous; + + bollingerBandsMap.set(bollingerBand.begin, bollingerBand); + + previous = bollingerBand; + } + + nextBollingerChannels(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerBandsMap -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function nextBollingerChannels() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = bot.devTeam + "/" + "AAPaula" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + BOLLINGER_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildBollingerChannelsArray(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildBollingerChannelsArray() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerChannelsArray -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < marketFile.length; i++) { + + let bollingerChannel = { + begin: marketFile[i][0], + end: marketFile[i][1], + direction: marketFile[i][2], + period: marketFile[i][3], + firstMovingAverage: marketFile[i][4], + lastMovingAverage: marketFile[i][5], + firstDeviation: marketFile[i][6], + lastDeviation: marketFile[i][7] + }; + + bollingerChannel.previous = previous; + + bollingerChannelsArray.push(bollingerChannel); + + previous = bollingerChannel; + } + + nextBollingerSubChannels(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerChannelsArray -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function nextBollingerSubChannels() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = bot.devTeam + "/" + "AAPaula" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + BOLLINGER_SUB_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildBollingerSubChannelsArray(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildBollingerSubChannelsArray() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerSubChannelsArray -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < marketFile.length; i++) { + + let bollingerSubChannel = { + begin: marketFile[i][0], + end: marketFile[i][1], + direction: marketFile[i][2], + slope: marketFile[i][3], + period: marketFile[i][4], + firstMovingAverage: marketFile[i][5], + lastMovingAverage: marketFile[i][6], + firstDeviation: marketFile[i][7], + lastDeviation: marketFile[i][8] + }; + + bollingerSubChannel.previous = previous; + + bollingerSubChannelsArray.push(bollingerSubChannel); + + previous = bollingerSubChannel; + } + + nextCandlesFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerSubChannelsArray -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function nextCandlesFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = bot.devTeam + "/" + "AAOlivia" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + oliviaStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildCandles(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildCandles() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildCandles -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < marketFile.length; i++) { + + let candle = { + open: undefined, + close: undefined, + min: 10000000000000, + max: 0, + begin: undefined, + end: undefined, + direction: undefined + }; + + candle.min = marketFile[i][0]; + candle.max = marketFile[i][1]; + + candle.open = marketFile[i][2]; + candle.close = marketFile[i][3]; + + candle.begin = marketFile[i][4]; + candle.end = marketFile[i][5]; + + if (candle.open > candle.close) { candle.direction = 'down'; } + if (candle.open < candle.close) { candle.direction = 'up'; } + if (candle.open === candle.close) { candle.direction = 'side'; } + + candle.previous = previous; + + candles.push(candle); + + previous = candle; + } + + commons.runSimulation( + candles, + bollingerBandsMap, + percentageBandwidthMap, + LRCMap, + bollingerChannelsArray, + bollingerSubChannelsArray, + recordsArray, + conditionsArray, + simulationLogic, + outputPeriod, + writeRecordsFile) + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildCandles -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeRecordsFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < recordsArray.length; i++) { + + let record = recordsArray[i]; + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.type + "," + + record.rate + "," + + record.amount + "," + + record.balanceA + "," + + record.balanceB + "," + + record.profit + "," + + record.lastProfit + "," + + record.stopLoss + "," + + record.roundtrips + "," + + record.hits + "," + + record.fails + "," + + record.hitRatio + "," + + record.ROI + "," + + record.periods + "," + + record.days + "," + + record.anualizedRateOfReturn + "," + + record.sellRate + "," + + record.lastProfitPercent + "," + + record.strategy + "," + + record.strategyPhase + "," + + record.buyOrder + "," + + record.stopLossPhase + "," + + record.buyOrderPhase + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + writeConditionsFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeConditionsFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < conditionsArray.length; i++) { + + let record = conditionsArray[i]; + + let conditions = ""; + let conditionsSeparator = ""; + + for (let j = 0; j < record.length - 1; j++) { + conditions = conditions + conditionsSeparator + record[j]; + if (conditionsSeparator === "") { conditionsSeparator = ","; } + } + + conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of condition values. + + fileContent = fileContent + separator + '[' + conditions + ']'; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + fileContent = "[" + JSON.stringify(simulationLogic) + "," + fileContent + "]"; + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + controlLoop(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function controlLoop() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> controlLoop -> Entering function."); } + + n++; + + if (n < global.marketFilesPeriods.length) { + + loopBody(); + + } else { + + writeStatusReport(callBackFunction); + + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> controlLoop -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeStatusReport(callBack) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> Entering function."); } + + try { + + let reportKey = "AAMasters" + "-" + "AAJason" + "-" + "Multi-Period-Market" + "-" + "dataSet.V1"; + let thisReport = statusDependencies.statusReports.get(reportKey); + + thisReport.file.lastExecution = bot.processDatetime; + thisReport.save(callBack); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } +}; From fa5f4cb2f5060d4cbcc372f25521e9c156d2f290 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 Mar 2019 10:30:31 +0100 Subject: [PATCH 44/76] Get Files Function --- Multi-Period-Market.js | 342 +++++++++-------------------------------- 1 file changed, 70 insertions(+), 272 deletions(-) diff --git a/Multi-Period-Market.js b/Multi-Period-Market.js index 75e4236c7..71dc66beb 100644 --- a/Multi-Period-Market.js +++ b/Multi-Period-Market.js @@ -33,6 +33,7 @@ let statusDependencies; let dataDependencies; let storages = []; + let marketFiles = []; return thisObject; @@ -52,12 +53,13 @@ let key; let storage; + let dependency = dataDependencies[i]; - key = dataDependencies.devTeam + "-" + - dataDependencies.bot + "-" + - dataDependencies.product + "-" + - dataDependencies.dataSet + "-" + - dataDependencies.dataSetVersion + key = dependency.devTeam + "-" + + dependency.bot + "-" + + dependency.product + "-" + + dependency.dataSet + "-" + + dependency.dataSetVersion storage = dataDependencies.dataSets.get(key); @@ -126,12 +128,73 @@ const outputPeriod = global.marketFilesPeriods[n][0]; const timePeriod = global.marketFilesPeriods[n][1]; - - let marketFile; + let fileCount = 0; + + for (let i = 0; i < dataDependencies.length; i++) { + + let dependency = dataDependencies[i]; + let storage = storages[i]; + + getFile(); + + function getFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> getFile -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = dependency.devTeam + "/" + dependency.bot + "." + dependency.botVersion.major + "." + dependency.botVersion.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + dependency.dataSetVersion; + let filePath = filePathRoot + "/Output/" + dependency.product + "/" + "Multi-Period-Market" + "/" + timePeriod; + + storage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> getFile -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> getFile -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> getFile -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + let marketFile = JSON.parse(text); + marketFiles.push(marketFile); + fileCount++; + + callTheBot(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> getFile -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> getFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + } + + function callTheBot() { + + if (fileCount === dataDependencies.length + 1) { + } + } @@ -148,51 +211,7 @@ nextLRC(); - function nextLRC() { - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = "AAVikings" + "/" + "AAGauss" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + LRC_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - gaussStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildLRC(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } function buildLRC() { @@ -244,51 +263,7 @@ } } - function nextPercentageBandwidth() { - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + PERCENTAGE_BANDWIDTH_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildPercentageBandwidthMap(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } function buildPercentageBandwidthMap() { @@ -332,51 +307,7 @@ } } - function nextBollingerBands() { - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + BOLLINGER_BANDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildBollingerBandsMap(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } function buildBollingerBandsMap() { @@ -420,51 +351,7 @@ } } - function nextBollingerChannels() { - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = bot.devTeam + "/" + "AAPaula" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + BOLLINGER_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildBollingerChannelsArray(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } function buildBollingerChannelsArray() { @@ -503,51 +390,7 @@ } } - function nextBollingerSubChannels() { - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = bot.devTeam + "/" + "AAPaula" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + BOLLINGER_SUB_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildBollingerSubChannelsArray(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } function buildBollingerSubChannelsArray() { @@ -587,51 +430,6 @@ } } - function nextCandlesFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = bot.devTeam + "/" + "AAOlivia" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - oliviaStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildCandles(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } function buildCandles() { From 2e476b39b61a423295eae76eabf53a931e20ced7 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 Mar 2019 10:57:38 +0100 Subject: [PATCH 45/76] Initialize Function done --- Multi-Period-Market.js | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/Multi-Period-Market.js b/Multi-Period-Market.js index 71dc66beb..bce2f7c45 100644 --- a/Multi-Period-Market.js +++ b/Multi-Period-Market.js @@ -1,4 +1,4 @@ -exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, FILE_STORAGE) { +exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, FILE_STORAGE, USER_BOT_MODULE, COMMONS_MODULE) { const FULL_LOG = true; const LOG_FILE_CONTENT = false; @@ -7,15 +7,6 @@ const EXCHANGE_NAME = "Poloniex"; - const LRC_FOLDER_NAME = "LRC-Points"; - const PERCENTAGE_BANDWIDTH_FOLDER_NAME = "Percentage-Bandwidth"; - const BOLLINGER_BANDS_FOLDER_NAME = "Bollinger-Bands"; - const BOLLINGER_CHANNELS_FOLDER_NAME = "Bollinger-Channels"; - const BOLLINGER_SUB_CHANNELS_FOLDER_NAME = "Bollinger-Sub-Channels"; - const CANDLES_FOLDER_NAME = "Candles"; - const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; - const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; - const commons = COMMONS.newCommons(bot, logger, UTILITIES); thisObject = { @@ -23,11 +14,6 @@ start: start }; - let gaussStorage = BLOB_STORAGE.newBlobStorage(bot, logger); - let chrisStorage = BLOB_STORAGE.newBlobStorage(bot, logger); - let oliviaStorage = BLOB_STORAGE.newBlobStorage(bot, logger); - let jasonStorage = BLOB_STORAGE.newBlobStorage(bot, logger); - let utilities = UTILITIES.newCloudUtilities(bot, logger); let statusDependencies; @@ -35,6 +21,8 @@ let storages = []; let marketFiles = []; + let usertBot; + return thisObject; function initialize(pStatusDependencies, pDataDependencies, pMonth, pYear, callBackFunction) { @@ -67,7 +55,8 @@ } - callBackFunction(global.DEFAULT_OK_RESPONSE); + usertBot = USER_BOT_MODULE.newUserBot(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE); + usertBot.initialize(dataDependencies, pMonth, pYear, callBackFunction); } catch (err) { logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message); From 07a766296c013b204698d62e05c76bef7a8375f2 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 Mar 2019 11:40:36 +0100 Subject: [PATCH 46/76] Update Multi-Period-Market.js --- Multi-Period-Market.js | 501 +++-------------------------------------- 1 file changed, 35 insertions(+), 466 deletions(-) diff --git a/Multi-Period-Market.js b/Multi-Period-Market.js index bce2f7c45..49b62d192 100644 --- a/Multi-Period-Market.js +++ b/Multi-Period-Market.js @@ -64,8 +64,6 @@ } } - - function start(callBackFunction) { try { @@ -74,11 +72,11 @@ let market = global.MARKET; - buildRecords(); + processTimePeriods(); - function buildRecords() { + function processTimePeriods() { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> Entering function."); } try { @@ -90,7 +88,7 @@ try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> periodsLoop -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoop -> Entering function."); } /* @@ -104,7 +102,7 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> periodsLoop -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoop -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -113,7 +111,7 @@ try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> loopBody -> Entering function."); } const outputPeriod = global.marketFilesPeriods[n][0]; const timePeriod = global.marketFilesPeriods[n][1]; @@ -131,7 +129,7 @@ try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> getFile -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> loopBody -> getFile -> Entering function."); } let fileName = market.assetA + '_' + market.assetB + ".json"; @@ -144,12 +142,12 @@ try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> getFile -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> getFile -> onFileReceived -> text = " + text); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> loopBody -> getFile -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> loopBody -> getFile -> onFileReceived -> text = " + text); } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> getFile -> onFileReceived -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> loopBody -> getFile -> onFileReceived -> err = " + err.message); callBackFunction(err); return; @@ -163,13 +161,13 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> getFile -> onFileReceived -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> loopBody -> getFile -> onFileReceived -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> getFile -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> loopBody -> getFile -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -178,476 +176,47 @@ function callTheBot() { - if (fileCount === dataDependencies.length + 1) { - - - - } - } - - - - let LRCMap = new Map(); - let percentageBandwidthMap = new Map(); - let bollingerBandsMap = new Map(); - let bollingerChannelsArray = []; - let bollingerSubChannelsArray = []; - - let candles = []; - let recordsArray = []; - let conditionsArray = []; - let simulationLogic = {}; - - nextLRC(); - - - - function buildLRC() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildLRC -> Entering function."); } - try { - let previous; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> loopBody -> callTheBot -> Entering function."); } - for (let i = 0; i < marketFile.length; i++) { + if (fileCount === dataDependencies.length + 1) { - let LRC = { - begin: marketFile[i][0], - end: marketFile[i][1], - _15: marketFile[i][2], - _30: marketFile[i][3], - _60: marketFile[i][4] - }; + const outputPeriod = global.marketFilesPeriods[n][0]; + const timePeriod = global.marketFilesPeriods[n][1]; - if (previous !== undefined) { + usertBot.initialize(marketFiles, outputPeriod, timePeriod, callBackFunction); - if (previous._15 > LRC._15) { LRC.direction15 = 'down'; } - if (previous._15 < LRC._15) { LRC.direction15 = 'up'; } - if (previous._15 === LRC._15) { LRC.direction15 = 'side'; } + function onBotFinished(err) { - if (previous._30 > LRC._30) { LRC.direction30 = 'down'; } - if (previous._30 < LRC._30) { LRC.direction30 = 'up'; } - if (previous._30 === LRC._30) { LRC.direction30 = 'side'; } + try { - if (previous._60 > LRC._60) { LRC.direction60 = 'down'; } - if (previous._60 < LRC._60) { LRC.direction60 = 'up'; } - if (previous._60 === LRC._60) { LRC.direction60 = 'side'; } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> loopBody -> callTheBot -> onBotFinished -> Entering function."); } - } + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - LRC.previous = previous; - - LRCMap.set(LRC.begin, LRC); - - previous = LRC; - } - - nextPercentageBandwidth(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildLRC -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - - - function buildPercentageBandwidthMap() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildPercentageBandwidthMap -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let percentageBandwidth = { - begin: marketFile[i][0], - end: marketFile[i][1], - value: marketFile[i][2], - movingAverage: marketFile[i][3], - bandwidth: marketFile[i][4] - }; - - if (previous !== undefined) { - - if (previous.movingAverage > percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'down'; } - if (previous.movingAverage < percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'up'; } - if (previous.movingAverage === percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'side'; } - - } - - percentageBandwidth.previous = previous; - - percentageBandwidthMap.set(percentageBandwidth.begin, percentageBandwidth); - - previous = percentageBandwidth; - } - - nextBollingerBands(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildPercentageBandwidthMap -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - - - function buildBollingerBandsMap() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerBandsMap -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let bollingerBand = { - begin: marketFile[i][0], - end: marketFile[i][1], - movingAverage: marketFile[i][2], - standardDeviation: marketFile[i][3], - deviation: marketFile[i][4] - }; - - if (previous !== undefined) { - - if (previous.movingAverage > bollingerBand.movingAverage) { bollingerBand.direction = 'down'; } - if (previous.movingAverage < bollingerBand.movingAverage) { bollingerBand.direction = 'up'; } - if (previous.movingAverage === bollingerBand.movingAverage) { bollingerBand.direction = 'side'; } - - } - - bollingerBand.previous = previous; - - bollingerBandsMap.set(bollingerBand.begin, bollingerBand); - - previous = bollingerBand; - } - - nextBollingerChannels(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerBandsMap -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - - - function buildBollingerChannelsArray() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerChannelsArray -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let bollingerChannel = { - begin: marketFile[i][0], - end: marketFile[i][1], - direction: marketFile[i][2], - period: marketFile[i][3], - firstMovingAverage: marketFile[i][4], - lastMovingAverage: marketFile[i][5], - firstDeviation: marketFile[i][6], - lastDeviation: marketFile[i][7] - }; - - bollingerChannel.previous = previous; - - bollingerChannelsArray.push(bollingerChannel); - - previous = bollingerChannel; - } - - nextBollingerSubChannels(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerChannelsArray -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - - - function buildBollingerSubChannelsArray() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerSubChannelsArray -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let bollingerSubChannel = { - begin: marketFile[i][0], - end: marketFile[i][1], - direction: marketFile[i][2], - slope: marketFile[i][3], - period: marketFile[i][4], - firstMovingAverage: marketFile[i][5], - lastMovingAverage: marketFile[i][6], - firstDeviation: marketFile[i][7], - lastDeviation: marketFile[i][8] - }; - - bollingerSubChannel.previous = previous; - - bollingerSubChannelsArray.push(bollingerSubChannel); - - previous = bollingerSubChannel; - } - - nextCandlesFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerSubChannelsArray -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - - function buildCandles() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildCandles -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let candle = { - open: undefined, - close: undefined, - min: 10000000000000, - max: 0, - begin: undefined, - end: undefined, - direction: undefined - }; - - candle.min = marketFile[i][0]; - candle.max = marketFile[i][1]; - - candle.open = marketFile[i][2]; - candle.close = marketFile[i][3]; - - candle.begin = marketFile[i][4]; - candle.end = marketFile[i][5]; - - if (candle.open > candle.close) { candle.direction = 'down'; } - if (candle.open < candle.close) { candle.direction = 'up'; } - if (candle.open === candle.close) { candle.direction = 'side'; } - - candle.previous = previous; - - candles.push(candle); - - previous = candle; - } - - commons.runSimulation( - candles, - bollingerBandsMap, - percentageBandwidthMap, - LRCMap, - bollingerChannelsArray, - bollingerSubChannelsArray, - recordsArray, - conditionsArray, - simulationLogic, - outputPeriod, - writeRecordsFile) - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildCandles -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeRecordsFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < recordsArray.length; i++) { - - let record = recordsArray[i]; - - fileContent = fileContent + separator + '[' + - record.begin + "," + - record.end + "," + - record.type + "," + - record.rate + "," + - record.amount + "," + - record.balanceA + "," + - record.balanceB + "," + - record.profit + "," + - record.lastProfit + "," + - record.stopLoss + "," + - record.roundtrips + "," + - record.hits + "," + - record.fails + "," + - record.hitRatio + "," + - record.ROI + "," + - record.periods + "," + - record.days + "," + - record.anualizedRateOfReturn + "," + - record.sellRate + "," + - record.lastProfitPercent + "," + - record.strategy + "," + - record.strategyPhase + "," + - record.buyOrder + "," + - record.stopLossPhase + "," + - record.buyOrderPhase + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; + callBackFunction(err); + return; + } + controlLoop(); } - - writeConditionsFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeConditionsFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < conditionsArray.length; i++) { - - let record = conditionsArray[i]; - - let conditions = ""; - let conditionsSeparator = ""; - - for (let j = 0; j < record.length - 1; j++) { - conditions = conditions + conditionsSeparator + record[j]; - if (conditionsSeparator === "") { conditionsSeparator = ","; } - } - - conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of condition values. - - fileContent = fileContent + separator + '[' + conditions + ']'; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - fileContent = "[" + JSON.stringify(simulationLogic) + "," + fileContent + "]"; - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> loopBody -> callTheBot -> onBotFinished -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); } - - controlLoop(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } + } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> err = " + err.message); + catch(err){ + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> loopBody -> callTheBot -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> loopBody -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -656,7 +225,7 @@ try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> controlLoop -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> controlLoop -> Entering function."); } n++; @@ -671,14 +240,14 @@ } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> controlLoop -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> controlLoop -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } From fdbfad1e6753799abc9446298e77fda883302e51 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 Mar 2019 12:38:13 +0100 Subject: [PATCH 47/76] Debugging, Data Confirg added at data Dependencies --- DataDependencies.js | 13 +- IndicatorBotProcessMainLoop.js | 246 +++++++++++++++++- ...i-Period-Market.js => MultiPeriodMarket.js | 6 +- Project.njsproj | 3 + 4 files changed, 258 insertions(+), 10 deletions(-) rename Multi-Period-Market.js => MultiPeriodMarket.js (97%) diff --git a/DataDependencies.js b/DataDependencies.js index 0660226b9..df98108cc 100644 --- a/DataDependencies.js +++ b/DataDependencies.js @@ -9,6 +9,7 @@ let ownerBot; // This is the bot owner of the Data Set. let thisObject = { + config: undefined, dataSets: new Map(), initialize: initialize, keys: [] @@ -23,7 +24,9 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } - if (pDataDependenciesConfig === undefined) { + thisObject.config = pDataDependenciesConfig; + + if (thisObject.config === undefined) { // We allow old indicators not to declare their data dependencies. @@ -38,11 +41,11 @@ let alreadyCalledBack = false; let addCount = 0; - for (let i = 0; i < pDataDependenciesConfig.length; i++) { + for (let i = 0; i < thisObject.config.length; i++) { let dataSetModule = DATA_SET.newDataSet(BOT, logger, BLOB_STORAGE, UTILITIES); - dataSetModule.initialize(pDataDependenciesConfig[i], onInitilized); + dataSetModule.initialize(thisObject.config[i], onInitilized); function onInitilized(err) { @@ -65,14 +68,14 @@ let key; - key = pDataDependenciesConfig[i].devTeam + "-" + pDataDependenciesConfig[i].bot + "-" + pDataDependenciesConfig[i].product + "-" + pDataDependenciesConfig[i].dataSet + "-" + pDataDependenciesConfig[i].dataSetVersion; + key = thisObject.config[i].devTeam + "-" + thisObject.config[i].bot + "-" + thisObject.config[i].product + "-" + thisObject.config[i].dataSet + "-" + thisObject.config[i].dataSetVersion; thisObject.keys.push(key); thisObject.dataSets.set(key, dataSetModule); if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> addDataSet -> DataSet added to Map. -> key = " + key); } - if (addCount === pDataDependenciesConfig.length) { + if (addCount === thisObject.config.length) { if (alreadyCalledBack === false) { callBackFunction(global.DEFAULT_OK_RESPONSE); return; diff --git a/IndicatorBotProcessMainLoop.js b/IndicatorBotProcessMainLoop.js index 88347779d..0b1b0013a 100644 --- a/IndicatorBotProcessMainLoop.js +++ b/IndicatorBotProcessMainLoop.js @@ -9,6 +9,7 @@ let COMMONS_MODULE; const BLOB_STORAGE = require(ROOT_DIR + 'BlobStorage'); + const MULTI_PERIOD_MARKET = require(ROOT_DIR + 'MultiPeriodMarket'); const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog'); let logger; // We need this here in order for the loopHealth function to work and be able to rescue the loop when it gets in trouble. @@ -190,6 +191,7 @@ /* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */ let userBot; + let multiPeriodMarket; let statusDependencies; let dataDependencies; @@ -291,7 +293,16 @@ switch (err.result) { case global.DEFAULT_OK_RESPONSE.result: { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeDataDependencies -> onInizialized -> Execution finished well."); } - initializeUserBot(); + + /* If the process is configured to run inside a framework, we continue there, otherwise we run the bot directly. */ + + switch (processConfig.framework) { + case 'Multi-Period-Market': { + intitializeMultiPeriodMarket(); + break; + } + default: { initializeUserBot();} + } return; } case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time. @@ -354,7 +365,7 @@ usertBot = USER_BOT_MODULE.newUserBot(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE); - usertBot.initialize(statusDependencies, pMonth, pYear, onInizialized, dataDependencies); + usertBot.initialize(statusDependencies, pMonth, pYear, onInizialized); function onInizialized(err) { @@ -577,6 +588,237 @@ } } + function intitializeMultiPeriodMarket() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeMultiPeriodMarket -> Entering function."); } + + multiPeriodMarket = MULTI_PERIOD_MARKET.newMultiPeriodMarket(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE); + + multiPeriodMarket.initialize(statusDependencies, dataDependencies, pMonth, pYear, onInizialized, dataDependencies); + + function onInizialized(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeMultiPeriodMarket -> onInizialized -> Entering function."); } + + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeMultiPeriodMarket -> onInizialized -> Execution finished well."); + startMultiPeriodMarket(); + return; + } + case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time. + logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeMultiPeriodMarket -> onInizialized -> Retry Later. Requesting Execution Retry."); + nextWaitTime = 'Retry'; + loopControl(nextWaitTime); + return; + } + case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. + logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeMultiPeriodMarket -> onInizialized -> Operation Failed. Aborting the process."); + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(err); + return; + } + case global.CUSTOM_OK_RESPONSE.result: { + + switch (err.message) { + case "Too far in the future.": { + logger.write(MODULE_NAME, "[WARN] run -> loop -> intitializeMultiPeriodMarket -> onInizialized > Too far in the future. This Loop will enter in coma."); + nextWaitTime = 'Coma'; + loopControl(nextWaitTime); + return; + } + case "Not needed now, but soon.": { + logger.write(MODULE_NAME, "[WARN] run -> loop -> intitializeMultiPeriodMarket -> onInizialized > Not needed now, but soon. This Loop will continue with Normal wait time."); + nextWaitTime = 'Normal'; + loopControl(nextWaitTime); + return; + } + default: { + logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeMultiPeriodMarket -> onInizialized > Unhandled custom response received. -> err.message = " + err.message); + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(err); + return; + } + } + } + default: { + logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeMultiPeriodMarket -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeMultiPeriodMarket -> onInizialized -> Unhandled err.result received. -> err.message = " + err.message); + + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return; + } + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeMultiPeriodMarket -> onInizialized -> err = " + err.message); + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(err); + } + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeMultiPeriodMarket -> err = " + err.message); + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(err); + } + } + + function startMultiPeriodMarket() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> startMultiPeriodMarket -> Entering function."); } + + multiPeriodMarket.start(onFinished); + + function onFinished(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> startMultiPeriodMarket -> onFinished -> Entering function."); } + + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + logger.write(MODULE_NAME, "[INFO] run -> loop -> startMultiPeriodMarket -> onFinished -> Execution finished well."); + nextWaitTime = 'Normal'; + loopControl(nextWaitTime); + return; + } + case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time. + logger.write(MODULE_NAME, "[ERROR] run -> loop -> startMultiPeriodMarket -> onFinished -> Retry Later. Requesting Execution Retry."); + nextWaitTime = 'Retry'; + loopControl(nextWaitTime); + return; + } + case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. + logger.write(MODULE_NAME, "[ERROR] run -> loop -> startMultiPeriodMarket -> onFinished -> Operation Failed. Aborting the process."); + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(err); + return; + } + case global.CUSTOM_OK_RESPONSE.result: { + + switch (err.message) { + case "Dependency does not exist.": { + logger.write(MODULE_NAME, "[WARN] run -> loop -> startMultiPeriodMarket -> onFinished -> Dependency does not exist. This Loop will go to sleep."); + nextWaitTime = 'Sleep'; + loopControl(nextWaitTime); + return; + } + case "Dependency not ready.": { + logger.write(MODULE_NAME, "[WARN] run -> loop -> startMultiPeriodMarket -> onFinished -> Dependency not ready. This Loop will go to sleep."); + nextWaitTime = 'Sleep'; + loopControl(nextWaitTime); + return; + } + case "Month before it is needed.": { + logger.write(MODULE_NAME, "[WARN] run -> loop -> startMultiPeriodMarket -> onFinished -> Month before it is needed. This Loop will be terminated."); + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(global.DEFAULT_OK_RESPONSE); + return; + } + case "Month fully processed.": { + logger.write(MODULE_NAME, "[WARN] run -> loop -> startMultiPeriodMarket -> onFinished -> Month fully processed. This Loop will be terminated."); + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(global.DEFAULT_OK_RESPONSE); + return; + } + case "End of the month reached.": { + logger.write(MODULE_NAME, "[WARN] run -> loop -> startMultiPeriodMarket -> onFinished -> End of the month reached. This Loop will be terminated."); + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(global.DEFAULT_OK_RESPONSE); + return; + } + default: { + logger.write(MODULE_NAME, "[ERROR] run -> loop -> startMultiPeriodMarket -> onFinished -> Unhandled custom response received. -> err.message = " + err.message); + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(err); + return; + } + } + } + default: { + logger.write(MODULE_NAME, "[ERROR] run -> loop -> startMultiPeriodMarket -> onFinished -> Unhandled err.result received. -> err.result = " + err.result); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> startMultiPeriodMarket -> onFinished -> Unhandled err.result received. -> err.message = " + err.message); + + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return; + } + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] run -> loop -> startMultiPeriodMarket -> onFinished -> err = " + err.message); + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(err); + } + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] run -> loop -> startMultiPeriodMarket -> err = " + err.message); + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(err); + } + } + function loopControl(nextWaitTime) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Entering function."); } diff --git a/Multi-Period-Market.js b/MultiPeriodMarket.js similarity index 97% rename from Multi-Period-Market.js rename to MultiPeriodMarket.js index 49b62d192..719ea5683 100644 --- a/Multi-Period-Market.js +++ b/MultiPeriodMarket.js @@ -1,9 +1,9 @@ -exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, FILE_STORAGE, USER_BOT_MODULE, COMMONS_MODULE) { +exports.newMultiPeriodMarket = function newMultiPeriodMarket(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, FILE_STORAGE, USER_BOT_MODULE, COMMONS_MODULE) { const FULL_LOG = true; const LOG_FILE_CONTENT = false; - const MODULE_NAME = "User Bot"; + const MODULE_NAME = "Multi Period Market"; const EXCHANGE_NAME = "Poloniex"; @@ -37,7 +37,7 @@ statusDependencies = pStatusDependencies; dataDependencies = pDataDependencies; - for (let i = 0; i < dataDependencies.length; i++) { + for (let i = 0; i < dataDependencies.dataSets.Entries.length; i++) { let key; let storage; diff --git a/Project.njsproj b/Project.njsproj index 9edd19db5..3c981ef93 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -33,6 +33,9 @@ Code + + Code + Code From 03ea78988a79d2a3777d9f04469b8a6a28bdbbf5 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 Mar 2019 13:12:23 +0100 Subject: [PATCH 48/76] For transformed into a Loop --- DataSet.js | 1 - IndicatorBotProcessMainLoop.js | 2 +- MultiPeriodMarket.js | 168 +++++++++++++++++++-------------- 3 files changed, 100 insertions(+), 71 deletions(-) diff --git a/DataSet.js b/DataSet.js index 074135d0a..215137939 100644 --- a/DataSet.js +++ b/DataSet.js @@ -5,7 +5,6 @@ let bot = BOT; let thisObject = { - file: undefined, // Here we have the JSON object representing the file content. initialize: initialize, getTextFile: getTextFile, createTextFile: createTextFile diff --git a/IndicatorBotProcessMainLoop.js b/IndicatorBotProcessMainLoop.js index 0b1b0013a..0aa0046e0 100644 --- a/IndicatorBotProcessMainLoop.js +++ b/IndicatorBotProcessMainLoop.js @@ -594,7 +594,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeMultiPeriodMarket -> Entering function."); } - multiPeriodMarket = MULTI_PERIOD_MARKET.newMultiPeriodMarket(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE); + multiPeriodMarket = MULTI_PERIOD_MARKET.newMultiPeriodMarket(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE, USER_BOT_MODULE, COMMONS_MODULE); multiPeriodMarket.initialize(statusDependencies, dataDependencies, pMonth, pYear, onInizialized, dataDependencies); diff --git a/MultiPeriodMarket.js b/MultiPeriodMarket.js index 719ea5683..e3840bfb4 100644 --- a/MultiPeriodMarket.js +++ b/MultiPeriodMarket.js @@ -1,4 +1,4 @@ -exports.newMultiPeriodMarket = function newMultiPeriodMarket(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, FILE_STORAGE, USER_BOT_MODULE, COMMONS_MODULE) { +exports.newMultiPeriodMarket = function newMultiPeriodMarket(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, USER_BOT_MODULE, COMMONS_MODULE) { const FULL_LOG = true; const LOG_FILE_CONTENT = false; @@ -37,11 +37,11 @@ statusDependencies = pStatusDependencies; dataDependencies = pDataDependencies; - for (let i = 0; i < dataDependencies.dataSets.Entries.length; i++) { + for (let i = 0; i < dataDependencies.config.length; i++) { let key; let storage; - let dependency = dataDependencies[i]; + let dependency = dataDependencies.config[i]; key = dependency.devTeam + "-" + dependency.bot + "-" + @@ -98,7 +98,7 @@ n = 0 // loop Variable representing each possible period as defined at the periods array. - loopBody(); + periodsLoopBody(); } catch (err) { @@ -107,131 +107,161 @@ } } - function loopBody() { + function periodsLoopBody() { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> loopBody -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> Entering function."); } const outputPeriod = global.marketFilesPeriods[n][0]; const timePeriod = global.marketFilesPeriods[n][1]; - let fileCount = 0; + let dependencyIndex = 0; + dependencyLoopBody(); - for (let i = 0; i < dataDependencies.length; i++) { + function dependencyLoopBody() { - let dependency = dataDependencies[i]; - let storage = storages[i]; + try { - getFile(); + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> Entering function."); } - function getFile() { + let dependency = dataDependencies.config[dependencyIndex]; + let storage = storages[dependencyIndex]; - try { + getFile(); - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> loopBody -> getFile -> Entering function."); } + function getFile() { - let fileName = market.assetA + '_' + market.assetB + ".json"; + try { - let filePathRoot = dependency.devTeam + "/" + dependency.bot + "." + dependency.botVersion.major + "." + dependency.botVersion.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + dependency.dataSetVersion; - let filePath = filePathRoot + "/Output/" + dependency.product + "/" + "Multi-Period-Market" + "/" + timePeriod; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> Entering function."); } - storage.getTextFile(filePath, fileName, onFileReceived, true); + let fileName = market.assetA + '_' + market.assetB + ".json"; - function onFileReceived(err, text) { + let filePathRoot = dependency.devTeam + "/" + dependency.bot + "." + dependency.botVersion.major + "." + dependency.botVersion.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + dependency.dataSetVersion; + let filePath = filePathRoot + "/Output/" + dependency.product + "/" + "Multi-Period-Market" + "/" + timePeriod; - try { + storage.getTextFile(filePath, fileName, onFileReceived, true); - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> loopBody -> getFile -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> loopBody -> getFile -> onFileReceived -> text = " + text); } + function onFileReceived(err, text) { - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + try { - logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> loopBody -> getFile -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + let marketFile = JSON.parse(text); + marketFiles.push(marketFile); + fileCount++; + + callTheBot(); } - - let marketFile = JSON.parse(text); - marketFiles.push(marketFile); - fileCount++; - - callTheBot(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> loopBody -> getFile -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } } } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> loopBody -> getFile -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoop -> dependencyLoopBody -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } } + function dependencyControlLoop() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> dependencyControlLoop -> Entering function."); } + + dependencyIndex++; + + if (dependencyIndex < dataDependencies.config.length) { + + dependencyLoopBody(); + + } else { + + callTheBot(); + + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> dependencyControlLoop -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + function callTheBot() { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> loopBody -> callTheBot -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> Entering function."); } - if (fileCount === dataDependencies.length + 1) { + const outputPeriod = global.marketFilesPeriods[n][0]; + const timePeriod = global.marketFilesPeriods[n][1]; - const outputPeriod = global.marketFilesPeriods[n][0]; - const timePeriod = global.marketFilesPeriods[n][1]; + usertBot.initialize(marketFiles, outputPeriod, timePeriod, callBackFunction); - usertBot.initialize(marketFiles, outputPeriod, timePeriod, callBackFunction); + function onBotFinished(err) { - function onBotFinished(err) { + try { - try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> onBotFinished -> Entering function."); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> loopBody -> callTheBot -> onBotFinished -> Entering function."); } + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - callBackFunction(err); - return; - } - - controlLoop(); - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> loopBody -> callTheBot -> onBotFinished -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); + callBackFunction(err); + return; } + + periodsControlLoop(); + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> onBotFinished -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - } catch(err){ - logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> loopBody -> callTheBot -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> loopBody -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - function controlLoop() { + function periodsControlLoop() { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> controlLoop -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsControlLoop -> Entering function."); } n++; if (n < global.marketFilesPeriods.length) { - loopBody(); + periodsLoopBody(); } else { @@ -240,7 +270,7 @@ } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> controlLoop -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsControlLoop -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -258,7 +288,7 @@ try { - let reportKey = "AAMasters" + "-" + "AAJason" + "-" + "Multi-Period-Market" + "-" + "dataSet.V1"; + let reportKey = bot.devTeam + "-" + bot.codeName + "-" + "Multi-Period-Market" + "-" + "dataSet.V1"; let thisReport = statusDependencies.statusReports.get(reportKey); thisReport.file.lastExecution = bot.processDatetime; From d2a88e2b5435296085ccc2a9bbe393a66ca90bdb Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 Mar 2019 14:02:48 +0100 Subject: [PATCH 49/76] Multi Period Market Framework, ready! --- MultiPeriodMarket.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/MultiPeriodMarket.js b/MultiPeriodMarket.js index e3840bfb4..b360236be 100644 --- a/MultiPeriodMarket.js +++ b/MultiPeriodMarket.js @@ -138,8 +138,7 @@ let fileName = market.assetA + '_' + market.assetB + ".json"; - let filePathRoot = dependency.devTeam + "/" + dependency.bot + "." + dependency.botVersion.major + "." + dependency.botVersion.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + dependency.dataSetVersion; - let filePath = filePathRoot + "/Output/" + dependency.product + "/" + "Multi-Period-Market" + "/" + timePeriod; + let filePath = dependency.product + "/" + "Multi-Period-Market" + "/" + timePeriod; storage.getTextFile(filePath, fileName, onFileReceived, true); @@ -153,16 +152,16 @@ if (err.result !== global.DEFAULT_OK_RESPONSE.result) { logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> fileName = " + fileName); callBackFunction(err); return; - } let marketFile = JSON.parse(text); marketFiles.push(marketFile); - fileCount++; - callTheBot(); + dependencyControlLoop(); } catch (err) { @@ -217,7 +216,7 @@ const outputPeriod = global.marketFilesPeriods[n][0]; const timePeriod = global.marketFilesPeriods[n][1]; - usertBot.initialize(marketFiles, outputPeriod, timePeriod, callBackFunction); + usertBot.start(marketFiles, outputPeriod, timePeriod, callBackFunction); function onBotFinished(err) { From 07144f0385042fcb44c2cb63c150125d96c132a6 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 Mar 2019 15:36:59 +0100 Subject: [PATCH 50/76] dataFiles --- MultiPeriodMarket.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MultiPeriodMarket.js b/MultiPeriodMarket.js index b360236be..53d4a3776 100644 --- a/MultiPeriodMarket.js +++ b/MultiPeriodMarket.js @@ -19,7 +19,7 @@ let statusDependencies; let dataDependencies; let storages = []; - let marketFiles = []; + let dataFiles = []; let usertBot; @@ -159,7 +159,7 @@ } let marketFile = JSON.parse(text); - marketFiles.push(marketFile); + dataFiles.push(marketFile); dependencyControlLoop(); @@ -216,7 +216,7 @@ const outputPeriod = global.marketFilesPeriods[n][0]; const timePeriod = global.marketFilesPeriods[n][1]; - usertBot.start(marketFiles, outputPeriod, timePeriod, callBackFunction); + usertBot.start(dataFiles, outputPeriod, timePeriod, callBackFunction); function onBotFinished(err) { From 882bfe91393caa3520301429a39502d34344d13a Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 Mar 2019 16:01:42 +0100 Subject: [PATCH 51/76] Bug, array not being cleanned. --- MultiPeriodMarket.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/MultiPeriodMarket.js b/MultiPeriodMarket.js index 53d4a3776..a331941b8 100644 --- a/MultiPeriodMarket.js +++ b/MultiPeriodMarket.js @@ -117,6 +117,8 @@ const timePeriod = global.marketFilesPeriods[n][1]; let dependencyIndex = 0; + dataFiles = []; + dependencyLoopBody(); function dependencyLoopBody() { @@ -158,8 +160,8 @@ return; } - let marketFile = JSON.parse(text); - dataFiles.push(marketFile); + let dataFile = JSON.parse(text); + dataFiles.push(dataFile); dependencyControlLoop(); @@ -216,7 +218,7 @@ const outputPeriod = global.marketFilesPeriods[n][0]; const timePeriod = global.marketFilesPeriods[n][1]; - usertBot.start(dataFiles, outputPeriod, timePeriod, callBackFunction); + usertBot.start(dataFiles, outputPeriod, timePeriod, onBotFinished); function onBotFinished(err) { From a9d386a0607f9b53bddbe7d9175b36b5764d1a03 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 17 Mar 2019 08:35:30 +0100 Subject: [PATCH 52/76] Multi Period Daily implemented --- MultiPeriodDaily.js | 657 ++++++++++++++++++++++++++++++++++++++++++++ Project.njsproj | 3 + 2 files changed, 660 insertions(+) create mode 100644 MultiPeriodDaily.js diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js new file mode 100644 index 000000000..9f2ef1466 --- /dev/null +++ b/MultiPeriodDaily.js @@ -0,0 +1,657 @@ +exports.newMultiPeriodDaily = function newMultiPeriodDaily(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, USER_BOT_MODULE, COMMONS_MODULE) { + + const FULL_LOG = true; + const LOG_FILE_CONTENT = false; + + const MODULE_NAME = "Multi Period Daily"; + + const EXCHANGE_NAME = "Poloniex"; + + const commons = COMMONS.newCommons(bot, logger, UTILITIES); + + thisObject = { + initialize: initialize, + start: start + }; + + let utilities = UTILITIES.newCloudUtilities(bot, logger); + + let statusDependencies; + let dataDependencies; + let storages = []; + let dataFiles = []; + + let usertBot; + let currentBotStorage = BLOB_STORAGE.newBlobStorage(bot, logger); + + return thisObject; + + function initialize(pStatusDependencies, pDataDependencies, pMonth, pYear, callBackFunction) { + + try { + + logger.fileName = MODULE_NAME; + logger.initialize(); + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } + + statusDependencies = pStatusDependencies; + dataDependencies = pDataDependencies; + + for (let i = 0; i < dataDependencies.config.length; i++) { + + let key; + let storage; + let dependency = dataDependencies.config[i]; + + key = dependency.devTeam + "-" + + dependency.bot + "-" + + dependency.product + "-" + + dependency.dataSet + "-" + + dependency.dataSetVersion + + storage = dataDependencies.dataSets.get(key); + + storages.push(storage); + + } + + currentBotStorage.initialize(bot.devTeam, onStorageInizialized); + + function onStorageInizialized(err) { + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + usertBot = USER_BOT_MODULE.newUserBot(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE); + usertBot.initialize(dataDependencies, pMonth, pYear, callBackFunction); + + } else { + logger.write(MODULE_NAME, "[ERROR] initialize -> onStorageInizialized -> err = " + err.message); + callBackFunction(err); + } + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function start(callBackFunction) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); } + + let market = global.MARKET; + + /* Context Variables */ + + let contextVariables = { + lastFile: undefined, // Datetime of the last file files sucessfully produced by this process. + dateBeginingOfMarket: undefined, // Datetime of the first trade file in the whole market history. + dateEndOfMarket: undefined // Datetime of the last file available to be used as an input of this process. + }; + + let previousDay; // Holds the date of the previous day relative to the processing date. + let currentDate; // Holds the processing date. + + getContextVariables(); + + function getContextVariables() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Entering function."); } + + let thisReport; + let reportKey; + let statusReport; + + /* We look first for Charly in order to get when the market starts. */ + + reportKey = "AAMasters" + "-" + "AACharly" + "-" + "Poloniex-Historic-Trades" + "-" + "dataSet.V1"; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); } + + statusReport = statusDependencies.statusReports.get(reportKey); + + if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. "); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; + } + + if (statusReport.status === "Status Report is corrupt.") { + logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. "); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; + } + + thisReport = statusDependencies.statusReports.get(reportKey).file; + + if (thisReport.lastFile === undefined) { + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey); + logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> It is too early too run this process since the trade history of the market is not there yet."); + + let customOK = { + result: global.CUSTOM_OK_RESPONSE.result, + message: "Dependency does not exist." + } + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message); + callBackFunction(customOK); + return; + } + + contextVariables.dateBeginingOfMarket = new Date(thisReport.lastFile.year + "-" + thisReport.lastFile.month + "-" + thisReport.lastFile.days + " " + thisReport.lastFile.hours + ":" + thisReport.lastFile.minutes + GMT_SECONDS); + + /* Second, we get the report from Olivia, to know when the marted ends. */ + + reportKey = "AAMasters" + "-" + "AAOlivia" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1"; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); } + + statusReport = statusDependencies.statusReports.get(reportKey); + + if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. "); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; + } + + if (statusReport.status === "Status Report is corrupt.") { + logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. "); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; + } + + thisReport = statusDependencies.statusReports.get(reportKey).file; + + if (thisReport.lastFile === undefined) { + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey); + + let customOK = { + result: global.CUSTOM_OK_RESPONSE.result, + message: "Dependency not ready." + } + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message); + callBackFunction(customOK); + return; + } + + contextVariables.dateEndOfMarket = new Date(thisReport.lastFile.valueOf()); + + /* Finally we get our own Status Report. */ + + reportKey = bot.devTeam + "-" + bot.codeName + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1"; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); } + + statusReport = statusDependencies.statusReports.get(reportKey); + + if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. "); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; + } + + if (statusReport.status === "Status Report is corrupt.") { + logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process."); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return; + } + + thisReport = statusDependencies.statusReports.get(reportKey).file; + + if (thisReport.lastFile !== undefined) { + + contextVariables.lastFile = new Date(thisReport.lastFile); + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> thisReport.lastFile !== undefined"); } + + processTimePeriods(); + return; + + } else { + + /* + In the case when there is no status report, we take the date of the file with the first trades as the begining of the market. Then we will + go one day further in time, so that the previous day does fine a file at the begining of the market. + */ + + contextVariables.lastFile = new Date(contextVariables.dateBeginingOfMarket.getUTCFullYear() + "-" + (contextVariables.dateBeginingOfMarket.getUTCMonth() + 1) + "-" + contextVariables.dateBeginingOfMarket.getUTCDate() + " " + "00:00" + GMT_SECONDS); + contextVariables.lastFile = new Date(contextVariables.lastFile.valueOf() + ONE_DAY_IN_MILISECONDS); + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> thisReport.lastFile === undefined"); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> contextVariables.lastFile = " + contextVariables.lastFile); } + + processTimePeriods(); + return; + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> err = " + err.message); + if (err.message === "Cannot read property 'file' of undefined") { + logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. "); + logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys)); + } + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function processTimePeriods() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> Entering function."); } + + try { + + let n; + + advanceTime(); + + function advanceTime() { + + try { + + logger.newInternalLoop(bot.codeName, bot.process); + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> Entering function."); } + + currentDate = new Date(currentDate.valueOf() + ONE_DAY_IN_MILISECONDS); + previousDay = new Date(currentDate.valueOf() - ONE_DAY_IN_MILISECONDS); + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> currentDate = " + currentDate); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> previousDay = " + previousDay); } + + /* Validation that we are not going past the head of the market. */ + + if (currentDate.valueOf() > contextVariables.dateEndOfMarket.valueOf()) { + + const logText = "Head of the market found @ " + previousDay.getUTCFullYear() + "/" + (previousDay.getUTCMonth() + 1) + "/" + previousDay.getUTCDate() + "."; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> " + logText); } + + callBackFunction(global.DEFAULT_OK_RESPONSE); + return; + + } + + periodsLoop(); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> advanceTime -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function periodsLoop() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoop -> Entering function."); } + + /* + + We will iterate through all posible periods. + + */ + + n = 0 // loop Variable representing each possible period as defined at the periods array. + + periodsLoopBody(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoop -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function periodsLoopBody() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> Entering function."); } + + const outputPeriod = global.dailyFilesPeriods[n][0]; + const timePeriod = global.dailyFilesPeriods[n][1]; + + let dependencyIndex = 0; + dataFiles = []; + + dependencyLoopBody(); + + function dependencyLoopBody() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> Entering function."); } + + let dependency = dataDependencies.config[dependencyIndex]; + let storage = storages[dependencyIndex]; + + let previousFile; + let currentFile; + + getPreviousFile(); + + function getPreviousFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> Entering function."); } + + let dateForPath = previousDay.getUTCFullYear() + '/' + utilities.pad(previousDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(previousDay.getUTCDate(), 2); + let filePath = dependency.product + '/' + "Multi-Period-Daily" + "/" + timePeriod + "/" + dateForPath; + let fileName = market.assetA + '_' + market.assetB + ".json"; + + storage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> fileName = " + fileName); + callBackFunction(err); + return; + } + + previousFile = JSON.parse(text); + + getCurrentFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function getCurrentFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> Entering function."); } + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(previousDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(previousDay.getUTCDate(), 2); + let filePath = dependency.product + '/' + "Multi-Period-Daily" + "/" + timePeriod + "/" + dateForPath; + let fileName = market.assetA + '_' + market.assetB + ".json"; + + storage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> fileName = " + fileName); + callBackFunction(err); + return; + } + + currentFile = JSON.parse(text); + + let datafile = previousFile.concat(currentFile); + + dataFiles.push(dataFile); + dependencyControlLoop(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoop -> dependencyLoopBody -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function dependencyControlLoop() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> dependencyControlLoop -> Entering function."); } + + dependencyIndex++; + + if (dependencyIndex < dataDependencies.config.length) { + + dependencyLoopBody(); + + } else { + + callTheBot(); + + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> dependencyControlLoop -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function callTheBot() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> Entering function."); } + + const outputPeriod = global.dailyFilesPeriods[n][0]; + const timePeriod = global.dailyFilesPeriods[n][1]; + + usertBot.start(dataFiles, outputPeriod, timePeriod, onBotFinished); + + function onBotFinished(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> onBotFinished -> Entering function."); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + callBackFunction(err); + return; + } + + periodsControlLoop(); + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> onBotFinished -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function periodsControlLoop() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsControlLoop -> Entering function."); } + + n++; + + if (n < global.dailyFilesPeriods.length) { + + periodsLoopBody(); + + } else { + + n = 0; + + writeDataRanges(onWritten); + + function onWritten(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> controlLoop -> onWritten -> Entering function."); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> controlLoop -> onWritten -> err = " + err.message); + callBackFunction(err); + return; + } + + writeStatusReport(currentDate, advanceTime); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> controlLoop -> onWritten -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsControlLoop -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeDataRanges(callBack) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRanges -> Entering function."); } + + let productIndex = 0; + productLoopBody(); + + function productLoopBody() { + + let folderName = bot.products[productIndex].codeName; + + writeDataRange(contextVariables.dateBeginingOfMarket, currentDate, folderName, controlLoop); + } + + function controlLoop() { + + productIndex++; + + if (productIndex < bot.products.length) { + productLoopBody(); + } else { + callBack(global.DEFAULT_OK_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDataRanges -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + + } + + function writeDataRange(pBegin, pEnd, pProductFolder, callBack) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> Entering function."); } + + let dataRange = { + begin: pBegin.valueOf(), + end: pEnd.valueOf() + }; + + let fileContent = JSON.stringify(dataRange); + + let fileName = 'Data.Range.' + market.assetA + '_' + market.assetB + '.json'; + let filePath = bot.filePathRoot + "/Output/" + pProductFolder + "/" + bot.process; + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> fileName = " + fileName); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> filePath = " + filePath); } + + currentBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Entering function."); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> onFileCreated -> err = " + err.message); + callBack(err); + return; + } + + if (LOG_FILE_CONTENT === true) { + logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Content written = " + fileContent); + } + + callBack(global.DEFAULT_OK_RESPONSE); + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeStatusReport(lastFileDate, callBack) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> lastFileDate = " + lastFileDate); } + + try { + + let reportKey = bot.devTeam + "-" + bot.codeName + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1"; + let thisReport = statusDependencies.statusReports.get(reportKey); + + thisReport.file.lastExecution = bot.currentDatetime; + thisReport.file.lastFile = lastFileDate; + thisReport.save(callBack); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } +}; diff --git a/Project.njsproj b/Project.njsproj index 3c981ef93..c9cb27126 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -33,6 +33,9 @@ Code + + Code + Code From a3ddec4831d3572e91f3a0c3e9b72faa7328be91 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 17 Mar 2019 08:47:59 +0100 Subject: [PATCH 53/76] processFramework Implemented --- IndicatorBotProcessMainLoop.js | 77 ++++++++++++++++++---------------- MultiPeriodDaily.js | 4 +- MultiPeriodMarket.js | 4 +- 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/IndicatorBotProcessMainLoop.js b/IndicatorBotProcessMainLoop.js index 0aa0046e0..58f34ccce 100644 --- a/IndicatorBotProcessMainLoop.js +++ b/IndicatorBotProcessMainLoop.js @@ -10,6 +10,7 @@ const BLOB_STORAGE = require(ROOT_DIR + 'BlobStorage'); const MULTI_PERIOD_MARKET = require(ROOT_DIR + 'MultiPeriodMarket'); + const MULTI_PERIOD_DAILY = require(ROOT_DIR + 'MultiPeriodDaily'); const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog'); let logger; // We need this here in order for the loopHealth function to work and be able to rescue the loop when it gets in trouble. @@ -191,7 +192,7 @@ /* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */ let userBot; - let multiPeriodMarket; + let processFramework; let statusDependencies; let dataDependencies; @@ -298,7 +299,13 @@ switch (processConfig.framework) { case 'Multi-Period-Market': { - intitializeMultiPeriodMarket(); + processFramework = MULTI_PERIOD_MARKET.newMultiPeriodMarket(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE, USER_BOT_MODULE, COMMONS_MODULE); + intitializeProcessFramework(); + break; + } + case 'Multi-Period-Daily': { + processFramework = MULTI_PERIOD_DAILY.newMultiPeriodDaily(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE, USER_BOT_MODULE, COMMONS_MODULE); + intitializeProcessFramework(); break; } default: { initializeUserBot();} @@ -588,36 +595,34 @@ } } - function intitializeMultiPeriodMarket() { + function intitializeProcessFramework() { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeMultiPeriodMarket -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeProcessFramework -> Entering function."); } - multiPeriodMarket = MULTI_PERIOD_MARKET.newMultiPeriodMarket(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE, USER_BOT_MODULE, COMMONS_MODULE); - - multiPeriodMarket.initialize(statusDependencies, dataDependencies, pMonth, pYear, onInizialized, dataDependencies); + processFramework.initialize(statusDependencies, dataDependencies, onInizialized, dataDependencies); function onInizialized(err) { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeMultiPeriodMarket -> onInizialized -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeProcessFramework -> onInizialized -> Entering function."); } switch (err.result) { case global.DEFAULT_OK_RESPONSE.result: { - logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeMultiPeriodMarket -> onInizialized -> Execution finished well."); - startMultiPeriodMarket(); + logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeProcessFramework -> onInizialized -> Execution finished well."); + startProcessFramework(); return; } case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time. - logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeMultiPeriodMarket -> onInizialized -> Retry Later. Requesting Execution Retry."); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Retry Later. Requesting Execution Retry."); nextWaitTime = 'Retry'; loopControl(nextWaitTime); return; } case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. - logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeMultiPeriodMarket -> onInizialized -> Operation Failed. Aborting the process."); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Operation Failed. Aborting the process."); logger.persist(); clearInterval(fixedTimeLoopIntervalHandle); clearTimeout(nextLoopTimeoutHandle); @@ -630,19 +635,19 @@ switch (err.message) { case "Too far in the future.": { - logger.write(MODULE_NAME, "[WARN] run -> loop -> intitializeMultiPeriodMarket -> onInizialized > Too far in the future. This Loop will enter in coma."); + logger.write(MODULE_NAME, "[WARN] run -> loop -> intitializeProcessFramework -> onInizialized > Too far in the future. This Loop will enter in coma."); nextWaitTime = 'Coma'; loopControl(nextWaitTime); return; } case "Not needed now, but soon.": { - logger.write(MODULE_NAME, "[WARN] run -> loop -> intitializeMultiPeriodMarket -> onInizialized > Not needed now, but soon. This Loop will continue with Normal wait time."); + logger.write(MODULE_NAME, "[WARN] run -> loop -> intitializeProcessFramework -> onInizialized > Not needed now, but soon. This Loop will continue with Normal wait time."); nextWaitTime = 'Normal'; loopControl(nextWaitTime); return; } default: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeMultiPeriodMarket -> onInizialized > Unhandled custom response received. -> err.message = " + err.message); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized > Unhandled custom response received. -> err.message = " + err.message); logger.persist(); clearInterval(fixedTimeLoopIntervalHandle); clearTimeout(nextLoopTimeoutHandle); @@ -654,8 +659,8 @@ } } default: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeMultiPeriodMarket -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result); - logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeMultiPeriodMarket -> onInizialized -> Unhandled err.result received. -> err.message = " + err.message); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Unhandled err.result received. -> err.message = " + err.message); logger.persist(); clearInterval(fixedTimeLoopIntervalHandle); @@ -668,7 +673,7 @@ } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeMultiPeriodMarket -> onInizialized -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> err = " + err.message); logger.persist(); clearInterval(fixedTimeLoopIntervalHandle); clearTimeout(nextLoopTimeoutHandle); @@ -679,7 +684,7 @@ } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeMultiPeriodMarket -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> err = " + err.message); logger.persist(); clearInterval(fixedTimeLoopIntervalHandle); clearTimeout(nextLoopTimeoutHandle); @@ -689,35 +694,35 @@ } } - function startMultiPeriodMarket() { + function startProcessFramework() { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> startMultiPeriodMarket -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> startProcessFramework -> Entering function."); } - multiPeriodMarket.start(onFinished); + processFramework.start(onFinished); function onFinished(err) { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> startMultiPeriodMarket -> onFinished -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> startProcessFramework -> onFinished -> Entering function."); } switch (err.result) { case global.DEFAULT_OK_RESPONSE.result: { - logger.write(MODULE_NAME, "[INFO] run -> loop -> startMultiPeriodMarket -> onFinished -> Execution finished well."); + logger.write(MODULE_NAME, "[INFO] run -> loop -> startProcessFramework -> onFinished -> Execution finished well."); nextWaitTime = 'Normal'; loopControl(nextWaitTime); return; } case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time. - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startMultiPeriodMarket -> onFinished -> Retry Later. Requesting Execution Retry."); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Retry Later. Requesting Execution Retry."); nextWaitTime = 'Retry'; loopControl(nextWaitTime); return; } case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startMultiPeriodMarket -> onFinished -> Operation Failed. Aborting the process."); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Operation Failed. Aborting the process."); logger.persist(); clearInterval(fixedTimeLoopIntervalHandle); clearTimeout(nextLoopTimeoutHandle); @@ -730,19 +735,19 @@ switch (err.message) { case "Dependency does not exist.": { - logger.write(MODULE_NAME, "[WARN] run -> loop -> startMultiPeriodMarket -> onFinished -> Dependency does not exist. This Loop will go to sleep."); + logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> Dependency does not exist. This Loop will go to sleep."); nextWaitTime = 'Sleep'; loopControl(nextWaitTime); return; } case "Dependency not ready.": { - logger.write(MODULE_NAME, "[WARN] run -> loop -> startMultiPeriodMarket -> onFinished -> Dependency not ready. This Loop will go to sleep."); + logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> Dependency not ready. This Loop will go to sleep."); nextWaitTime = 'Sleep'; loopControl(nextWaitTime); return; } case "Month before it is needed.": { - logger.write(MODULE_NAME, "[WARN] run -> loop -> startMultiPeriodMarket -> onFinished -> Month before it is needed. This Loop will be terminated."); + logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> Month before it is needed. This Loop will be terminated."); logger.persist(); clearInterval(fixedTimeLoopIntervalHandle); clearTimeout(nextLoopTimeoutHandle); @@ -752,7 +757,7 @@ return; } case "Month fully processed.": { - logger.write(MODULE_NAME, "[WARN] run -> loop -> startMultiPeriodMarket -> onFinished -> Month fully processed. This Loop will be terminated."); + logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> Month fully processed. This Loop will be terminated."); logger.persist(); clearInterval(fixedTimeLoopIntervalHandle); clearTimeout(nextLoopTimeoutHandle); @@ -762,7 +767,7 @@ return; } case "End of the month reached.": { - logger.write(MODULE_NAME, "[WARN] run -> loop -> startMultiPeriodMarket -> onFinished -> End of the month reached. This Loop will be terminated."); + logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> End of the month reached. This Loop will be terminated."); logger.persist(); clearInterval(fixedTimeLoopIntervalHandle); clearTimeout(nextLoopTimeoutHandle); @@ -772,7 +777,7 @@ return; } default: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startMultiPeriodMarket -> onFinished -> Unhandled custom response received. -> err.message = " + err.message); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled custom response received. -> err.message = " + err.message); logger.persist(); clearInterval(fixedTimeLoopIntervalHandle); clearTimeout(nextLoopTimeoutHandle); @@ -784,8 +789,8 @@ } } default: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startMultiPeriodMarket -> onFinished -> Unhandled err.result received. -> err.result = " + err.result); - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startMultiPeriodMarket -> onFinished -> Unhandled err.result received. -> err.message = " + err.message); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled err.result received. -> err.result = " + err.result); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled err.result received. -> err.message = " + err.message); logger.persist(); clearInterval(fixedTimeLoopIntervalHandle); @@ -798,7 +803,7 @@ } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startMultiPeriodMarket -> onFinished -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> err = " + err.message); logger.persist(); clearInterval(fixedTimeLoopIntervalHandle); clearTimeout(nextLoopTimeoutHandle); @@ -809,7 +814,7 @@ } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startMultiPeriodMarket -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> err = " + err.message); logger.persist(); clearInterval(fixedTimeLoopIntervalHandle); clearTimeout(nextLoopTimeoutHandle); diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js index 9f2ef1466..194497a1c 100644 --- a/MultiPeriodDaily.js +++ b/MultiPeriodDaily.js @@ -26,7 +26,7 @@ return thisObject; - function initialize(pStatusDependencies, pDataDependencies, pMonth, pYear, callBackFunction) { + function initialize(pStatusDependencies, pDataDependencies, callBackFunction) { try { @@ -63,7 +63,7 @@ if (err.result === global.DEFAULT_OK_RESPONSE.result) { usertBot = USER_BOT_MODULE.newUserBot(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE); - usertBot.initialize(dataDependencies, pMonth, pYear, callBackFunction); + usertBot.initialize(dataDependencies, callBackFunction); } else { logger.write(MODULE_NAME, "[ERROR] initialize -> onStorageInizialized -> err = " + err.message); diff --git a/MultiPeriodMarket.js b/MultiPeriodMarket.js index a331941b8..485a087e0 100644 --- a/MultiPeriodMarket.js +++ b/MultiPeriodMarket.js @@ -25,7 +25,7 @@ return thisObject; - function initialize(pStatusDependencies, pDataDependencies, pMonth, pYear, callBackFunction) { + function initialize(pStatusDependencies, pDataDependencies, callBackFunction) { try { @@ -56,7 +56,7 @@ } usertBot = USER_BOT_MODULE.newUserBot(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE); - usertBot.initialize(dataDependencies, pMonth, pYear, callBackFunction); + usertBot.initialize(dataDependencies, callBackFunction); } catch (err) { logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message); From f08383d65b4df330c22458ed83c03add129bcace Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 17 Mar 2019 09:15:44 +0100 Subject: [PATCH 54/76] Sending current date to the bot --- MultiPeriodDaily.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js index 194497a1c..46e72f39b 100644 --- a/MultiPeriodDaily.js +++ b/MultiPeriodDaily.js @@ -463,7 +463,7 @@ const outputPeriod = global.dailyFilesPeriods[n][0]; const timePeriod = global.dailyFilesPeriods[n][1]; - usertBot.start(dataFiles, outputPeriod, timePeriod, onBotFinished); + usertBot.start(dataFiles, outputPeriod, timePeriod, currentDate, onBotFinished); function onBotFinished(err) { From 9197efc3ad9acbeded96b2c5eb758d8e668b6ce6 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 17 Mar 2019 09:28:53 +0100 Subject: [PATCH 55/76] Better naming --- MultiPeriodDaily.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js index 46e72f39b..01108f4df 100644 --- a/MultiPeriodDaily.js +++ b/MultiPeriodDaily.js @@ -89,8 +89,8 @@ let contextVariables = { lastFile: undefined, // Datetime of the last file files sucessfully produced by this process. - dateBeginingOfMarket: undefined, // Datetime of the first trade file in the whole market history. - dateEndOfMarket: undefined // Datetime of the last file available to be used as an input of this process. + dateBeginingOfMarket: undefined, // Datetime of the first trade file in the whole market history. + dateEndOfMarket: undefined // Datetime of the last file available to be used as an input of this process. }; let previousDay; // Holds the date of the previous day relative to the processing date. From b6d7b6b220ab70a153bbe449a3f563e21c27f39a Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 17 Mar 2019 09:45:58 +0100 Subject: [PATCH 56/76] Missing parts added --- MultiPeriodDaily.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js index 01108f4df..7fd39a18f 100644 --- a/MultiPeriodDaily.js +++ b/MultiPeriodDaily.js @@ -2,12 +2,11 @@ const FULL_LOG = true; const LOG_FILE_CONTENT = false; - const MODULE_NAME = "Multi Period Daily"; - const EXCHANGE_NAME = "Poloniex"; - const commons = COMMONS.newCommons(bot, logger, UTILITIES); + const GMT_SECONDS = ':00.000 GMT+0000'; + const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; thisObject = { initialize: initialize, @@ -243,6 +242,7 @@ try { let n; + currentDate = new Date(contextVariables.lastFile.valueOf() - ONE_DAY_IN_MILISECONDS); // Go back one day to start well when we advance time at the begining of the loop. advanceTime(); From bf8c8fbd2b04263b0752ee87b8aa46568111ef35 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 17 Mar 2019 10:23:59 +0100 Subject: [PATCH 57/76] Loading Dependencies and merging files --- MultiPeriodDaily.js | 56 ++++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js index 7fd39a18f..b3f46f47a 100644 --- a/MultiPeriodDaily.js +++ b/MultiPeriodDaily.js @@ -93,7 +93,7 @@ }; let previousDay; // Holds the date of the previous day relative to the processing date. - let currentDate; // Holds the processing date. + let currentDay; // Holds the processing date. getContextVariables(); @@ -142,8 +142,9 @@ } contextVariables.dateBeginingOfMarket = new Date(thisReport.lastFile.year + "-" + thisReport.lastFile.month + "-" + thisReport.lastFile.days + " " + thisReport.lastFile.hours + ":" + thisReport.lastFile.minutes + GMT_SECONDS); + contextVariables.dateBeginingOfMarket = new Date("2018-01-01"); // Remove this temporaty patch. - /* Second, we get the report from Olivia, to know when the marted ends. */ + /* Second, we get the report from Olivia, to know when the martet ends. */ reportKey = "AAMasters" + "-" + "AAOlivia" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1"; if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); } @@ -242,7 +243,9 @@ try { let n; - currentDate = new Date(contextVariables.lastFile.valueOf() - ONE_DAY_IN_MILISECONDS); // Go back one day to start well when we advance time at the begining of the loop. + let botNeverRan = true; + + currentDay = new Date(contextVariables.lastFile.valueOf() - ONE_DAY_IN_MILISECONDS); // Go back one day to start well when we advance time at the begining of the loop. advanceTime(); @@ -254,15 +257,15 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> Entering function."); } - currentDate = new Date(currentDate.valueOf() + ONE_DAY_IN_MILISECONDS); - previousDay = new Date(currentDate.valueOf() - ONE_DAY_IN_MILISECONDS); + currentDay = new Date(currentDay.valueOf() + ONE_DAY_IN_MILISECONDS); + previousDay = new Date(currentDay.valueOf() - ONE_DAY_IN_MILISECONDS); - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> currentDate = " + currentDate); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> currentDay = " + currentDay); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> previousDay = " + previousDay); } /* Validation that we are not going past the head of the market. */ - if (currentDate.valueOf() > contextVariables.dateEndOfMarket.valueOf()) { + if (currentDay.valueOf() > contextVariables.dateEndOfMarket.valueOf()) { const logText = "Head of the market found @ " + previousDay.getUTCFullYear() + "/" + (previousDay.getUTCMonth() + 1) + "/" + previousDay.getUTCDate() + "."; if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> " + logText); } @@ -309,9 +312,9 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> Entering function."); } - const outputPeriod = global.dailyFilesPeriods[n][0]; - const timePeriod = global.dailyFilesPeriods[n][1]; - + const outputPeriod = global.dailyFilePeriods[n][0]; + const timePeriod = global.dailyFilePeriods[n][1]; + let dependencyIndex = 0; dataFiles = []; @@ -350,6 +353,22 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> Entering function."); } if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> text = " + text); } + if (err.message === "File does not exist." && botNeverRan === true) { + + /* + Sometimes one of the dependencies of an indicator for some reasons are not calculated from the begining of the market. + When that happens we can not find those files. What we do in this situation is to move the time fordward until we can find + all the dependencies and the first run of the bot is successful. + + After that, we will not accept more missing files on any of the dependencies, and if any is missing we will abort the processing. + */ + logger.write(MODULE_NAME, "[WARN] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> Skipping day because file " + filePath + "/" + fileName + " was not found."); + + advanceTime(); + return; + } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> err = " + err.message); @@ -406,7 +425,7 @@ currentFile = JSON.parse(text); - let datafile = previousFile.concat(currentFile); + let dataFile = previousFile.concat(currentFile); dataFiles.push(dataFile); dependencyControlLoop(); @@ -460,10 +479,10 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> Entering function."); } - const outputPeriod = global.dailyFilesPeriods[n][0]; - const timePeriod = global.dailyFilesPeriods[n][1]; + const outputPeriod = global.dailyFilePeriods[n][0]; + const timePeriod = global.dailyFilePeriods[n][1]; - usertBot.start(dataFiles, outputPeriod, timePeriod, currentDate, onBotFinished); + usertBot.start(dataFiles, outputPeriod, timePeriod, currentDay, onBotFinished); function onBotFinished(err) { @@ -477,6 +496,7 @@ return; } + botNeverRan = false; periodsControlLoop(); } catch (err) { @@ -505,7 +525,7 @@ n++; - if (n < global.dailyFilesPeriods.length) { + if (n < global.dailyFilePeriods.length) { periodsLoopBody(); @@ -527,7 +547,7 @@ return; } - writeStatusReport(currentDate, advanceTime); + writeStatusReport(currentDay, advanceTime); } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> controlLoop -> onWritten -> err = " + err.message); @@ -562,7 +582,7 @@ let folderName = bot.products[productIndex].codeName; - writeDataRange(contextVariables.dateBeginingOfMarket, currentDate, folderName, controlLoop); + writeDataRange(contextVariables.dateBeginingOfMarket, currentDay, folderName, controlLoop); } function controlLoop() { @@ -637,7 +657,7 @@ let reportKey = bot.devTeam + "-" + bot.codeName + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1"; let thisReport = statusDependencies.statusReports.get(reportKey); - thisReport.file.lastExecution = bot.currentDatetime; + thisReport.file.lastExecution = bot.currentDaytime; thisReport.file.lastFile = lastFileDate; thisReport.save(callBack); From 664b688820d100825127133a9de15ec749400d0c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 17 Mar 2019 15:47:08 +0100 Subject: [PATCH 58/76] TimePeriod corrected --- IndicatorBotProcessMainLoop.js | 2 +- MultiPeriodDaily.js | 40 +++++++++++++++++++++------------- MultiPeriodMarket.js | 14 ++++++------ StatusDependencies.js | 3 +++ 4 files changed, 36 insertions(+), 23 deletions(-) diff --git a/IndicatorBotProcessMainLoop.js b/IndicatorBotProcessMainLoop.js index 58f34ccce..45e6cf024 100644 --- a/IndicatorBotProcessMainLoop.js +++ b/IndicatorBotProcessMainLoop.js @@ -601,7 +601,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeProcessFramework -> Entering function."); } - processFramework.initialize(statusDependencies, dataDependencies, onInizialized, dataDependencies); + processFramework.initialize(processConfig, statusDependencies, dataDependencies, onInizialized, dataDependencies); function onInizialized(err) { diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js index b3f46f47a..c9c8fe1cf 100644 --- a/MultiPeriodDaily.js +++ b/MultiPeriodDaily.js @@ -23,9 +23,11 @@ let usertBot; let currentBotStorage = BLOB_STORAGE.newBlobStorage(bot, logger); + let pProcessConfig; + return thisObject; - function initialize(pStatusDependencies, pDataDependencies, callBackFunction) { + function initialize(pProcessConfig, pStatusDependencies, pDataDependencies, callBackFunction) { try { @@ -36,6 +38,7 @@ statusDependencies = pStatusDependencies; dataDependencies = pDataDependencies; + processConfig = pProcessConfig; for (let i = 0; i < dataDependencies.config.length; i++) { @@ -107,9 +110,14 @@ let reportKey; let statusReport; - /* We look first for Charly in order to get when the market starts. */ + /* + We look first for the bot who knows the begining of the marke in order to get when the market starts. + */ - reportKey = "AAMasters" + "-" + "AACharly" + "-" + "Poloniex-Historic-Trades" + "-" + "dataSet.V1"; + let botWhoKnowsTheBeginingOfTheMarket = statusDependencies.config[processConfig.statusDependenciesIndexBegingOfMarket]; + let botWhoKnowsTheEndOfTheMarket = statusDependencies.config[processConfig.statusDependenciesIndexEndOfMarket]; + + reportKey = botWhoKnowsTheBeginingOfTheMarket.devTeam + "-" + botWhoKnowsTheBeginingOfTheMarket.bot + "-" + botWhoKnowsTheBeginingOfTheMarket.process + "-" + "dataSet.V1"; if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); } statusReport = statusDependencies.statusReports.get(reportKey); @@ -142,15 +150,17 @@ } contextVariables.dateBeginingOfMarket = new Date(thisReport.lastFile.year + "-" + thisReport.lastFile.month + "-" + thisReport.lastFile.days + " " + thisReport.lastFile.hours + ":" + thisReport.lastFile.minutes + GMT_SECONDS); - contextVariables.dateBeginingOfMarket = new Date("2018-01-01"); // Remove this temporaty patch. + //contextVariables.dateBeginingOfMarket = new Date("2018-01-01"); // TODO: Remove this temporaty patch. - /* Second, we get the report from Olivia, to know when the martet ends. */ + /* + Here we get the status report from the bot who knows which is the end of the market. + */ - reportKey = "AAMasters" + "-" + "AAOlivia" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1"; + reportKey = botWhoKnowsTheEndOfTheMarket.devTeam + "-" + botWhoKnowsTheEndOfTheMarket.bot + "-" + botWhoKnowsTheEndOfTheMarket.process + "-" + "dataSet.V1"; if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); } statusReport = statusDependencies.statusReports.get(reportKey); - + if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. "); callBackFunction(global.DEFAULT_RETRY_RESPONSE); @@ -312,8 +322,8 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> Entering function."); } - const outputPeriod = global.dailyFilePeriods[n][0]; - const timePeriod = global.dailyFilePeriods[n][1]; + const timePeriod = global.dailyFilePeriods[n][0]; + const outputPeriodLabel = global.dailyFilePeriods[n][1]; let dependencyIndex = 0; dataFiles = []; @@ -341,7 +351,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> Entering function."); } let dateForPath = previousDay.getUTCFullYear() + '/' + utilities.pad(previousDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(previousDay.getUTCDate(), 2); - let filePath = dependency.product + '/' + "Multi-Period-Daily" + "/" + timePeriod + "/" + dateForPath; + let filePath = dependency.product + '/' + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; let fileName = market.assetA + '_' + market.assetB + ".json"; storage.getTextFile(filePath, fileName, onFileReceived, true); @@ -401,8 +411,8 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> Entering function."); } - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(previousDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(previousDay.getUTCDate(), 2); - let filePath = dependency.product + '/' + "Multi-Period-Daily" + "/" + timePeriod + "/" + dateForPath; + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); + let filePath = dependency.product + '/' + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; let fileName = market.assetA + '_' + market.assetB + ".json"; storage.getTextFile(filePath, fileName, onFileReceived, true); @@ -479,10 +489,10 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> Entering function."); } - const outputPeriod = global.dailyFilePeriods[n][0]; - const timePeriod = global.dailyFilePeriods[n][1]; + const timePeriod = global.dailyFilePeriods[n][0]; + const outputPeriodLabel = global.dailyFilePeriods[n][1]; - usertBot.start(dataFiles, outputPeriod, timePeriod, currentDay, onBotFinished); + usertBot.start(dataFiles, timePeriod, outputPeriodLabel, currentDay, onBotFinished); function onBotFinished(err) { diff --git a/MultiPeriodMarket.js b/MultiPeriodMarket.js index 485a087e0..f0e3ffccb 100644 --- a/MultiPeriodMarket.js +++ b/MultiPeriodMarket.js @@ -25,7 +25,7 @@ return thisObject; - function initialize(pStatusDependencies, pDataDependencies, callBackFunction) { + function initialize(pProcessConfig, pStatusDependencies, pDataDependencies, callBackFunction) { try { @@ -113,8 +113,8 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> Entering function."); } - const outputPeriod = global.marketFilesPeriods[n][0]; - const timePeriod = global.marketFilesPeriods[n][1]; + const timePeriod = global.marketFilesPeriods[n][0]; + const outputPeriodLabel = global.marketFilesPeriods[n][1]; let dependencyIndex = 0; dataFiles = []; @@ -140,7 +140,7 @@ let fileName = market.assetA + '_' + market.assetB + ".json"; - let filePath = dependency.product + "/" + "Multi-Period-Market" + "/" + timePeriod; + let filePath = dependency.product + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; storage.getTextFile(filePath, fileName, onFileReceived, true); @@ -215,10 +215,10 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> Entering function."); } - const outputPeriod = global.marketFilesPeriods[n][0]; - const timePeriod = global.marketFilesPeriods[n][1]; + const timePeriod = global.marketFilesPeriods[n][0]; + const outputPeriodLabel = global.marketFilesPeriods[n][1]; - usertBot.start(dataFiles, outputPeriod, timePeriod, onBotFinished); + usertBot.start(dataFiles, timePeriod, outputPeriodLabel, onBotFinished); function onBotFinished(err) { diff --git a/StatusDependencies.js b/StatusDependencies.js index 635efdf37..2ce421ef8 100644 --- a/StatusDependencies.js +++ b/StatusDependencies.js @@ -6,6 +6,7 @@ const MODULE_NAME = "Status Dependencies"; let thisObject = { + config: undefined, statusReports: new Map(), initialize: initialize, keys: [] @@ -22,6 +23,8 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } + thisObject.config = pStatusDependenciesConfig; + /* For each dependency declared at the bot config, we will initialize the status report, and load it as part of this initialization process. From d0a7f15c07a112e15307ec3d0f44d04331c84939 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 18 Mar 2019 15:43:29 +0100 Subject: [PATCH 59/76] You can define start dates and end dates not dependant on dependencies --- IndicatorBotProcessMainLoop.js | 18 +++- MultiPeriodDaily.js | 161 ++++++++++++++++++--------------- MultiPeriodMarket.js | 28 +++++- 3 files changed, 133 insertions(+), 74 deletions(-) diff --git a/IndicatorBotProcessMainLoop.js b/IndicatorBotProcessMainLoop.js index 45e6cf024..514f6d635 100644 --- a/IndicatorBotProcessMainLoop.js +++ b/IndicatorBotProcessMainLoop.js @@ -296,8 +296,12 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeDataDependencies -> onInizialized -> Execution finished well."); } /* If the process is configured to run inside a framework, we continue there, otherwise we run the bot directly. */ + if (processConfig.framework === undefined) { + initializeUserBot(); + return; + } - switch (processConfig.framework) { + switch (processConfig.framework.name) { case 'Multi-Period-Market': { processFramework = MULTI_PERIOD_MARKET.newMultiPeriodMarket(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE, USER_BOT_MODULE, COMMONS_MODULE); intitializeProcessFramework(); @@ -308,7 +312,17 @@ intitializeProcessFramework(); break; } - default: { initializeUserBot();} + default: { + logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Process Framework not Supported."); + logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Process Framework Name = " + processConfig.framework.name); + logger.persist(); + clearInterval(fixedTimeLoopIntervalHandle); + clearTimeout(nextLoopTimeoutHandle); + clearTimeout(checkLoopHealthHandle); + bot.enableCheckLoopHealth = false; + callBackFunction(err); + return; + } } return; } diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js index c9c8fe1cf..0a8447ab6 100644 --- a/MultiPeriodDaily.js +++ b/MultiPeriodDaily.js @@ -23,7 +23,7 @@ let usertBot; let currentBotStorage = BLOB_STORAGE.newBlobStorage(bot, logger); - let pProcessConfig; + let processConfig; return thisObject; @@ -91,12 +91,12 @@ let contextVariables = { lastFile: undefined, // Datetime of the last file files sucessfully produced by this process. - dateBeginingOfMarket: undefined, // Datetime of the first trade file in the whole market history. + dateBeginOfMarket: undefined, // Datetime of the first trade file in the whole market history. dateEndOfMarket: undefined // Datetime of the last file available to be used as an input of this process. }; let previousDay; // Holds the date of the previous day relative to the processing date. - let currentDay; // Holds the processing date. + let currentDay; // Holds the processing date. getContextVariables(); @@ -110,84 +110,103 @@ let reportKey; let statusReport; - /* - We look first for the bot who knows the begining of the marke in order to get when the market starts. - */ + if (processConfig.framework.startDate.fixedDate !== undefined) { - let botWhoKnowsTheBeginingOfTheMarket = statusDependencies.config[processConfig.statusDependenciesIndexBegingOfMarket]; - let botWhoKnowsTheEndOfTheMarket = statusDependencies.config[processConfig.statusDependenciesIndexEndOfMarket]; + /* The starting date is fixed, we will start from there. */ - reportKey = botWhoKnowsTheBeginingOfTheMarket.devTeam + "-" + botWhoKnowsTheBeginingOfTheMarket.bot + "-" + botWhoKnowsTheBeginingOfTheMarket.process + "-" + "dataSet.V1"; - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); } + contextVariables.dateBeginOfMarket = new Date(processConfig.framework.startDate.fixedDate); - statusReport = statusDependencies.statusReports.get(reportKey); + } else { - if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. - logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. "); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); - return; - } + /* + We look first for the bot who knows the begining of the marke in order to get when the market starts. + */ - if (statusReport.status === "Status Report is corrupt.") { - logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. "); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); - return; - } + let botWhoKnowsTheBeginingOfTheMarket = statusDependencies.config[processConfig.framework.startDate.takeItFromStatusDependency]; - thisReport = statusDependencies.statusReports.get(reportKey).file; + reportKey = botWhoKnowsTheBeginingOfTheMarket.devTeam + "-" + botWhoKnowsTheBeginingOfTheMarket.bot + "-" + botWhoKnowsTheBeginingOfTheMarket.process + "-" + "dataSet.V1"; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); } - if (thisReport.lastFile === undefined) { - logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey); - logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> It is too early too run this process since the trade history of the market is not there yet."); + statusReport = statusDependencies.statusReports.get(reportKey); - let customOK = { - result: global.CUSTOM_OK_RESPONSE.result, - message: "Dependency does not exist." + if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. "); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; } - logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message); - callBackFunction(customOK); - return; - } - contextVariables.dateBeginingOfMarket = new Date(thisReport.lastFile.year + "-" + thisReport.lastFile.month + "-" + thisReport.lastFile.days + " " + thisReport.lastFile.hours + ":" + thisReport.lastFile.minutes + GMT_SECONDS); - //contextVariables.dateBeginingOfMarket = new Date("2018-01-01"); // TODO: Remove this temporaty patch. - - /* - Here we get the status report from the bot who knows which is the end of the market. - */ - - reportKey = botWhoKnowsTheEndOfTheMarket.devTeam + "-" + botWhoKnowsTheEndOfTheMarket.bot + "-" + botWhoKnowsTheEndOfTheMarket.process + "-" + "dataSet.V1"; - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); } - - statusReport = statusDependencies.statusReports.get(reportKey); - - if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. - logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. "); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); - return; - } - - if (statusReport.status === "Status Report is corrupt.") { - logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. "); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); - return; - } - - thisReport = statusDependencies.statusReports.get(reportKey).file; - - if (thisReport.lastFile === undefined) { - logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey); - - let customOK = { - result: global.CUSTOM_OK_RESPONSE.result, - message: "Dependency not ready." + if (statusReport.status === "Status Report is corrupt.") { + logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. "); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; } - logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message); - callBackFunction(customOK); - return; + + thisReport = statusDependencies.statusReports.get(reportKey).file; + + if (thisReport.lastFile === undefined) { + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey); + logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> It is too early too run this process since the trade history of the market is not there yet."); + + let customOK = { + result: global.CUSTOM_OK_RESPONSE.result, + message: "Dependency does not exist." + } + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message); + callBackFunction(customOK); + return; + } + + contextVariables.dateBeginOfMarket = new Date(thisReport.lastFile.year + "-" + thisReport.lastFile.month + "-" + thisReport.lastFile.days + " " + thisReport.lastFile.hours + ":" + thisReport.lastFile.minutes + GMT_SECONDS); + } - contextVariables.dateEndOfMarket = new Date(thisReport.lastFile.valueOf()); + if (processConfig.framework.endDate.fixedDate !== undefined) { + + /* The ending date is fixed, we will end there. */ + + contextVariables.dateEndOfMarket = new Date(processConfig.framework.endDate.fixedDate); + + } else { + + /* + Here we get the status report from the bot who knows which is the end of the market. + */ + + let botWhoKnowsTheEndOfTheMarket = statusDependencies.config[processConfig.framework.endDate.takeItFromStatusDependency]; + + reportKey = botWhoKnowsTheEndOfTheMarket.devTeam + "-" + botWhoKnowsTheEndOfTheMarket.bot + "-" + botWhoKnowsTheEndOfTheMarket.process + "-" + "dataSet.V1"; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); } + + statusReport = statusDependencies.statusReports.get(reportKey); + + if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. "); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; + } + + if (statusReport.status === "Status Report is corrupt.") { + logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. "); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; + } + + thisReport = statusDependencies.statusReports.get(reportKey).file; + + if (thisReport.lastFile === undefined) { + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey); + + let customOK = { + result: global.CUSTOM_OK_RESPONSE.result, + message: "Dependency not ready." + } + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message); + callBackFunction(customOK); + return; + } + + contextVariables.dateEndOfMarket = new Date(thisReport.lastFile.valueOf()); + } /* Finally we get our own Status Report. */ @@ -226,7 +245,7 @@ go one day further in time, so that the previous day does fine a file at the begining of the market. */ - contextVariables.lastFile = new Date(contextVariables.dateBeginingOfMarket.getUTCFullYear() + "-" + (contextVariables.dateBeginingOfMarket.getUTCMonth() + 1) + "-" + contextVariables.dateBeginingOfMarket.getUTCDate() + " " + "00:00" + GMT_SECONDS); + contextVariables.lastFile = new Date(contextVariables.dateBeginOfMarket.getUTCFullYear() + "-" + (contextVariables.dateBeginOfMarket.getUTCMonth() + 1) + "-" + contextVariables.dateBeginOfMarket.getUTCDate() + " " + "00:00" + GMT_SECONDS); contextVariables.lastFile = new Date(contextVariables.lastFile.valueOf() + ONE_DAY_IN_MILISECONDS); if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> thisReport.lastFile === undefined"); } @@ -492,7 +511,7 @@ const timePeriod = global.dailyFilePeriods[n][0]; const outputPeriodLabel = global.dailyFilePeriods[n][1]; - usertBot.start(dataFiles, timePeriod, outputPeriodLabel, currentDay, onBotFinished); + usertBot.start(dataFiles, timePeriod, outputPeriodLabel, currentDay, contextVariables.dateBeginOfMarket, contextVariables.dateEndOfMarket, onBotFinished); function onBotFinished(err) { @@ -592,7 +611,7 @@ let folderName = bot.products[productIndex].codeName; - writeDataRange(contextVariables.dateBeginingOfMarket, currentDay, folderName, controlLoop); + writeDataRange(contextVariables.dateBeginOfMarket, currentDay, folderName, controlLoop); } function controlLoop() { diff --git a/MultiPeriodMarket.js b/MultiPeriodMarket.js index f0e3ffccb..4cda411fa 100644 --- a/MultiPeriodMarket.js +++ b/MultiPeriodMarket.js @@ -23,6 +23,8 @@ let usertBot; + let processConfig; + return thisObject; function initialize(pProcessConfig, pStatusDependencies, pDataDependencies, callBackFunction) { @@ -36,6 +38,7 @@ statusDependencies = pStatusDependencies; dataDependencies = pDataDependencies; + processConfig = pProcessConfig; for (let i = 0; i < dataDependencies.config.length; i++) { @@ -72,6 +75,29 @@ let market = global.MARKET; + /* Context Variables */ + + let contextVariables = { + dateBeginOfMarket: undefined, // Datetime of the first trade file in the whole market history. + dateEndOfMarket: undefined // Datetime of the last file available to be used as an input of this process. + }; + + if (processConfig.framework.startDate.fixedDate !== undefined) { + + /* The starting date is fixed, we will start from there. */ + + contextVariables.dateBeginOfMarket = new Date(processConfig.framework.startDate.fixedDate); + + } + + if (processConfig.framework.endDate.fixedDate !== undefined) { + + /* The ending date is fixed, we will end there. */ + + contextVariables.dateEndOfMarket = new Date(processConfig.framework.endDate.fixedDate); + + } + processTimePeriods(); function processTimePeriods() { @@ -218,7 +244,7 @@ const timePeriod = global.marketFilesPeriods[n][0]; const outputPeriodLabel = global.marketFilesPeriods[n][1]; - usertBot.start(dataFiles, timePeriod, outputPeriodLabel, onBotFinished); + usertBot.start(dataFiles, timePeriod, outputPeriodLabel, contextVariables.dateBeginOfMarket, contextVariables.dateEndOfMarket, onBotFinished); function onBotFinished(err) { From aa6ea90bad9cd83a3b30f1acafbfb850555ac238 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 18 Mar 2019 21:41:27 +0100 Subject: [PATCH 60/76] Inter Process Memory Implemented --- MultiPeriodDaily.js | 28 ++++++++++++++++++++++++++-- MultiPeriodMarket.js | 8 +++++++- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js index 0a8447ab6..d40f4952c 100644 --- a/MultiPeriodDaily.js +++ b/MultiPeriodDaily.js @@ -98,6 +98,8 @@ let previousDay; // Holds the date of the previous day relative to the processing date. let currentDay; // Holds the processing date. + let interExecutionMemoryArray; + getContextVariables(); function getContextVariables() { @@ -233,7 +235,7 @@ contextVariables.lastFile = new Date(thisReport.lastFile); - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> thisReport.lastFile !== undefined"); } + interExecutionMemoryArray = thisReport.interExecutionMemoryArray; processTimePeriods(); return; @@ -251,6 +253,19 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> thisReport.lastFile === undefined"); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> contextVariables.lastFile = " + contextVariables.lastFile); } + /* + The first time the process is running is the right time to create the data structure that is going to be shared across different executions. + This data structure has one object per each timePeriod. + */ + + interExecutionMemoryArray = []; + + for (let i = 0; i < global.dailyFilePeriods.length; i++) + { + let emptyObject = {}; + interExecutionMemoryArray.push(emptyObject); + } + processTimePeriods(); return; } @@ -511,7 +526,15 @@ const timePeriod = global.dailyFilePeriods[n][0]; const outputPeriodLabel = global.dailyFilePeriods[n][1]; - usertBot.start(dataFiles, timePeriod, outputPeriodLabel, currentDay, contextVariables.dateBeginOfMarket, contextVariables.dateEndOfMarket, onBotFinished); + usertBot.start( + dataFiles, + timePeriod, + outputPeriodLabel, + currentDay, + contextVariables.dateBeginOfMarket, + contextVariables.dateEndOfMarket, + interExecutionMemoryArray[n], + onBotFinished); function onBotFinished(err) { @@ -688,6 +711,7 @@ thisReport.file.lastExecution = bot.currentDaytime; thisReport.file.lastFile = lastFileDate; + thisReport.file.interExecutionMemoryArray = interExecutionMemoryArray; thisReport.save(callBack); } diff --git a/MultiPeriodMarket.js b/MultiPeriodMarket.js index 4cda411fa..20ade8176 100644 --- a/MultiPeriodMarket.js +++ b/MultiPeriodMarket.js @@ -244,7 +244,13 @@ const timePeriod = global.marketFilesPeriods[n][0]; const outputPeriodLabel = global.marketFilesPeriods[n][1]; - usertBot.start(dataFiles, timePeriod, outputPeriodLabel, contextVariables.dateBeginOfMarket, contextVariables.dateEndOfMarket, onBotFinished); + usertBot.start( + dataFiles, + timePeriod, + outputPeriodLabel, + contextVariables.dateBeginOfMarket, + contextVariables.dateEndOfMarket, + onBotFinished); function onBotFinished(err) { From e200c42b7296ac7dce45f3d4e4ec9fafb040f6cb Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 19 Mar 2019 17:45:49 +0100 Subject: [PATCH 61/76] Bug fixed edcase when we start we dont have a previous file --- MultiPeriodDaily.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js index d40f4952c..47293e621 100644 --- a/MultiPeriodDaily.js +++ b/MultiPeriodDaily.js @@ -243,12 +243,11 @@ } else { /* - In the case when there is no status report, we take the date of the file with the first trades as the begining of the market. Then we will - go one day further in time, so that the previous day does fine a file at the begining of the market. + In the case when there is no status report, we assume like the last processed file is the one on the date of Begining of Market. */ contextVariables.lastFile = new Date(contextVariables.dateBeginOfMarket.getUTCFullYear() + "-" + (contextVariables.dateBeginOfMarket.getUTCMonth() + 1) + "-" + contextVariables.dateBeginOfMarket.getUTCDate() + " " + "00:00" + GMT_SECONDS); - contextVariables.lastFile = new Date(contextVariables.lastFile.valueOf() + ONE_DAY_IN_MILISECONDS); + //contextVariables.lastFile = new Date(contextVariables.lastFile.valueOf() + ONE_DAY_IN_MILISECONDS); if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> thisReport.lastFile === undefined"); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> contextVariables.lastFile = " + contextVariables.lastFile); } @@ -376,7 +375,12 @@ let previousFile; let currentFile; - getPreviousFile(); + if (currentDay.valueOf() > contextVariables.dateBeginOfMarket.valueOf()) { + getPreviousFile(); + } else { + previousFile = []; + getCurrentFile() + } function getPreviousFile() { From d63dd016e244cc38210f22dc263db7fa00b00b94 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 20 Mar 2019 12:45:46 +0100 Subject: [PATCH 62/76] Retry when it does not have a dependency --- MultiPeriodDaily.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js index 47293e621..508590812 100644 --- a/MultiPeriodDaily.js +++ b/MultiPeriodDaily.js @@ -416,6 +416,14 @@ return; } + if (err.result === "Fail Because" && err.message === "File does not exist.") { + + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> fileName = " + fileName); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; + } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { @@ -462,6 +470,15 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> Entering function."); } if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> text = " + text); } + if (err.result === "Fail Because" && err.message === "File does not exist.") { + + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> fileName = " + fileName); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; + } + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> err = " + err.message); From 1026c0837689e80734bc80d57fb80dea80c60add Mon Sep 17 00:00:00 2001 From: Matias Date: Fri, 22 Mar 2019 11:07:19 +0100 Subject: [PATCH 63/76] Adding Bots Execution Parameters --- Root.js | 23 +-- Run.js | 38 ++++- package-lock.json | 379 ++++++++++++++++++++++++++-------------------- package.json | 1 + 4 files changed, 264 insertions(+), 177 deletions(-) diff --git a/Root.js b/Root.js index 17ca233a9..cd1a399f4 100644 --- a/Root.js +++ b/Root.js @@ -212,7 +212,7 @@ /* The local configuration allows to select the configuration to run - locally, without overwriting the server config. + locally, without overwriting the server config. Here we check that the local configuration for the execution exist, if it doesn't exist we will take the one on the server. */ @@ -341,10 +341,13 @@ if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> listItem.process = " + listItem.process); } let processConfig = botConfig.processes[i]; - + switch (global.CURRENT_EXECUTION_AT) { case "Cloud": { processConfig.startMode = global.EXECUTION_CONFIG.startMode // Override file storage configuration + if(global.EXECUTION_CONFIG.timePeriod){ + processConfig.timePeriod = global.EXECUTION_CONFIG.timePeriod + } break; } case "Browser": { @@ -361,7 +364,7 @@ } } try { - + /* We test each type of start Mode to get what to run and how. */ if (processConfig.startMode.allMonths !== undefined) { @@ -500,7 +503,7 @@ if (processConfig.startMode.live !== undefined) { if (processConfig.startMode.live.run === "true") { - + botConfig.startMode = "Live"; console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode); @@ -762,9 +765,9 @@ } - /* + /* Now we have all the possible genes values in a multi-dimensional matrix. - We will go thorugh each of the elements of each dimension and get each combination possible with the other dimmensions. + We will go thorugh each of the elements of each dimension and get each combination possible with the other dimmensions. */ let combinations = []; @@ -827,7 +830,7 @@ setTimeout(execute, i * Math.random() * 10 * 1000); function execute() { - + createBotInstance(genes, combinations.length, botConfig); } @@ -842,7 +845,7 @@ if (global.CURRENT_EXECUTION_AT === "Cloud") { clonName += "-" + process.env.CLONE_ID; } - + clonName += ".1.0"; botConfig.filePathRoot = botConfig.devTeam + "/" + clonName + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion; @@ -899,7 +902,7 @@ logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot execution finished with errors. Please check the logs."); logger.persist(); - } + } } } else { @@ -922,7 +925,7 @@ console.log(logDisplace + "Root : [ERROR] start -> findProcess -> err.message = " + err.message); return; } - } + } } } } diff --git a/Run.js b/Run.js index 0b8d69e0a..52f7889a5 100644 --- a/Run.js +++ b/Run.js @@ -3,7 +3,7 @@ global.CURRENT_ENVIRONMENT = "Develop"; global.CURRENT_EXECUTION_AT = "Cloud"; global.SHALL_BOT_STOP = false; -global.AT_BREAKPOINT = false; // This is used only when running at the browser. +global.AT_BREAKPOINT = false; // This is used only when running at the browser. global.RUN_AS_TEAM = false; /* Default parameters can be changed by the execution configuration */ @@ -122,7 +122,8 @@ function readExecutionConfiguration() { global.EXECUTION_CONFIG = { executionList: executionList, - startMode: startMode + startMode: startMode, + timePeriod: getTimePeriod() }; readStoragePermissions(); @@ -135,6 +136,39 @@ function readExecutionConfiguration() { } } +function getTimePeriod(){ + if(process.env.EXECUTION_PARAMETERS !== undefined){ + try { + let executionParameters = JSON.parse(process.env.EXECUTION_PARAMETERS) + let timePeriodMap = new Map() + timePeriodMap.set("24-hs","86400000") + timePeriodMap.set("12-hs","43200000") + timePeriodMap.set("08-hs","28800000") + timePeriodMap.set("06-hs","21600000") + timePeriodMap.set("04-hs","14400000") + timePeriodMap.set("03-hs","10800000") + timePeriodMap.set("02-hs","7200000") + timePeriodMap.set("01-hs","3600000") + timePeriodMap.set("45-min","2700000") + timePeriodMap.set("40-min","2400000") + timePeriodMap.set("30-min","1800000") + timePeriodMap.set("20-min","1200000") + timePeriodMap.set("15-min","900000") + timePeriodMap.set("10-min","600000") + timePeriodMap.set("05-min","300000") + timePeriodMap.set("04-min","240000") + timePeriodMap.set("03-min","180000") + timePeriodMap.set("02-min","120000") + timePeriodMap.set("01-min","60000") + return timePeriodMap.get(executionParameters.timePeriod) + } catch (error) { + console.log( "[WARN] Run -> readExecutionConfiguration -> getTimePeriod -> Error: ", error); + } + } else { + return undefined + } +} + function readStoragePermissions() { try { console.log( "[INFO] Run -> readStoragePermissions -> Entering function. "); diff --git a/package-lock.json b/package-lock.json index 6bba6e4e6..1180a7ec5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,45 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@azure/ms-rest-js": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-1.2.3.tgz", + "integrity": "sha512-eROQ034b+9v0Hd3wETKi/EwF5pqS3VRAk1Lm8iKVPOP8v30f6Zfzsi420MRfBMsbNCx/mE2N0L65Px7tvcGfVg==", + "requires": { + "axios": "^0.18.0", + "form-data": "^2.3.2", + "tough-cookie": "^2.4.3", + "tslib": "^1.9.2", + "uuid": "^3.2.1", + "xml2js": "^0.4.19" + }, + "dependencies": { + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + } + } + }, + "@azure/storage-blob": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-10.3.0.tgz", + "integrity": "sha512-KZbJ3q8RpAdeIB5Em1lgXkiq7Mll9bSHHbHavOFMepkkF7HQa3Sez9FdkAVIkVVWK5YoBlshBGZ+mtiSQiS9Fw==", + "requires": { + "@azure/ms-rest-js": "1.2.3", + "events": "3.0.0", + "tslib": "^1.9.3" + } + }, "@types/async": { "version": "2.0.49", "resolved": "https://registry.npmjs.org/@types/async/-/async-2.0.49.tgz", @@ -20,10 +59,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "apollo-boost": { @@ -31,14 +70,14 @@ "resolved": "https://registry.npmjs.org/apollo-boost/-/apollo-boost-0.1.16.tgz", "integrity": "sha512-ppnQr90n2cn0ZMveEbqxW6NxmskIpThiLziLlRpRLy4keoAICg1NZecxJQmeaBLMtyhf5UholAjpS2SLmEJeHg==", "requires": { - "apollo-cache": "1.1.17", - "apollo-cache-inmemory": "1.2.10", - "apollo-client": "2.4.2", - "apollo-link": "1.2.3", - "apollo-link-error": "1.1.1", - "apollo-link-http": "1.5.5", - "apollo-link-state": "0.4.2", - "graphql-tag": "2.10.0" + "apollo-cache": "^1.1.17", + "apollo-cache-inmemory": "^1.2.10", + "apollo-client": "^2.4.2", + "apollo-link": "^1.0.6", + "apollo-link-error": "^1.0.3", + "apollo-link-http": "^1.3.1", + "apollo-link-state": "^0.4.0", + "graphql-tag": "^2.4.2" } }, "apollo-cache": { @@ -46,7 +85,7 @@ "resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.1.17.tgz", "integrity": "sha512-7sp24n2HZO4vXgTaKNomLyIfGxG4gDdDkBB0jkRzRi7HhnKmfwhiF/RCiKNbgLdrPX151INdls0KwIVliD0dHQ==", "requires": { - "apollo-utilities": "1.0.21" + "apollo-utilities": "^1.0.21" } }, "apollo-cache-inmemory": { @@ -54,9 +93,9 @@ "resolved": "https://registry.npmjs.org/apollo-cache-inmemory/-/apollo-cache-inmemory-1.2.10.tgz", "integrity": "sha512-eBusPFVtYIuo+PIfJdAwUCQ4cs7AJ4mB7sTdXxNQCXToYw8mzE6EfHnV37kdVfBXSaa82BzE2rb/YUq/duuamw==", "requires": { - "apollo-cache": "1.1.17", - "apollo-utilities": "1.0.21", - "graphql-anywhere": "4.1.19" + "apollo-cache": "^1.1.17", + "apollo-utilities": "^1.0.21", + "graphql-anywhere": "^4.1.19" } }, "apollo-client": { @@ -65,13 +104,13 @@ "integrity": "sha512-g1z23umaVSoKLj9xNl0aAnk2KBF4JeBi7MeKFc9CGTixH7TkqeQUQtxcjrC7j2h4KmDbuhOAHOFUGf8YshN+ag==", "requires": { "@types/async": "2.0.49", - "@types/zen-observable": "0.8.0", + "@types/zen-observable": "^0.8.0", "apollo-cache": "1.1.17", - "apollo-link": "1.2.3", - "apollo-link-dedup": "1.0.10", + "apollo-link": "^1.0.0", + "apollo-link-dedup": "^1.0.0", "apollo-utilities": "1.0.21", - "symbol-observable": "1.2.0", - "zen-observable": "0.8.9" + "symbol-observable": "^1.0.2", + "zen-observable": "^0.8.0" } }, "apollo-link": { @@ -79,8 +118,8 @@ "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.3.tgz", "integrity": "sha512-iL9yS2OfxYhigme5bpTbmRyC+Htt6tyo2fRMHT3K1XRL/C5IQDDz37OjpPy4ndx7WInSvfSZaaOTKFja9VWqSw==", "requires": { - "apollo-utilities": "1.0.21", - "zen-observable-ts": "0.8.10" + "apollo-utilities": "^1.0.0", + "zen-observable-ts": "^0.8.10" } }, "apollo-link-dedup": { @@ -88,7 +127,7 @@ "resolved": "https://registry.npmjs.org/apollo-link-dedup/-/apollo-link-dedup-1.0.10.tgz", "integrity": "sha512-tpUI9lMZsidxdNygSY1FxflXEkUZnvKRkMUsXXuQUNoSLeNtEvUX7QtKRAl4k9ubLl8JKKc9X3L3onAFeGTK8w==", "requires": { - "apollo-link": "1.2.3" + "apollo-link": "^1.2.3" } }, "apollo-link-error": { @@ -96,7 +135,7 @@ "resolved": "https://registry.npmjs.org/apollo-link-error/-/apollo-link-error-1.1.1.tgz", "integrity": "sha512-/yPcaQWcBdB94vpJ4FsiCJt1dAGGRm+6Tsj3wKwP+72taBH+UsGRQQZk7U/1cpZwl1yqhHZn+ZNhVOebpPcIlA==", "requires": { - "apollo-link": "1.2.3" + "apollo-link": "^1.2.3" } }, "apollo-link-http": { @@ -104,8 +143,8 @@ "resolved": "https://registry.npmjs.org/apollo-link-http/-/apollo-link-http-1.5.5.tgz", "integrity": "sha512-C5N6N/mRwmepvtzO27dgMEU3MMtRKSqcljBkYNZmWwH11BxkUQ5imBLPM3V4QJXNE7NFuAQAB5PeUd4ligivTQ==", "requires": { - "apollo-link": "1.2.3", - "apollo-link-http-common": "0.2.5" + "apollo-link": "^1.2.3", + "apollo-link-http-common": "^0.2.5" } }, "apollo-link-http-common": { @@ -113,7 +152,7 @@ "resolved": "https://registry.npmjs.org/apollo-link-http-common/-/apollo-link-http-common-0.2.5.tgz", "integrity": "sha512-6FV1wr5AqAyJ64Em1dq5hhGgiyxZE383VJQmhIoDVc3MyNcFL92TkhxREOs4rnH2a9X2iJMko7nodHSGLC6d8w==", "requires": { - "apollo-link": "1.2.3" + "apollo-link": "^1.2.3" } }, "apollo-link-state": { @@ -121,8 +160,8 @@ "resolved": "https://registry.npmjs.org/apollo-link-state/-/apollo-link-state-0.4.2.tgz", "integrity": "sha512-xMPcAfuiPVYXaLwC6oJFIZrKgV3GmdO31Ag2eufRoXpvT0AfJZjdaPB4450Nu9TslHRePN9A3quxNueILlQxlw==", "requires": { - "apollo-utilities": "1.0.21", - "graphql-anywhere": "4.1.19" + "apollo-utilities": "^1.0.8", + "graphql-anywhere": "^4.1.0-alpha.0" } }, "apollo-utilities": { @@ -130,8 +169,8 @@ "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.0.21.tgz", "integrity": "sha512-ZcxELlEl+sDCYBgEMdNXJAsZtRVm8wk4HIA58bMsqYfd1DSAJQEtZ93F0GZgYNAGy3QyaoBeZtbb0/01++G8JQ==", "requires": { - "fast-json-stable-stringify": "2.0.0", - "fclone": "1.0.11" + "fast-json-stable-stringify": "^2.0.0", + "fclone": "^1.0.11" } }, "asn1": { @@ -139,7 +178,7 @@ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": "~2.1.0" } }, "assert": { @@ -160,7 +199,7 @@ "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", "requires": { - "lodash": "4.17.11" + "lodash": "^4.17.10" } }, "asynckit": { @@ -183,8 +222,8 @@ "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", "requires": { - "follow-redirects": "1.6.1", - "is-buffer": "1.1.6" + "follow-redirects": "^1.3.0", + "is-buffer": "^1.1.5" } }, "azure-storage": { @@ -192,17 +231,17 @@ "resolved": "https://registry.npmjs.org/azure-storage/-/azure-storage-2.10.2.tgz", "integrity": "sha512-pOyGPya9+NDpAfm5YcFfklo57HfjDbYLXxs4lomPwvRxmb0Di/A+a+RkUmEFzaQ8S13CqxK40bRRB0sjj2ZQxA==", "requires": { - "browserify-mime": "1.2.9", - "extend": "3.0.2", + "browserify-mime": "~1.2.9", + "extend": "^3.0.2", "json-edm-parser": "0.1.2", "md5.js": "1.3.4", - "readable-stream": "2.0.6", - "request": "2.88.0", - "underscore": "1.8.3", - "uuid": "3.3.2", - "validator": "9.4.1", + "readable-stream": "~2.0.0", + "request": "^2.86.0", + "underscore": "~1.8.3", + "uuid": "^3.0.0", + "validator": "~9.4.1", "xml2js": "0.2.8", - "xmlbuilder": "9.0.7" + "xmlbuilder": "^9.0.7" }, "dependencies": { "underscore": { @@ -218,7 +257,7 @@ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "optional": true, "requires": { - "tweetnacl": "0.14.5" + "tweetnacl": "^0.14.3" } }, "browserify-mime": { @@ -246,8 +285,8 @@ "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", "requires": { - "color-convert": "1.9.3", - "color-string": "1.5.3" + "color-convert": "^1.9.1", + "color-string": "^1.5.2" } }, "color-convert": { @@ -268,8 +307,8 @@ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", "requires": { - "color-name": "1.1.3", - "simple-swizzle": "0.2.2" + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" } }, "colornames": { @@ -287,8 +326,8 @@ "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.1.tgz", "integrity": "sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw==", "requires": { - "color": "3.0.0", - "text-hex": "1.0.0" + "color": "3.0.x", + "text-hex": "1.0.x" } }, "combined-stream": { @@ -296,7 +335,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "core-util-is": { @@ -309,7 +348,7 @@ "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" } }, "debug": { @@ -330,9 +369,9 @@ "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", "requires": { - "colorspace": "1.1.1", - "enabled": "1.0.2", - "kuler": "1.0.1" + "colorspace": "1.1.x", + "enabled": "1.0.x", + "kuler": "1.0.x" } }, "dotenv": { @@ -346,8 +385,8 @@ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "optional": true, "requires": { - "jsbn": "0.1.1", - "safer-buffer": "2.1.2" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "ecdsa-sig-formatter": { @@ -355,7 +394,7 @@ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz", "integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.0.1" } }, "enabled": { @@ -363,7 +402,7 @@ "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", "requires": { - "env-variable": "0.0.5" + "env-variable": "0.0.x" } }, "env-variable": { @@ -371,6 +410,11 @@ "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==" }, + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==" + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -411,7 +455,7 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.1.tgz", "integrity": "sha512-t2JCjbzxQpWvbhts3l6SH1DKzSrx8a+SsaVf4h6bG4kOXUuPYS/kg2Lr4gQSb7eemaHqJkOThF1BGyjlUkO1GQ==", "requires": { - "debug": "3.1.0" + "debug": "=3.1.0" } }, "forever-agent": { @@ -424,9 +468,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "requires": { - "asynckit": "0.4.0", + "asynckit": "^0.4.0", "combined-stream": "1.0.6", - "mime-types": "2.1.20" + "mime-types": "^2.1.12" }, "dependencies": { "combined-stream": { @@ -434,7 +478,7 @@ "resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } } } @@ -444,7 +488,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" } }, "graphql": { @@ -452,7 +496,7 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.0.2.tgz", "integrity": "sha512-gUC4YYsaiSJT1h40krG3J+USGlwhzNTXSb4IOZljn9ag5Tj+RkoXrWp+Kh7WyE3t1NCfab5kzCuxBIvOMERMXw==", "requires": { - "iterall": "1.2.2" + "iterall": "^1.2.2" } }, "graphql-anywhere": { @@ -460,7 +504,7 @@ "resolved": "https://registry.npmjs.org/graphql-anywhere/-/graphql-anywhere-4.1.19.tgz", "integrity": "sha512-mQlvbECzYPBcgBC9JsdM4v+DSvNmcIP+8Vwr+ij3gktbaLSE0Iza30mztuz40Jlf7ooMs+0emBZucNjLzqz7tA==", "requires": { - "apollo-utilities": "1.0.21" + "apollo-utilities": "^1.0.21" } }, "graphql-tag": { @@ -478,8 +522,8 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", "requires": { - "ajv": "5.5.2", - "har-schema": "2.0.0" + "ajv": "^5.3.0", + "har-schema": "^2.0.0" } }, "hash-base": { @@ -487,8 +531,8 @@ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "requires": { - "inherits": "2.0.1", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "http-signature": { @@ -496,9 +540,9 @@ "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.14.2" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "inherits": { @@ -552,7 +596,7 @@ "resolved": "https://registry.npmjs.org/json-edm-parser/-/json-edm-parser-0.1.2.tgz", "integrity": "sha1-HmCw/vG8CvZ7wNFG393lSGzWFbQ=", "requires": { - "jsonparse": "1.2.0" + "jsonparse": "~1.2.0" } }, "json-schema": { @@ -580,15 +624,15 @@ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.4.0.tgz", "integrity": "sha512-coyXjRTCy0pw5WYBpMvWOMN+Kjaik2MwTUIq9cna/W7NpO9E+iYbumZONAz3hcr+tXFJECoQVrtmIoC3Oz0gvg==", "requires": { - "jws": "3.2.1", - "lodash.includes": "4.3.0", - "lodash.isboolean": "3.0.3", - "lodash.isinteger": "4.0.4", - "lodash.isnumber": "3.0.3", - "lodash.isplainobject": "4.0.6", - "lodash.isstring": "4.0.1", - "lodash.once": "4.1.1", - "ms": "2.1.1" + "jws": "^3.1.5", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1" }, "dependencies": { "ms": { @@ -616,7 +660,7 @@ "requires": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.10", - "safe-buffer": "5.1.2" + "safe-buffer": "^5.0.1" } }, "jws": { @@ -624,8 +668,8 @@ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.1.tgz", "integrity": "sha512-bGA2omSrFUkd72dhh05bIAN832znP4wOU3lfuXtRBuGTbsmNmDXMQg28f0Vsxaxgk4myF5YkKQpz6qeRpMgX9g==", "requires": { - "jwa": "1.2.0", - "safe-buffer": "5.1.2" + "jwa": "^1.2.0", + "safe-buffer": "^5.0.1" } }, "kuler": { @@ -633,7 +677,7 @@ "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", "requires": { - "colornames": "1.1.1" + "colornames": "^1.1.1" } }, "lodash": { @@ -681,11 +725,11 @@ "resolved": "https://registry.npmjs.org/logform/-/logform-1.10.0.tgz", "integrity": "sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg==", "requires": { - "colors": "1.3.3", - "fast-safe-stringify": "2.0.6", - "fecha": "2.3.3", - "ms": "2.1.1", - "triple-beam": "1.3.0" + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^2.3.3", + "ms": "^2.1.1", + "triple-beam": "^1.2.0" }, "dependencies": { "ms": { @@ -700,8 +744,8 @@ "resolved": "http://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.1" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, "mime-db": { @@ -714,7 +758,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", "requires": { - "mime-db": "1.36.0" + "mime-db": "~1.36.0" } }, "ms": { @@ -777,12 +821,12 @@ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.1", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" } }, "request": { @@ -790,26 +834,26 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.8.0", - "caseless": "0.12.0", - "combined-stream": "1.0.7", - "extend": "3.0.2", - "forever-agent": "0.6.1", - "form-data": "2.3.2", - "har-validator": "5.1.0", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.20", - "oauth-sign": "0.9.0", - "performance-now": "2.1.0", - "qs": "6.5.2", - "safe-buffer": "5.1.2", - "tough-cookie": "2.4.3", - "tunnel-agent": "0.6.0", - "uuid": "3.3.2" + "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.0", + "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.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" } }, "retry": { @@ -837,7 +881,7 @@ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", "requires": { - "is-arrayish": "0.3.2" + "is-arrayish": "^0.3.1" } }, "sshpk": { @@ -845,15 +889,15 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", "requires": { - "asn1": "0.2.4", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.2", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.2", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "safer-buffer": "2.1.2", - "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", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" } }, "stack-trace": { @@ -881,8 +925,8 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "requires": { - "psl": "1.1.29", - "punycode": "1.4.1" + "psl": "^1.1.24", + "punycode": "^1.4.1" } }, "triple-beam": { @@ -890,12 +934,17 @@ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + }, "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.2" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { @@ -937,9 +986,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" } }, "winston": { @@ -947,15 +996,15 @@ "resolved": "https://registry.npmjs.org/winston/-/winston-3.1.0.tgz", "integrity": "sha512-FsQfEE+8YIEeuZEYhHDk5cILo1HOcWkGwvoidLrDgPog0r4bser1lEIOco2dN9zpDJ1M88hfDgZvxe5z4xNcwg==", "requires": { - "async": "2.6.1", - "diagnostics": "1.1.1", - "is-stream": "1.1.0", - "logform": "1.10.0", + "async": "^2.6.0", + "diagnostics": "^1.1.1", + "is-stream": "^1.1.0", + "logform": "^1.9.1", "one-time": "0.0.4", - "readable-stream": "2.3.6", - "stack-trace": "0.0.10", - "triple-beam": "1.3.0", - "winston-transport": "4.3.0" + "readable-stream": "^2.3.6", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.2.0" }, "dependencies": { "inherits": { @@ -973,13 +1022,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -987,7 +1036,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -997,8 +1046,8 @@ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", "requires": { - "readable-stream": "2.3.6", - "triple-beam": "1.3.0" + "readable-stream": "^2.3.6", + "triple-beam": "^1.2.0" }, "dependencies": { "inherits": { @@ -1016,13 +1065,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -1030,7 +1079,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -1040,7 +1089,7 @@ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.2.8.tgz", "integrity": "sha1-m4FpCTFjH/CdGVdUn69U9PmAs8I=", "requires": { - "sax": "0.5.8" + "sax": "0.5.x" } }, "xmlbuilder": { @@ -1058,7 +1107,7 @@ "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.10.tgz", "integrity": "sha512-5vqMtRggU/2GhePC9OU4sYEWOdvmayp2k3gjPf4F0mXwB3CSbbNznfDUvDJx9O2ZTa1EIXdJhPchQveFKwNXPQ==", "requires": { - "zen-observable": "0.8.9" + "zen-observable": "^0.8.0" } } } diff --git a/package.json b/package.json index 90a19c944..321b779f7 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "author": "Luis-Fernando-Molina", "license": "ISC", "dependencies": { + "@azure/storage-blob": "^10.3.0", "apollo-boost": "^0.1.16", "assert": "^1.4.1", "axios": "^0.18.0", From 94ef85863eacc62b97c5aecd81352bdee6bc3170 Mon Sep 17 00:00:00 2001 From: Matias Date: Fri, 22 Mar 2019 18:01:25 +0100 Subject: [PATCH 64/76] Numeric value for the timePeriod --- Root.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Root.js b/Root.js index cd1a399f4..6938a84ed 100644 --- a/Root.js +++ b/Root.js @@ -346,7 +346,7 @@ case "Cloud": { processConfig.startMode = global.EXECUTION_CONFIG.startMode // Override file storage configuration if(global.EXECUTION_CONFIG.timePeriod){ - processConfig.timePeriod = global.EXECUTION_CONFIG.timePeriod + processConfig.timePeriod = Number(global.EXECUTION_CONFIG.timePeriod) } break; } From 3af01296d3a3eb7dcb450bcd631a0badae66ad6b Mon Sep 17 00:00:00 2001 From: Matias Date: Fri, 22 Mar 2019 18:33:18 +0100 Subject: [PATCH 65/76] Individual parameters --- Root.js | 4 +-- Run.js | 43 ++++++++++++++++--------------- TradingBotProcessMainLoop.js | 28 ++++++++++----------- package-lock.json | 49 ------------------------------------ package.json | 1 - 5 files changed, 37 insertions(+), 88 deletions(-) diff --git a/Root.js b/Root.js index 6938a84ed..f2c4737fb 100644 --- a/Root.js +++ b/Root.js @@ -345,8 +345,8 @@ switch (global.CURRENT_EXECUTION_AT) { case "Cloud": { processConfig.startMode = global.EXECUTION_CONFIG.startMode // Override file storage configuration - if(global.EXECUTION_CONFIG.timePeriod){ - processConfig.timePeriod = Number(global.EXECUTION_CONFIG.timePeriod) + if(global.TIME_PERIOD){ + processConfig.timePeriod = global.TIME_PERIOD } break; } diff --git a/Run.js b/Run.js index 52f7889a5..0610f0498 100644 --- a/Run.js +++ b/Run.js @@ -137,30 +137,29 @@ function readExecutionConfiguration() { } function getTimePeriod(){ - if(process.env.EXECUTION_PARAMETERS !== undefined){ + if(process.env.TIME_PERIOD !== undefined){ try { - let executionParameters = JSON.parse(process.env.EXECUTION_PARAMETERS) let timePeriodMap = new Map() - timePeriodMap.set("24-hs","86400000") - timePeriodMap.set("12-hs","43200000") - timePeriodMap.set("08-hs","28800000") - timePeriodMap.set("06-hs","21600000") - timePeriodMap.set("04-hs","14400000") - timePeriodMap.set("03-hs","10800000") - timePeriodMap.set("02-hs","7200000") - timePeriodMap.set("01-hs","3600000") - timePeriodMap.set("45-min","2700000") - timePeriodMap.set("40-min","2400000") - timePeriodMap.set("30-min","1800000") - timePeriodMap.set("20-min","1200000") - timePeriodMap.set("15-min","900000") - timePeriodMap.set("10-min","600000") - timePeriodMap.set("05-min","300000") - timePeriodMap.set("04-min","240000") - timePeriodMap.set("03-min","180000") - timePeriodMap.set("02-min","120000") - timePeriodMap.set("01-min","60000") - return timePeriodMap.get(executionParameters.timePeriod) + timePeriodMap.set("24-hs", 86400000) + timePeriodMap.set("12-hs", 43200000) + timePeriodMap.set("08-hs", 28800000) + timePeriodMap.set("06-hs", 21600000) + timePeriodMap.set("04-hs", 14400000) + timePeriodMap.set("03-hs", 10800000) + timePeriodMap.set("02-hs", 7200000) + timePeriodMap.set("01-hs", 3600000) + timePeriodMap.set("45-min", 2700000) + timePeriodMap.set("40-min", 2400000) + timePeriodMap.set("30-min", 1800000) + timePeriodMap.set("20-min", 1200000) + timePeriodMap.set("15-min", 900000) + timePeriodMap.set("10-min", 600000) + timePeriodMap.set("05-min", 300000) + timePeriodMap.set("04-min", 240000) + timePeriodMap.set("03-min", 180000) + timePeriodMap.set("02-min", 120000) + timePeriodMap.set("01-min", 60000) + return timePeriodMap.get(process.env.TIME_PERIOD) } catch (error) { console.log( "[WARN] Run -> readExecutionConfiguration -> getTimePeriod -> Error: ", error); } diff --git a/TradingBotProcessMainLoop.js b/TradingBotProcessMainLoop.js index 9d6e6cab5..0f5185b48 100644 --- a/TradingBotProcessMainLoop.js +++ b/TradingBotProcessMainLoop.js @@ -14,7 +14,7 @@ const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog'); let logger; // We need this here in order for the loopHealth function to work and be able to rescue the loop when it gets in trouble. - let nextLoopTimeoutHandle; + let nextLoopTimeoutHandle; let checkLoopHealthHandle; let thisObject = { @@ -25,7 +25,7 @@ bot["botCache"] = new Map(); let processConfig; let cloudStorage; - let UI_COMMANDS; + let UI_COMMANDS; return thisObject; @@ -58,7 +58,7 @@ } else { filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser. } - + break; } case "Browser": { @@ -145,7 +145,7 @@ try { if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[INFO] run -> Entering function."); } - bot.enableCheckLoopHealth = true; + bot.enableCheckLoopHealth = true; let fixedTimeLoopIntervalHandle; @@ -248,7 +248,7 @@ } else { - bot.processDatetime = new Date(bot.backtest.beginDatetime); // Set the starting time as the configured beginDatetime. + bot.processDatetime = new Date(bot.backtest.beginDatetime); // Set the starting time as the configured beginDatetime. } @@ -263,7 +263,7 @@ } else { - bot.processDatetime = new Date(bot.processDatetime.valueOf() + timePeriod); // We advance time here. + bot.processDatetime = new Date(bot.processDatetime.valueOf() + timePeriod); // We advance time here. if (UI_COMMANDS.eventHandler !== undefined) { @@ -276,11 +276,11 @@ if (UI_COMMANDS.endDatetime !== undefined) { - endDatetime = new Date(UI_COMMANDS.endDatetime.valueOf()); + endDatetime = new Date(UI_COMMANDS.endDatetime.valueOf()); } else { - endDatetime = new Date(bot.backtest.endDatetime); + endDatetime = new Date(bot.backtest.endDatetime); } @@ -381,7 +381,7 @@ + " " + bot.startMode + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8) + " bot.processDatetime = " + bot.processDatetime.toISOString()); /* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */ - + let exchangeAPI; let assistant; let userBot; @@ -537,7 +537,7 @@ callBackFunction(err); } } - + function initializeContext() { try { @@ -864,7 +864,7 @@ clearInterval(fixedTimeLoopIntervalHandle); clearTimeout(nextLoopTimeoutHandle); clearTimeout(checkLoopHealthHandle); - bot.enableCheckLoopHealth = false; + bot.enableCheckLoopHealth = false; callBackFunction(err); return; } @@ -1007,7 +1007,7 @@ nextWaitTime = 'Normal'; loopControl(nextWaitTime); - + } catch (err) { logger.write(MODULE_NAME, "[ERROR] run -> loop -> updateClonesModule -> err = " + err.message); logger.write(MODULE_NAME, "[ERROR] run -> loop -> updateClonesModule -> Execution will continue anyways. "); @@ -1167,7 +1167,7 @@ if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - /* + /* If for any reason this config file cannot be read, we are not going to abort the loop for that. Instead we are going to assume that there are no instructions to stop and we will keep the show running. */ @@ -1217,7 +1217,7 @@ } } catch (err) { - parentLogger.write(MODULE_NAME, "[ERROR] run -> loop -> err = " + err.message); + parentLogger.write(MODULE_NAME, "[ERROR] run -> loop -> err = " + err.stack); clearInterval(fixedTimeLoopIntervalHandle); clearTimeout(nextLoopTimeoutHandle); clearTimeout(checkLoopHealthHandle); diff --git a/package-lock.json b/package-lock.json index 1180a7ec5..72604727b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,45 +4,6 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@azure/ms-rest-js": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-1.2.3.tgz", - "integrity": "sha512-eROQ034b+9v0Hd3wETKi/EwF5pqS3VRAk1Lm8iKVPOP8v30f6Zfzsi420MRfBMsbNCx/mE2N0L65Px7tvcGfVg==", - "requires": { - "axios": "^0.18.0", - "form-data": "^2.3.2", - "tough-cookie": "^2.4.3", - "tslib": "^1.9.2", - "uuid": "^3.2.1", - "xml2js": "^0.4.19" - }, - "dependencies": { - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - } - } - }, - "@azure/storage-blob": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-10.3.0.tgz", - "integrity": "sha512-KZbJ3q8RpAdeIB5Em1lgXkiq7Mll9bSHHbHavOFMepkkF7HQa3Sez9FdkAVIkVVWK5YoBlshBGZ+mtiSQiS9Fw==", - "requires": { - "@azure/ms-rest-js": "1.2.3", - "events": "3.0.0", - "tslib": "^1.9.3" - } - }, "@types/async": { "version": "2.0.49", "resolved": "https://registry.npmjs.org/@types/async/-/async-2.0.49.tgz", @@ -410,11 +371,6 @@ "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==" }, - "events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", - "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==" - }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -934,11 +890,6 @@ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" }, - "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" - }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", diff --git a/package.json b/package.json index 321b779f7..90a19c944 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,6 @@ "author": "Luis-Fernando-Molina", "license": "ISC", "dependencies": { - "@azure/storage-blob": "^10.3.0", "apollo-boost": "^0.1.16", "assert": "^1.4.1", "axios": "^0.18.0", From 29a2fb56eb2bada0a73459015adb43cb90083adc Mon Sep 17 00:00:00 2001 From: Matias Date: Fri, 22 Mar 2019 19:15:34 +0100 Subject: [PATCH 66/76] Moving to paramaters to bot config --- Root.js | 6 ++++-- Run.js | 10 ++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Root.js b/Root.js index f2c4737fb..23f587d6a 100644 --- a/Root.js +++ b/Root.js @@ -345,8 +345,8 @@ switch (global.CURRENT_EXECUTION_AT) { case "Cloud": { processConfig.startMode = global.EXECUTION_CONFIG.startMode // Override file storage configuration - if(global.TIME_PERIOD){ - processConfig.timePeriod = global.TIME_PERIOD + if(global.EXECUTION_CONFIG.timePeriod){ + processConfig.timePeriod = global.EXECUTION_CONFIG.timePeriod } break; } @@ -865,6 +865,8 @@ logger = DEBUG_MODULE.newDebugLog(); logger.bot = pBotConfig; + pBotConfig.timePeriodFileStorage = global.EXECUTION_CONFIG.timePeriodFileStorage + pBotConfig.dataSet = global.EXECUTION_CONFIG.dataSet if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runTradingBot -> createBotInstance -> Entering function."); } diff --git a/Run.js b/Run.js index 0610f0498..be015b060 100644 --- a/Run.js +++ b/Run.js @@ -123,7 +123,9 @@ function readExecutionConfiguration() { global.EXECUTION_CONFIG = { executionList: executionList, startMode: startMode, - timePeriod: getTimePeriod() + timePeriod: getTimePeriod(process.env.TIME_PERIOD), + timePeriodFileStorage: process.env.TIME_PERIOD, + dataSet: process.env.DATA_SET }; readStoragePermissions(); @@ -136,8 +138,8 @@ function readExecutionConfiguration() { } } -function getTimePeriod(){ - if(process.env.TIME_PERIOD !== undefined){ +function getTimePeriod(timePeriod){ + if(timePeriod !== undefined){ try { let timePeriodMap = new Map() timePeriodMap.set("24-hs", 86400000) @@ -159,7 +161,7 @@ function getTimePeriod(){ timePeriodMap.set("03-min", 180000) timePeriodMap.set("02-min", 120000) timePeriodMap.set("01-min", 60000) - return timePeriodMap.get(process.env.TIME_PERIOD) + return timePeriodMap.get(timePeriod) } catch (error) { console.log( "[WARN] Run -> readExecutionConfiguration -> getTimePeriod -> Error: ", error); } From 052f000db948216053d1f49a917cdf07ef902612 Mon Sep 17 00:00:00 2001 From: Matias Date: Mon, 25 Mar 2019 11:09:49 +0100 Subject: [PATCH 67/76] Adding indicator error Causing the process to fail when there was an error on the initialization of the indicator. --- Root.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Root.js b/Root.js index 23f587d6a..a12f148bb 100644 --- a/Root.js +++ b/Root.js @@ -725,9 +725,10 @@ } else { logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> Bot will not be started. "); + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> Failed to initialize the bot. "); console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> err = " + err.message); logger.persist(); + throw new Error("Root -> start -> findProcess -> runIndicatorBot -> onInitializeReady -> Failed to initialize the bot.") } } } From e92f9cfeb951cf5c7bbfc31161601f835831bbab Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 25 Mar 2019 11:26:28 +0100 Subject: [PATCH 68/76] Update README.md --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1604ed841..26c9cd48e 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ -# AACloud +# Clone Executor -This repository holds the code of the bits of the AA Platform that run in the cloud. +Whithin the Superalgos project, we have the concept of Financial Beings, which are autonomous agents that have a financial life. These FBs entities have a master (imagine a class in programming) and clones (imagine an instance of a class running). The master is the one who aquires reputation after competitions. Every time we need to do a backtest, live trading or participating in a competition, a clone is extracted from the master and is put to run, either in backtest mode, live trading mode or competition mode. The clone lifespan is contrained by the purpose it was created. For instance, a clone created for a competition will live only during the period of such competition. -## About the AA Project +The software needed to execute these clones is the Clone Executor. -The AA Platform is built and maintained by Advanced Algos, the start up behind the AA Project. +## About the Superalgos Project + +Superalgos is built and maintained by the Superalgos Foundation and its Community. Our mission is to enable the fast-paced evolution of crypto trading bots within the context of trading bots competitions. From 66e4a286dfb6040cc206ef6c989bd3efac952f35 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 25 Mar 2019 12:17:32 +0100 Subject: [PATCH 69/76] Visual Studio Project Renamed --- AACloud.sln => CloneExecutor.sln | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename AACloud.sln => CloneExecutor.sln (100%) diff --git a/AACloud.sln b/CloneExecutor.sln similarity index 100% rename from AACloud.sln rename to CloneExecutor.sln From 50422852ae3f6736facab672682835b3b5e90463 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 25 Mar 2019 12:31:13 +0100 Subject: [PATCH 70/76] Cloud refactored to Node --- DebugLog.js | 2 +- Exchange/ExchangeAPI.js | 2 +- ExtractionBotProcessMainLoop.js | 8 ++++---- IndicatorBotProcessMainLoop.js | 8 ++++---- Root.js | 10 +++++----- Run.js | 2 +- TradingBotProcessMainLoop.js | 14 +++++++------- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/DebugLog.js b/DebugLog.js index 70adf7be0..50b83f7f8 100644 --- a/DebugLog.js +++ b/DebugLog.js @@ -163,7 +163,7 @@ return; } - if (global.CURRENT_EXECUTION_AT === "Cloud") { + if (global.CURRENT_EXECUTION_AT === "Node") { /* Only ERRORs go to the cloud console. */ diff --git a/Exchange/ExchangeAPI.js b/Exchange/ExchangeAPI.js index 3129473d6..6e8f68098 100644 --- a/Exchange/ExchangeAPI.js +++ b/Exchange/ExchangeAPI.js @@ -38,7 +38,7 @@ let accessToken let keyId let cloneId - if (global.CURRENT_EXECUTION_AT === "Cloud") { + if (global.CURRENT_EXECUTION_AT === "Node") { keyId = process.env.KEY_ID cloneId = process.env.CLONE_ID diff --git a/ExtractionBotProcessMainLoop.js b/ExtractionBotProcessMainLoop.js index 81b4b90a5..b6dbe7ae5 100644 --- a/ExtractionBotProcessMainLoop.js +++ b/ExtractionBotProcessMainLoop.js @@ -49,7 +49,7 @@ let filePath; switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy. - case "Cloud": { + case "Node": { if (global.RUN_AS_TEAM) { filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud. } else { @@ -85,7 +85,7 @@ USER_BOT_MODULE = pMODULE; switch (global.CURRENT_EXECUTION_AT) { - case "Cloud": { + case "Node": { filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo; break; } @@ -664,7 +664,7 @@ function checkLoopHealth(pLastLoop) { - if (global.CURRENT_EXECUTION_AT !== "Cloud") { + if (global.CURRENT_EXECUTION_AT !== "Node") { return; } @@ -717,7 +717,7 @@ let filePath; switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy. - case "Cloud": { + case "Node": { filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud. break; } diff --git a/IndicatorBotProcessMainLoop.js b/IndicatorBotProcessMainLoop.js index 514f6d635..591aa6648 100644 --- a/IndicatorBotProcessMainLoop.js +++ b/IndicatorBotProcessMainLoop.js @@ -51,7 +51,7 @@ let filePath; switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy. - case "Cloud": { + case "Node": { if (global.RUN_AS_TEAM) { filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud. } else { @@ -88,7 +88,7 @@ USER_BOT_MODULE = pMODULE; switch (global.CURRENT_EXECUTION_AT) { - case "Cloud": { + case "Node": { filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo; break; } @@ -898,7 +898,7 @@ function checkLoopHealth(pLastLoop) { - if (global.CURRENT_EXECUTION_AT !== "Cloud") { + if (global.CURRENT_EXECUTION_AT !== "Node") { return; } @@ -951,7 +951,7 @@ let filePath; switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy. - case "Cloud": { + case "Node": { filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud. break; } diff --git a/Root.js b/Root.js index a12f148bb..1cf6532fa 100644 --- a/Root.js +++ b/Root.js @@ -140,7 +140,7 @@ let filePath; switch (global.CURRENT_EXECUTION_AT) { - case "Cloud": { + case "Node": { filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud. break; } @@ -253,7 +253,7 @@ let filePath; switch (global.CURRENT_EXECUTION_AT) { - case "Cloud": { + case "Node": { filePath = global.DEV_TEAM + "/" + "bots" + "/" + listItem.repo; // DevTeams bots only are run at the cloud. console.log(logDisplace + "Root : [INFO] start -> getBotConfig -> Getting Bot Config from the devTeams's Bot. "); @@ -343,7 +343,7 @@ let processConfig = botConfig.processes[i]; switch (global.CURRENT_EXECUTION_AT) { - case "Cloud": { + case "Node": { processConfig.startMode = global.EXECUTION_CONFIG.startMode // Override file storage configuration if(global.EXECUTION_CONFIG.timePeriod){ processConfig.timePeriod = global.EXECUTION_CONFIG.timePeriod @@ -819,7 +819,7 @@ let clonName = botConfig.codeName + "-" + "Clon" + clonKey; clonName += ".1.0"; - if (global.CURRENT_EXECUTION_AT === "Cloud") { + if (global.CURRENT_EXECUTION_AT === "Node") { clonName += "-" + process.env.CLONE_ID; } @@ -843,7 +843,7 @@ let genes = {}; let clonName = botConfig.codeName; - if (global.CURRENT_EXECUTION_AT === "Cloud") { + if (global.CURRENT_EXECUTION_AT === "Node") { clonName += "-" + process.env.CLONE_ID; } diff --git a/Run.js b/Run.js index be015b060..926474a32 100644 --- a/Run.js +++ b/Run.js @@ -1,7 +1,7 @@ require('dotenv').config() global.CURRENT_ENVIRONMENT = "Develop"; -global.CURRENT_EXECUTION_AT = "Cloud"; +global.CURRENT_EXECUTION_AT = "Node"; global.SHALL_BOT_STOP = false; global.AT_BREAKPOINT = false; // This is used only when running at the browser. global.RUN_AS_TEAM = false; diff --git a/TradingBotProcessMainLoop.js b/TradingBotProcessMainLoop.js index 0f5185b48..4aceb006b 100644 --- a/TradingBotProcessMainLoop.js +++ b/TradingBotProcessMainLoop.js @@ -52,7 +52,7 @@ let filePath; switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy. - case "Cloud": { + case "Node": { if (global.RUN_AS_TEAM) { filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud. } else { @@ -94,7 +94,7 @@ USER_BOT_MODULE = pMODULE; switch (global.CURRENT_EXECUTION_AT) { - case "Cloud": { + case "Node": { filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo; break; } @@ -284,7 +284,7 @@ } - if (global.CURRENT_EXECUTION_AT === "Cloud") { + if (global.CURRENT_EXECUTION_AT === "Node") { if (bot.processDatetime.valueOf() > endDatetime.valueOf()) { @@ -323,7 +323,7 @@ } - if (global.CURRENT_EXECUTION_AT === "Cloud") { + if (global.CURRENT_EXECUTION_AT === "Node") { let beginDatetime = new Date(bot.competition.beginDatetime); @@ -987,7 +987,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> updateClonesModule -> Entering function."); } - if (global.CURRENT_EXECUTION_AT === "Cloud") { + if (global.CURRENT_EXECUTION_AT === "Node") { // Update clones module with latest context informations @@ -1079,7 +1079,7 @@ function checkLoopHealth(pLastLoop) { - if (global.CURRENT_EXECUTION_AT !== "Cloud") { + if (global.CURRENT_EXECUTION_AT !== "Node") { return; } @@ -1134,7 +1134,7 @@ let filePath; switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy. - case "Cloud": { + case "Node": { filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud. break; } From 9a277ddd720cc2ac401bc18460ab162b9c3544a8 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 25 Mar 2019 14:34:35 +0100 Subject: [PATCH 71/76] Browser Execution type removed --- DebugLog.js | 19 +-------- Exchange/ExchangeAPI.js | 4 +- ExtractionBotProcessMainLoop.js | 73 ++++----------------------------- IndicatorBotProcessMainLoop.js | 70 ++++--------------------------- Root.js | 69 ++++--------------------------- TradingBotProcessMainLoop.js | 55 +++---------------------- 6 files changed, 33 insertions(+), 257 deletions(-) diff --git a/DebugLog.js b/DebugLog.js index 50b83f7f8..8f82f1c19 100644 --- a/DebugLog.js +++ b/DebugLog.js @@ -60,13 +60,6 @@ internalLoopCounter++; - if (global.CURRENT_EXECUTION_AT === "Browser") { - - //console.log("[INFO] DebugLog -> persist -> We do not persist logs while running at the Browser"); - return; - - } - let contentToPersist = accumulatedLog; accumulatedLog = "["; @@ -149,20 +142,12 @@ if (global.CURRENT_EXECUTION_AT === "IDE") { - console.log("AACloud" + spacePad(pModule, 50) + " : " + pMessage); + console.log("CloneExecutor" + spacePad(pModule, 50) + " : " + pMessage); } if (disableLogging === true) { return; } - if (global.CURRENT_EXECUTION_AT === "Browser") { - - /* Only at the browser we send the messages to the console. At the Cloud it does not make sense. */ - - console.log("AACloud" + spacePad(pModule, 50) + " : " + pMessage); - return; - } - if (global.CURRENT_EXECUTION_AT === "Node") { /* Only ERRORs go to the cloud console. */ @@ -170,7 +155,7 @@ if (pMessage.indexOf("[ERROR]") >= 0) { let now = new Date; - console.log("Loop." + pad(thisObject.bot.loopCounter, 8) + " " + now.toUTCString() + " AACloud " + spacePad(pModule, 20) + " : " + pMessage); + console.log("Loop." + pad(thisObject.bot.loopCounter, 8) + " " + now.toUTCString() + " CloneExecutor " + spacePad(pModule, 20) + " : " + pMessage); } } diff --git a/Exchange/ExchangeAPI.js b/Exchange/ExchangeAPI.js index 6e8f68098..1f29542b4 100644 --- a/Exchange/ExchangeAPI.js +++ b/Exchange/ExchangeAPI.js @@ -45,9 +45,7 @@ let auth = require('../utils/auth') let authTokenCloud = await auth.authenticate() accessToken = 'Bearer ' + authTokenCloud - } else if (global.CURRENT_EXECUTION_AT === "Browser") { - accessToken = 'Bearer ' + authToken - } + } let keyVaultAPI = createKeyVaultAPIClient(accessToken, keyId, cloneId) apiClient = api.newAPIClient(keyVaultAPI, logger); diff --git a/ExtractionBotProcessMainLoop.js b/ExtractionBotProcessMainLoop.js index b6dbe7ae5..8d1b4209c 100644 --- a/ExtractionBotProcessMainLoop.js +++ b/ExtractionBotProcessMainLoop.js @@ -47,25 +47,11 @@ if (err.result === global.DEFAULT_OK_RESPONSE.result) { let filePath; - - switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy. - case "Node": { - if (global.RUN_AS_TEAM) { - filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud. - } else { - filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser. - } - break; - } - case "Browser": { - filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser. - break; - } - default: { - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'."); - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - return; } + + if (global.RUN_AS_TEAM) { + filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud. + } else { + filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser. } const CLOUD_REQUIRE = require(ROOT_DIR + 'CloudRequire'); @@ -84,23 +70,8 @@ USER_BOT_MODULE = pMODULE; - switch (global.CURRENT_EXECUTION_AT) { - case "Node": { - filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo; - break; - } - case "Browser": { - filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO; - break; - } - default: { - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'."); - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - return; - } - } - + filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo; + cloudRequire.downloadCommons(cloudStorage, filePath, onCommonsDownloaded); function onCommonsDownloaded(err, pMODULE) { @@ -714,34 +685,8 @@ if (err.result === global.DEFAULT_OK_RESPONSE.result) { - let filePath; - - switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy. - case "Node": { - filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud. - break; - } - case "Browser": { - if (global.SHALL_BOT_STOP === false) { - continueCallBack(); - } else { - stopCallBack(); - } - return; - } - default: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'."); - logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT); - logger.persist(); - clearInterval(fixedTimeLoopIntervalHandle); - clearTimeout(nextLoopTimeoutHandle); - clearTimeout(checkLoopHealthHandle); - bot.enableCheckLoopHealth = false; - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - return; - } - } - + let filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud. + let fileName = "this.config.json"; cloudStorage.getTextFile(filePath, fileName, onFileReceived); diff --git a/IndicatorBotProcessMainLoop.js b/IndicatorBotProcessMainLoop.js index 591aa6648..6de54adc5 100644 --- a/IndicatorBotProcessMainLoop.js +++ b/IndicatorBotProcessMainLoop.js @@ -50,25 +50,10 @@ let filePath; - switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy. - case "Node": { - if (global.RUN_AS_TEAM) { - filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud. - } else { - filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser. - } - break; - } - case "Browser": { - filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser. - break; - } - default: { - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'."); - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - return; - } + if (global.RUN_AS_TEAM) { + filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud. + } else { + filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser. } const CLOUD_REQUIRE = require(ROOT_DIR + 'CloudRequire'); @@ -87,22 +72,7 @@ USER_BOT_MODULE = pMODULE; - switch (global.CURRENT_EXECUTION_AT) { - case "Node": { - filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo; - break; - } - case "Browser": { - filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO; - break; - } - default: { - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'."); - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - return; - } - } + filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo; cloudRequire.downloadCommons(cloudStorage, filePath, onCommonsDownloaded); @@ -948,34 +918,8 @@ if (err.result === global.DEFAULT_OK_RESPONSE.result) { - let filePath; - - switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy. - case "Node": { - filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud. - break; - } - case "Browser": { - if (global.SHALL_BOT_STOP === false) { - continueCallBack(); - } else { - stopCallBack(); - } - return; - } - default: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'."); - logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT); - logger.persist(); - clearInterval(fixedTimeLoopIntervalHandle); - clearTimeout(nextLoopTimeoutHandle); - clearTimeout(checkLoopHealthHandle); - bot.enableCheckLoopHealth = false; - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - return; - } - } - + let filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud. + let fileName = "this.config.json"; cloudStorage.getTextFile(filePath, fileName, onFileReceived); diff --git a/Root.js b/Root.js index 1cf6532fa..240117a74 100644 --- a/Root.js +++ b/Root.js @@ -74,7 +74,7 @@ let cloudStorage; - let logDisplace = "AACloud" + " "; + let logDisplace = "CloneExecutor" + " "; let UI_COMMANDS; return thisObject; @@ -137,21 +137,7 @@ if (err.result === global.DEFAULT_OK_RESPONSE.result) { - let filePath; - - switch (global.CURRENT_EXECUTION_AT) { - case "Node": { - filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud. - break; - } - case "Browser": { - filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + "AACloud"; // DevTeam Members bots only are run at the browser. - break; - } - default: { - console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser' "); - } - } + let filePath = global.DEV_TEAM + "/" + "CloneExecutor"; // DevTeams bots only are run at the cloud. let fileName = "this.config.json"; @@ -230,7 +216,7 @@ continue; } - /* Now we will read the config of the bot from the path we obtained at the AACloud config. */ + /* Now we will read the config of the bot from the path we obtained at the CloneExecutor config. */ let botConfig; @@ -250,28 +236,7 @@ if (err.result === global.DEFAULT_OK_RESPONSE.result) { - let filePath; - - switch (global.CURRENT_EXECUTION_AT) { - case "Node": { - filePath = global.DEV_TEAM + "/" + "bots" + "/" + listItem.repo; // DevTeams bots only are run at the cloud. - - console.log(logDisplace + "Root : [INFO] start -> getBotConfig -> Getting Bot Config from the devTeams's Bot. "); - console.log(logDisplace + "Root : [INFO] start -> getBotConfig -> filePath = " + filePath); - break; - } - case "Browser": { - filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO; // DevTeam Members bots only are run at the browser. - - console.log(logDisplace + "Root : [INFO] start -> getBotConfig -> Getting Bot Config from the endUser's Bot. "); - console.log(logDisplace + "Root : [INFO] start -> getBotConfig -> global.USER_LOGGED_IN = " + global.USER_LOGGED_IN); - console.log(logDisplace + "Root : [INFO] start -> getBotConfig -> filePath = " + filePath); - break; - } - default: { - console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser' "); - } - } + let filePath = global.DEV_TEAM + "/" + "bots" + "/" + listItem.repo; // DevTeams bots only are run at the cloud. let fileName = "this.bot.config.json"; @@ -342,27 +307,11 @@ let processConfig = botConfig.processes[i]; - switch (global.CURRENT_EXECUTION_AT) { - case "Node": { - processConfig.startMode = global.EXECUTION_CONFIG.startMode // Override file storage configuration - if(global.EXECUTION_CONFIG.timePeriod){ - processConfig.timePeriod = global.EXECUTION_CONFIG.timePeriod - } - break; - } - case "Browser": { - let startMode = { - live: { run: "false" }, - backtest: { run: "false", waitTime: 5000 }, - competition: { run: "false" } - } - let browserStartMode = global.CURRENT_START_MODE.toLowerCase() - startMode[browserStartMode].run = "true" - - processConfig.startMode = startMode - break; - } + processConfig.startMode = global.EXECUTION_CONFIG.startMode // Override file storage configuration + if(global.EXECUTION_CONFIG.timePeriod){ + processConfig.timePeriod = global.EXECUTION_CONFIG.timePeriod } + try { /* We test each type of start Mode to get what to run and how. */ @@ -593,7 +542,7 @@ if (processFound === false) { - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Process listed at the configuration file of AACloud not found at the configuration file of the bot."); + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Process listed at the configuration file of CloneExecutor not found at the configuration file of the bot."); console.log(logDisplace + "Root : [ERROR] start -> findProcess -> listItem.process = " + listItem.process); } diff --git a/TradingBotProcessMainLoop.js b/TradingBotProcessMainLoop.js index 4aceb006b..14ad87b49 100644 --- a/TradingBotProcessMainLoop.js +++ b/TradingBotProcessMainLoop.js @@ -61,16 +61,12 @@ break; } - case "Browser": { - filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser. - break; - } case "IDE": { filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // This works like Cloud except of a few things. break; } default: { - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'."); + parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Node' or 'IDE'."); parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return; @@ -93,23 +89,8 @@ USER_BOT_MODULE = pMODULE; - switch (global.CURRENT_EXECUTION_AT) { - case "Node": { - filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo; - break; - } - case "Browser": { - filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO; - break; - } - default: { - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'."); - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - return; - } - } - + filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo; + cloudRequire.downloadCommons(cloudStorage, filePath, onCommonsDownloaded); function onCommonsDownloaded(err, pMODULE) { @@ -1131,34 +1112,8 @@ if (err.result === global.DEFAULT_OK_RESPONSE.result) { - let filePath; - - switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy. - case "Node": { - filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud. - break; - } - case "Browser": { - if (global.SHALL_BOT_STOP === false) { - continueCallBack(); - } else { - stopCallBack(); - } - return; - } - default: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'."); - logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT); - logger.persist(); - clearInterval(fixedTimeLoopIntervalHandle); - clearTimeout(nextLoopTimeoutHandle); - clearTimeout(checkLoopHealthHandle); - bot.enableCheckLoopHealth = false; - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - return; - } - } - + let filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud. + let fileName = "this.config.json"; cloudStorage.getTextFile(filePath, fileName, onFileReceived); From 0353bddef7176af96aa56b5835fc4ef9fd925a6f Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 25 Mar 2019 16:25:05 +0100 Subject: [PATCH 72/76] Eliminated the Execution List from the config and the code. Only one clone can be executed at the time now. --- Root.js | 1032 ++++++++++++++++++++++------------------------ Run.js | 6 +- this.config.json | 51 --- 3 files changed, 507 insertions(+), 582 deletions(-) diff --git a/Root.js b/Root.js index 240117a74..710a8ee01 100644 --- a/Root.js +++ b/Root.js @@ -137,7 +137,7 @@ if (err.result === global.DEFAULT_OK_RESPONSE.result) { - let filePath = global.DEV_TEAM + "/" + "CloneExecutor"; // DevTeams bots only are run at the cloud. + let filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud. let fileName = "this.config.json"; @@ -192,224 +192,170 @@ /* Loop through all the processes configured to be run by this Node.js Instance. */ - for (let p = 0; p < global.PLATFORM_CONFIG.executionList.length; p++) { + let cloneToExecute = global.EXECUTION_CONFIG.cloneToExecute; - let listItem; + /* Now we will read the config of the bot from the path we obtained at the CloneExecutor config. */ - /* - The local configuration allows to select the configuration to run - locally, without overwriting the server config. - Here we check that the local configuration for the execution - exist, if it doesn't exist we will take the one on the server. - */ - if (global.EXECUTION_CONFIG === undefined) { - listItem = PLATFORM_CONFIG.executionList[p]; - } else { - listItem = global.EXECUTION_CONFIG.executionList[p]; - } + let botConfig; - if (listItem === undefined || listItem.enabled !== "true") { + getBotConfig(); - console.log(logDisplace + "Root : [INFO] start -> Skipping process for being disabled."); - console.log(logDisplace + "Root : [INFO] start -> listItem.process = " + PLATFORM_CONFIG.executionList[p].process); + function getBotConfig() { - continue; - } + try { + console.log(logDisplace + "Root : [INFO] start -> getBotConfig -> Entering function. "); - /* Now we will read the config of the bot from the path we obtained at the CloneExecutor config. */ + const BLOB_STORAGE = require(ROOT_DIR + 'BlobStorage'); + let cloudStorage = BLOB_STORAGE.newBlobStorage(cloneToExecute); - let botConfig; + cloudStorage.initialize("AAPlatform", onInizialized, true); - getBotConfig(); + function onInizialized(err) { - function getBotConfig() { + if (err.result === global.DEFAULT_OK_RESPONSE.result) { - try { - console.log(logDisplace + "Root : [INFO] start -> getBotConfig -> Entering function. "); + let filePath = global.DEV_TEAM + "/" + "bots" + "/" + cloneToExecute.repo; // DevTeams bots only are run at the cloud. - const BLOB_STORAGE = require(ROOT_DIR + 'BlobStorage'); - let cloudStorage = BLOB_STORAGE.newBlobStorage(listItem); + let fileName = "this.bot.config.json"; - cloudStorage.initialize("AAPlatform", onInizialized, true); + cloudStorage.getTextFile(filePath, fileName, onFileReceived); - function onInizialized(err) { + function onFileReceived(err, text) { - if (err.result === global.DEFAULT_OK_RESPONSE.result) { + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> onFileReceived -> err = " + err.message); + console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> onFileReceived -> filePath = " + filePath); + console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> onFileReceived -> fileName = " + fileName); - let filePath = global.DEV_TEAM + "/" + "bots" + "/" + listItem.repo; // DevTeams bots only are run at the cloud. - - let fileName = "this.bot.config.json"; - - cloudStorage.getTextFile(filePath, fileName, onFileReceived); - - function onFileReceived(err, text) { - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> onFileReceived -> err = " + err.message); - console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> onFileReceived -> filePath = " + filePath); - console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> onFileReceived -> fileName = " + fileName); - - return; - } - - try { - botConfig = JSON.parse(text); - botConfig.repo = listItem.repo; - findProcess(); - } catch (err) { - console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> onFileReceived -> err = " + err.message); - return; - } + return; } - } else { - console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> err = " + err.message); - return; + try { + botConfig = JSON.parse(text); + botConfig.repo = cloneToExecute.repo; + findProcess(); + } catch (err) { + console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> onFileReceived -> err = " + err.message); + return; + } } + + } else { + console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> onInizialized -> err = " + err.message); + return; } } - catch (err) { - console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> err.message = " + err.message); - return; - } } + catch (err) { + console.log(logDisplace + "Root : [ERROR] start -> getBotConfig -> err.message = " + err.message); + return; + } + } - function findProcess() { + function findProcess() { - try { - if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Entering function. "); } + try { + if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Entering function. "); } - botConfig.process = listItem.process; - botConfig.debug = {}; + botConfig.process = cloneToExecute.process; + botConfig.debug = {}; - /* Loop Counter */ + /* Loop Counter */ - botConfig.loopCounter = 0; + botConfig.loopCounter = 0; - if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Processing item from executionList -> p = " + p); } + /* File Path Root */ - /* File Path Root */ + botConfig.filePathRoot = botConfig.devTeam + "/" + botConfig.codeName + "." + botConfig.version.major + "." + botConfig.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion; - botConfig.filePathRoot = botConfig.devTeam + "/" + botConfig.codeName + "." + botConfig.version.major + "." + botConfig.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion; + if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> cloneToExecute.process = " + cloneToExecute.process); } - if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> listItem.process = " + listItem.process); } + /* Now we loop throug all the configured processes at each bots configuration until we find the one we are supposed to run at this Node.js process. */ - /* Now we loop throug all the configured processes at each bots configuration until we find the one we are supposed to run at this Node.js process. */ + let processFound = false; - let processFound = false; + for (let i = 0; i < botConfig.processes.length; i++) { - for (let i = 0; i < botConfig.processes.length; i++) { + if (botConfig.processes[i].name === cloneToExecute.process) { - if (botConfig.processes[i].name === listItem.process) { + processFound = true; + if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> cloneToExecute.process = " + cloneToExecute.process); } - processFound = true; - if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> listItem.process = " + listItem.process); } + let processConfig = botConfig.processes[i]; - let processConfig = botConfig.processes[i]; - - processConfig.startMode = global.EXECUTION_CONFIG.startMode // Override file storage configuration - if(global.EXECUTION_CONFIG.timePeriod){ - processConfig.timePeriod = global.EXECUTION_CONFIG.timePeriod - } + processConfig.startMode = global.EXECUTION_CONFIG.startMode // Override file storage configuration + if(global.EXECUTION_CONFIG.timePeriod){ + processConfig.timePeriod = global.EXECUTION_CONFIG.timePeriod + } - try { + try { - /* We test each type of start Mode to get what to run and how. */ + /* We test each type of start Mode to get what to run and how. */ - if (processConfig.startMode.allMonths !== undefined) { + if (processConfig.startMode.allMonths !== undefined) { - if (processConfig.startMode.allMonths.run === "true") { + if (processConfig.startMode.allMonths.run === "true") { - if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> allMonths start mode detected. "); } + if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> allMonths start mode detected. "); } - for (let year = processConfig.startMode.allMonths.maxYear; year >= processConfig.startMode.allMonths.minYear; year--) { + for (let year = processConfig.startMode.allMonths.maxYear; year >= processConfig.startMode.allMonths.minYear; year--) { - for (let month = 12; month > 0; month--) { + for (let month = 12; month > 0; month--) { - let padMonth = pad(month, 2) + let padMonth = pad(month, 2) - let newInstanceBotConfig = JSON.parse(JSON.stringify(botConfig)); + let newInstanceBotConfig = JSON.parse(JSON.stringify(botConfig)); - newInstanceBotConfig.debug = { - month: pad(month, 2), - year: pad(year, 4) - }; + newInstanceBotConfig.debug = { + month: pad(month, 2), + year: pad(year, 4) + }; - let timeDelay = Math.random() * 10 * 1000; // We introduce a short delay so as to not overload the machine. - setTimeout(startProcess, timeDelay); + let timeDelay = Math.random() * 10 * 1000; // We introduce a short delay so as to not overload the machine. + setTimeout(startProcess, timeDelay); - function startProcess() { + function startProcess() { - if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> startProcess -> Ready to start process."); } + if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> startProcess -> Ready to start process."); } - switch (botConfig.type) { - case 'Extraction': { - runExtractionBot(newInstanceBotConfig, processConfig, padMonth, year); - break; - } - case 'Indicator': { - runIndicatorBot(newInstanceBotConfig, processConfig, padMonth, year); - break; - } - default: { - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> startProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type); - } + switch (botConfig.type) { + case 'Extraction': { + runExtractionBot(newInstanceBotConfig, processConfig, padMonth, year); + break; + } + case 'Indicator': { + runIndicatorBot(newInstanceBotConfig, processConfig, padMonth, year); + break; + } + default: { + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> startProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type); } } } } } } + } - if (processConfig.startMode.oneMonth !== undefined) { + if (processConfig.startMode.oneMonth !== undefined) { - if (processConfig.startMode.oneMonth.run === "true") { + if (processConfig.startMode.oneMonth.run === "true") { - if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> oneMonth start mode detected. "); } + if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> oneMonth start mode detected. "); } - startProcess(); + startProcess(); - function startProcess() { + function startProcess() { - if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> startProcess -> Ready to start process."); } + if (FULL_LOG === true) { console.log(logDisplace + "Root : [INFO] start -> findProcess -> startProcess -> Ready to start process."); } - let month = pad(processConfig.startMode.oneMonth.month, 2); - let year = processConfig.startMode.oneMonth.year; + let month = pad(processConfig.startMode.oneMonth.month, 2); + let year = processConfig.startMode.oneMonth.year; - botConfig.debug = { - month: pad(month, 2), - year: pad(year, 4) - }; - - switch (botConfig.type) { - case 'Extraction': { - runExtractionBot(botConfig, processConfig, month, year); - break; - } - case 'Indicator': { - runIndicatorBot(botConfig, processConfig, month, year); - break; - } - default: { - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> startProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type); - } - } - } - } - } - - if (processConfig.startMode.noTime !== undefined) { - - if (processConfig.startMode.noTime.run === "true") { - - let month = pad((new Date()).getUTCMonth() + 1, 2); - let year = (new Date()).getUTCFullYear(); - - if (processConfig.startMode.noTime.resumeExecution === "true") { - botConfig.hasTheBotJustStarted = false; - } else { - botConfig.hasTheBotJustStarted = true; - } + botConfig.debug = { + month: pad(month, 2), + year: pad(year, 4) + }; switch (botConfig.type) { case 'Extraction': { @@ -421,464 +367,494 @@ break; } default: { - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type); + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> startProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type); } } } } + } - if (processConfig.startMode.fixedInterval !== undefined) { + if (processConfig.startMode.noTime !== undefined) { - if (processConfig.startMode.fixedInterval.run === "true") { + if (processConfig.startMode.noTime.run === "true") { - botConfig.runAtFixedInterval = true; - botConfig.fixedInterval = processConfig.startMode.fixedInterval.interval; - - let month = pad((new Date()).getUTCMonth() + 1, 2); - let year = (new Date()).getUTCFullYear(); - - switch (botConfig.type) { - case 'Extraction': { - runExtractionBot(botConfig, processConfig, month, year); - break; - } - default: { - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type); - } - } - } - } - - if (processConfig.startMode.live !== undefined) { - - if (processConfig.startMode.live.run === "true") { - - botConfig.startMode = "Live"; - console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode); - - let month = pad((new Date()).getUTCMonth() + 1, 2); - let year = (new Date()).getUTCFullYear(); - - if (processConfig.startMode.live.resumeExecution === "true") { - botConfig.hasTheBotJustStarted = false; - } else { - botConfig.hasTheBotJustStarted = true; - } - - switch (botConfig.type) { - case 'Trading': { - runTradingBot(botConfig, processConfig); - break; - } - default: { - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type); - } - } - } - } - - if (processConfig.startMode.backtest !== undefined) { - - if (processConfig.startMode.backtest.run === "true") { - - botConfig.startMode = "Backtest"; - console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode); - - botConfig.backtest = processConfig.startMode.backtest; - - /* We override these waitTimes to the one specified at the backtest configuration. */ - - processConfig.normalWaitTime = processConfig.startMode.backtest.waitTime; - processConfig.retryWaitTime = processConfig.startMode.backtest.waitTime; - - /* Backtest Mode does not support Resume Execution, so this is the only way. */ + let month = pad((new Date()).getUTCMonth() + 1, 2); + let year = (new Date()).getUTCFullYear(); + if (processConfig.startMode.noTime.resumeExecution === "true") { + botConfig.hasTheBotJustStarted = false; + } else { botConfig.hasTheBotJustStarted = true; - - switch (botConfig.type) { - case 'Trading': { - runTradingBot(botConfig, processConfig); - break; - } - default: { - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type); - } - } - } - } - - if (processConfig.startMode.competition !== undefined) { - - if (processConfig.startMode.competition.run === "true") { - - botConfig.startMode = "Competition"; - console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode); - - botConfig.competition = processConfig.startMode.competition; - - if (processConfig.startMode.competition.resumeExecution === "false") { - botConfig.hasTheBotJustStarted = true; - } else { - botConfig.hasTheBotJustStarted = false; - } - - switch (botConfig.type) { - case 'Trading': { - runTradingBot(botConfig, processConfig); - break; - } - default: { - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type); - } - } - } - } - - } catch (err) { - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected exception. -> err.message = " + err.message); - } - } - } - - if (processFound === false) { - - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Process listed at the configuration file of CloneExecutor not found at the configuration file of the bot."); - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> listItem.process = " + listItem.process); - - } - - function runExtractionBot(pBotConfig, pProcessConfig, pMonth, pYear) { - - try { - - const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog'); - let logger; - - logger = DEBUG_MODULE.newDebugLog(); - logger.bot = pBotConfig; - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runExtractionBot -> Entering function."); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runExtractionBot -> pMonth = " + pMonth); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runExtractionBot -> pYear = " + pYear); } - - let extractionBotMainLoop = EXTRACTION_BOT_MAIN_LOOP_MODULE.newExtractionBotProcessMainLoop(pBotConfig, logger); - extractionBotMainLoop.initialize(UI_COMMANDS, pProcessConfig, onInitializeReady); - - function onInitializeReady(err) { - - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - - extractionBotMainLoop.run(pMonth, pYear, whenRunFinishes); - - function whenRunFinishes(err) { - - pBotConfig.loopCounter = 0; - - let botId; - if (pYear !== undefined) { - botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.process + "." + pYear + "." + pMonth; - } else { - botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.process; - } - - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); - logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); - - console.log(logDisplace + "Root : [INFO] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> botId = " + botId); - console.log(logDisplace + "Root : [INFO] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); - - logger.persist(); - - } else { - - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. "); - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bye."); - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); - - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> botId = " + botId); - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bot execution was aborted."); - logger.persist(); - } } - } else { - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> Bot will not be started. "); - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> err = " + err.message); - - logger.persist(); + switch (botConfig.type) { + case 'Extraction': { + runExtractionBot(botConfig, processConfig, month, year); + break; + } + case 'Indicator': { + runIndicatorBot(botConfig, processConfig, month, year); + break; + } + default: { + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type); + } + } } } - } - catch (err) { - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runExtractionBot -> err = " + err.message); - } - } - function runIndicatorBot(pBotConfig, pProcessConfig, pMonth, pYear) { + if (processConfig.startMode.fixedInterval !== undefined) { - try { - const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog'); - let logger; + if (processConfig.startMode.fixedInterval.run === "true") { - logger = DEBUG_MODULE.newDebugLog(); - logger.bot = pBotConfig; + botConfig.runAtFixedInterval = true; + botConfig.fixedInterval = processConfig.startMode.fixedInterval.interval; - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> Entering function."); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> pMonth = " + pMonth); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> pYear = " + pYear); } + let month = pad((new Date()).getUTCMonth() + 1, 2); + let year = (new Date()).getUTCFullYear(); - let indicatorBotMainLoop = INDICATOR_BOT_MAIN_LOOP_MODULE.newIndicatorBotProcessMainLoop(pBotConfig, logger); - indicatorBotMainLoop.initialize(UI_COMMANDS, pProcessConfig, onInitializeReady); - - function onInitializeReady(err) { - - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - - indicatorBotMainLoop.run(pMonth, pYear, whenRunFinishes); - - function whenRunFinishes(err) { - - pBotConfig.loopCounter = 0; - - let botId; - if (pYear !== undefined) { - botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.process + "." + pYear + "." + pMonth; - } else { - botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.process; + switch (botConfig.type) { + case 'Extraction': { + runExtractionBot(botConfig, processConfig, month, year); + break; } - - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); - logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); - - console.log(logDisplace + "Root : [INFO] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> botId = " + botId); - console.log(logDisplace + "Root : [INFO] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); - - logger.persist(); - - } else { - - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. "); - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bye."); - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished with errors. Please check the logs."); - logger.persist(); + default: { + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type); } } - - } else { - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> Failed to initialize the bot. "); - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> err = " + err.message); - logger.persist(); - throw new Error("Root -> start -> findProcess -> runIndicatorBot -> onInitializeReady -> Failed to initialize the bot.") } } - } - catch (err) { - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runIndicatorBot -> err = " + err.message); - } - } + if (processConfig.startMode.live !== undefined) { - function runTradingBot(pBotConfig, pProcessConfig) { + if (processConfig.startMode.live.run === "true") { - try { + botConfig.startMode = "Live"; + console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode); - if (FULL_LOG === true) { console.log(logDisplace + "[INFO] start -> findProcess -> runTradingBot -> Entering function."); } - - if (pBotConfig.genes !== undefined) { - - /* Here, based on the gene we will create one instance for each combination of genes */ - - let valueMatrix = []; - - for (let i = 0; i < pBotConfig.genes.length; i++) { - - let gene = pBotConfig.genes[i]; - - let possibleValues = []; - - for (let j = gene.lowerLimit; j <= gene.upperLimit; j++) { - - possibleValues.push(j); + let month = pad((new Date()).getUTCMonth() + 1, 2); + let year = (new Date()).getUTCFullYear(); + if (processConfig.startMode.live.resumeExecution === "true") { + botConfig.hasTheBotJustStarted = false; + } else { + botConfig.hasTheBotJustStarted = true; } - valueMatrix.push(possibleValues); - - } - - /* - Now we have all the possible genes values in a multi-dimensional matrix. - We will go thorugh each of the elements of each dimension and get each combination possible with the other dimmensions. - */ - - let combinations = []; - let combination = []; - let dimensionIndex = 0; - - calculateCombinations(dimensionIndex, combination); - - function calculateCombinations(pDimensionIndex, pCombination) { - - let dimension = valueMatrix[pDimensionIndex]; - - for (let j = 0; j < dimension.length; j++) { - - let copy = JSON.parse(JSON.stringify(pCombination)); - - let value = dimension[j]; - copy.push(value); - - if (pDimensionIndex < valueMatrix.length - 1) { - - calculateCombinations(pDimensionIndex + 1, copy); - - } else { - - combinations.push(copy); - + switch (botConfig.type) { + case 'Trading': { + runTradingBot(botConfig, processConfig); + break; + } + default: { + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type); } } } + } - /* At this point we have an array with all the possible combinations, we just need to create an instance for each one and set the genes according to that. */ + if (processConfig.startMode.backtest !== undefined) { - for (let i = 0; i < combinations.length; i++) { + if (processConfig.startMode.backtest.run === "true") { - let botConfig = JSON.parse(JSON.stringify(pBotConfig)); - let combination = combinations[i]; - let genes = {}; - let clonKey = ""; + botConfig.startMode = "Backtest"; + console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode); - for (let j = 0; j < botConfig.genes.length; j++) { + botConfig.backtest = processConfig.startMode.backtest; - genes[botConfig.genes[j].name] = combination[j]; - clonKey = clonKey + "." + combination[j]; + /* We override these waitTimes to the one specified at the backtest configuration. */ - } + processConfig.normalWaitTime = processConfig.startMode.backtest.waitTime; + processConfig.retryWaitTime = processConfig.startMode.backtest.waitTime; - let clonName = botConfig.codeName + "-" + "Clon" + clonKey; - clonName += ".1.0"; + /* Backtest Mode does not support Resume Execution, so this is the only way. */ - if (global.CURRENT_EXECUTION_AT === "Node") { - clonName += "-" + process.env.CLONE_ID; - } - - botConfig.filePathRoot = botConfig.devTeam + "/" + clonName + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion; - - botConfig.instance = clonName; - botConfig.instanceIndex = i; - - setTimeout(execute, i * Math.random() * 10 * 1000); - - function execute() { - - createBotInstance(genes, combinations.length, botConfig); + botConfig.hasTheBotJustStarted = true; + switch (botConfig.type) { + case 'Trading': { + runTradingBot(botConfig, processConfig); + break; + } + default: { + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type); + } } } + } + + if (processConfig.startMode.competition !== undefined) { + + if (processConfig.startMode.competition.run === "true") { + + botConfig.startMode = "Competition"; + console.log(logDisplace + "Root : [INFO] start -> findProcess -> Process found at the bot configuration file. -> Start Mode = " + botConfig.startMode); + + botConfig.competition = processConfig.startMode.competition; + + if (processConfig.startMode.competition.resumeExecution === "false") { + botConfig.hasTheBotJustStarted = true; + } else { + botConfig.hasTheBotJustStarted = false; + } + + switch (botConfig.type) { + case 'Trading': { + runTradingBot(botConfig, processConfig); + break; + } + default: { + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected bot type. -> botConfig.type = " + botConfig.type); + } + } + } + } + + } catch (err) { + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Unexpected exception. -> err.message = " + err.message); + } + } + } + + if (processFound === false) { + + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> Process listed at the configuration file of CloneExecutor not found at the configuration file of the bot."); + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> cloneToExecute.process = " + cloneToExecute.process); + + } + + function runExtractionBot(pBotConfig, pProcessConfig, pMonth, pYear) { + + try { + + const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog'); + let logger; + + logger = DEBUG_MODULE.newDebugLog(); + logger.bot = pBotConfig; + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runExtractionBot -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runExtractionBot -> pMonth = " + pMonth); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runExtractionBot -> pYear = " + pYear); } + + let extractionBotMainLoop = EXTRACTION_BOT_MAIN_LOOP_MODULE.newExtractionBotProcessMainLoop(pBotConfig, logger); + extractionBotMainLoop.initialize(UI_COMMANDS, pProcessConfig, onInitializeReady); + + function onInitializeReady(err) { + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + extractionBotMainLoop.run(pMonth, pYear, whenRunFinishes); + + function whenRunFinishes(err) { + + pBotConfig.loopCounter = 0; + + let botId; + if (pYear !== undefined) { + botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.process + "." + pYear + "." + pMonth; + } else { + botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.process; + } + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); + logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); + + console.log(logDisplace + "Root : [INFO] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> botId = " + botId); + console.log(logDisplace + "Root : [INFO] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); + + logger.persist(); + + } else { + + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. "); + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bye."); + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); + + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> botId = " + botId); + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bot execution was aborted."); + logger.persist(); + } + } + } else { + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> Bot will not be started. "); + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runExtractionBot -> onInitializeReady -> err = " + err.message); - /* If the bot does not have any genes at all */ + logger.persist(); + } + } + } + catch (err) { + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runExtractionBot -> err = " + err.message); + } + } + function runIndicatorBot(pBotConfig, pProcessConfig, pMonth, pYear) { + + try { + const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog'); + let logger; + + logger = DEBUG_MODULE.newDebugLog(); + logger.bot = pBotConfig; + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> pMonth = " + pMonth); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> pYear = " + pYear); } + + let indicatorBotMainLoop = INDICATOR_BOT_MAIN_LOOP_MODULE.newIndicatorBotProcessMainLoop(pBotConfig, logger); + indicatorBotMainLoop.initialize(UI_COMMANDS, pProcessConfig, onInitializeReady); + + function onInitializeReady(err) { + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + indicatorBotMainLoop.run(pMonth, pYear, whenRunFinishes); + + function whenRunFinishes(err) { + + pBotConfig.loopCounter = 0; + + let botId; + if (pYear !== undefined) { + botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.process + "." + pYear + "." + pMonth; + } else { + botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.process; + } + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); + logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); + + console.log(logDisplace + "Root : [INFO] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> botId = " + botId); + console.log(logDisplace + "Root : [INFO] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); + + logger.persist(); + + } else { + + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. "); + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bye."); + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished with errors. Please check the logs."); + logger.persist(); + } + } + + } else { + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> Failed to initialize the bot. "); + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runIndicatorBot -> onInitializeReady -> err = " + err.message); + logger.persist(); + throw new Error("Root -> start -> findProcess -> runIndicatorBot -> onInitializeReady -> Failed to initialize the bot.") + } + } + } + catch (err) { + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runIndicatorBot -> err = " + err.message); + + } + } + + function runTradingBot(pBotConfig, pProcessConfig) { + + try { + + if (FULL_LOG === true) { console.log(logDisplace + "[INFO] start -> findProcess -> runTradingBot -> Entering function."); } + + if (pBotConfig.genes !== undefined) { + + /* Here, based on the gene we will create one instance for each combination of genes */ + + let valueMatrix = []; + + for (let i = 0; i < pBotConfig.genes.length; i++) { + + let gene = pBotConfig.genes[i]; + + let possibleValues = []; + + for (let j = gene.lowerLimit; j <= gene.upperLimit; j++) { + + possibleValues.push(j); + + } + + valueMatrix.push(possibleValues); + + } + + /* + Now we have all the possible genes values in a multi-dimensional matrix. + We will go thorugh each of the elements of each dimension and get each combination possible with the other dimmensions. + */ + + let combinations = []; + let combination = []; + let dimensionIndex = 0; + + calculateCombinations(dimensionIndex, combination); + + function calculateCombinations(pDimensionIndex, pCombination) { + + let dimension = valueMatrix[pDimensionIndex]; + + for (let j = 0; j < dimension.length; j++) { + + let copy = JSON.parse(JSON.stringify(pCombination)); + + let value = dimension[j]; + copy.push(value); + + if (pDimensionIndex < valueMatrix.length - 1) { + + calculateCombinations(pDimensionIndex + 1, copy); + + } else { + + combinations.push(copy); + + } + } + } + + /* At this point we have an array with all the possible combinations, we just need to create an instance for each one and set the genes according to that. */ + + for (let i = 0; i < combinations.length; i++) { + + let botConfig = JSON.parse(JSON.stringify(pBotConfig)); + let combination = combinations[i]; let genes = {}; - let clonName = botConfig.codeName; + let clonKey = ""; + + for (let j = 0; j < botConfig.genes.length; j++) { + + genes[botConfig.genes[j].name] = combination[j]; + clonKey = clonKey + "." + combination[j]; + + } + + let clonName = botConfig.codeName + "-" + "Clon" + clonKey; + clonName += ".1.0"; if (global.CURRENT_EXECUTION_AT === "Node") { clonName += "-" + process.env.CLONE_ID; } - clonName += ".1.0"; - botConfig.filePathRoot = botConfig.devTeam + "/" + clonName + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion; - pBotConfig.instance = clonName; - pBotConfig.instanceIndex = 0; + botConfig.instance = clonName; + botConfig.instanceIndex = i; - createBotInstance(genes, 1, pBotConfig); + setTimeout(execute, i * Math.random() * 10 * 1000); + function execute() { + + createBotInstance(genes, combinations.length, botConfig); + + } + } + } else { + + /* If the bot does not have any genes at all */ + + let genes = {}; + let clonName = botConfig.codeName; + + if (global.CURRENT_EXECUTION_AT === "Node") { + clonName += "-" + process.env.CLONE_ID; } + clonName += ".1.0"; - function createBotInstance(pGenes, pTotalInstances, pBotConfig) { + botConfig.filePathRoot = botConfig.devTeam + "/" + clonName + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + botConfig.dataSetVersion; - const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog'); - let logger; + pBotConfig.instance = clonName; + pBotConfig.instanceIndex = 0; - logger = DEBUG_MODULE.newDebugLog(); - logger.bot = pBotConfig; - pBotConfig.timePeriodFileStorage = global.EXECUTION_CONFIG.timePeriodFileStorage - pBotConfig.dataSet = global.EXECUTION_CONFIG.dataSet + createBotInstance(genes, 1, pBotConfig); - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runTradingBot -> createBotInstance -> Entering function."); } + } - let tradingBotMainLoop = TRADING_BOT_MAIN_LOOP_MODULE.newTradingBotProcessMainLoop(pBotConfig, logger); - tradingBotMainLoop.initialize(UI_COMMANDS, pProcessConfig, onInitializeReady); - function onInitializeReady(err) { + function createBotInstance(pGenes, pTotalInstances, pBotConfig) { - if (err.result === global.DEFAULT_OK_RESPONSE.result) { + const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog'); + let logger; - tradingBotMainLoop.run(pGenes, pTotalInstances, whenRunFinishes); + logger = DEBUG_MODULE.newDebugLog(); + logger.bot = pBotConfig; + pBotConfig.timePeriodFileStorage = global.EXECUTION_CONFIG.timePeriodFileStorage + pBotConfig.dataSet = global.EXECUTION_CONFIG.dataSet - function whenRunFinishes(err) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runTradingBot -> createBotInstance -> Entering function."); } - pBotConfig.loopCounter = 0; + let tradingBotMainLoop = TRADING_BOT_MAIN_LOOP_MODULE.newTradingBotProcessMainLoop(pBotConfig, logger); + tradingBotMainLoop.initialize(UI_COMMANDS, pProcessConfig, onInitializeReady); - let botId; + function onInitializeReady(err) { - botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.instance + "." + pBotConfig.process; + if (err.result === global.DEFAULT_OK_RESPONSE.result) { - if (err.result === global.DEFAULT_OK_RESPONSE.result) { + tradingBotMainLoop.run(pGenes, pTotalInstances, whenRunFinishes); - logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); - logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); + function whenRunFinishes(err) { - console.log(logDisplace + "Root : [INFO] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> botId = " + botId); - console.log(logDisplace + "Root : [INFO] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); - logger.persist(); + pBotConfig.loopCounter = 0; - } else { + let botId; - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. "); - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bye."); - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot execution finished with errors. Please check the logs."); - logger.persist(); - } + botId = pBotConfig.devTeam + "." + pBotConfig.codeName + "." + pBotConfig.instance + "." + pBotConfig.process; + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); + logger.write(MODULE_NAME, "[INFO] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); + + console.log(logDisplace + "Root : [INFO] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> botId = " + botId); + console.log(logDisplace + "Root : [INFO] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); + logger.persist(); + + } else { + + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. "); + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bye."); + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> whenStartFinishes -> Bot execution finished with errors. Please check the logs."); + logger.persist(); } - - } else { - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> Bot will not be started. "); - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> err = " + err.message); - - logger.persist(); } + + } else { + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> Bot will not be started. "); + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runTradingBot -> createBotInstance -> onInitializeReady -> err = " + err.message); + + logger.persist(); } } } - catch (err) { - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runTradingBot -> err = " + err.message); - } } + catch (err) { + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> runTradingBot -> err = " + err.message); + } + } - } - catch (err) { - console.log(logDisplace + "Root : [ERROR] start -> findProcess -> err.message = " + err.message); - return; - } + } + catch (err) { + console.log(logDisplace + "Root : [ERROR] start -> findProcess -> err.message = " + err.message); + return; } } + } } diff --git a/Run.js b/Run.js index 926474a32..980e7dd72 100644 --- a/Run.js +++ b/Run.js @@ -112,16 +112,16 @@ function readExecutionConfiguration() { startMode[process.env.START_MODE].run = "true" - let executionList = [{ + let cloneToExecute = { enabled: "true", devTeam: process.env.DEV_TEAM, bot: process.env.BOT, process: process.env.PROCESS, repo: global.CURRENT_BOT_REPO - }] + } global.EXECUTION_CONFIG = { - executionList: executionList, + cloneToExecute: cloneToExecute, startMode: startMode, timePeriod: getTimePeriod(process.env.TIME_PERIOD), timePeriodFileStorage: process.env.TIME_PERIOD, diff --git a/this.config.json b/this.config.json index 9f33a2962..46ab69018 100644 --- a/this.config.json +++ b/this.config.json @@ -5,57 +5,6 @@ "minor": 1, "patch": 0 }, - "executionList": [ - { - "enabled": "false", - "devTeam": "AAMasters", - "bot": "AAMariam", - "process": "Trading-Process", - "repo": "AAMariam-Trading-Bot" - }, - { - "enabled": "false", - "devTeam": "AAMasters", - "bot": "AACharly", - "process": "Poloniex-Live-Trades", - "repo": "AACharly-Extraction-Bot" - }, - { - "enabled": "false", - "devTeam": "AAMasters", - "bot": "AACharly", - "process": "Poloniex-Hole-Fixing", - "repo": "AACharly-Extraction-Bot" - }, - { - "enabled": "false", - "devTeam": "AAMasters", - "bot": "AABruce", - "process": "One-Min-Daily-Candles-Volumes", - "repo": "AABruce-Indicator-Bot" - }, - { - "enabled": "false", - "devTeam": "AAMasters", - "bot": "AAOlivia", - "process": "Multi-Period-Daily", - "repo": "AAOlivia-Indicator-Bot" - }, - { - "enabled": "false", - "devTeam": "AAMasters", - "bot": "AAOlivia", - "process": "Multi-Period-Market", - "repo": "AAOlivia-Indicator-Bot" - }, - { - "enabled": "true", - "devTeam": "AAMasters", - "bot": "AAChris", - "process": "Multi-Period-Market", - "repo": "AAOlivia-Indicator-Bot" - } - ], "stopGracefully": false, "marketRateProvider": { "devTeam": "AAMasters", From dc7aae78672cb5e5317cb20cd0624e682e120d40 Mon Sep 17 00:00:00 2001 From: Matias Date: Mon, 25 Mar 2019 17:02:48 +0100 Subject: [PATCH 73/76] Adding Begin Time to indicator --- Run.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Run.js b/Run.js index 980e7dd72..d47d89476 100644 --- a/Run.js +++ b/Run.js @@ -16,13 +16,13 @@ global.MARKET = { process.on('uncaughtException', function (err) { console.log('[INFO] Run -> uncaughtException -> err.message = ' + err.message); console.log('[INFO] Run -> uncaughtException -> err.stack = ', err.stack); - return; + throw new Error() }); process.on('unhandledRejection', (reason, p) => { console.log('[INFO] Run -> unhandledRejection -> reason = ' + reason); console.log('[INFO] Run -> unhandledRejection -> p = ' + JSON.stringify(p)); - return; + throw new Error() }); process.on('exit', function (code) { @@ -92,7 +92,8 @@ function readExecutionConfiguration() { month: process.env.MONTH } let noTime = { - run: "false" + run: "false", + beginDatetime: process.env.BEGIN_DATE_TIME } let fixedInterval = { run: "false", From 676d0d34e5378ec6f1cd4478c17f961d01120ef1 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 25 Mar 2019 17:46:10 +0100 Subject: [PATCH 74/76] Begint Time arriving to MultiPeriodDaily market --- MultiPeriodDaily.js | 1 - Root.js | 5 +++++ Run.js | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js index 508590812..562cd2f3f 100644 --- a/MultiPeriodDaily.js +++ b/MultiPeriodDaily.js @@ -247,7 +247,6 @@ */ contextVariables.lastFile = new Date(contextVariables.dateBeginOfMarket.getUTCFullYear() + "-" + (contextVariables.dateBeginOfMarket.getUTCMonth() + 1) + "-" + contextVariables.dateBeginOfMarket.getUTCDate() + " " + "00:00" + GMT_SECONDS); - //contextVariables.lastFile = new Date(contextVariables.lastFile.valueOf() + ONE_DAY_IN_MILISECONDS); if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> thisReport.lastFile === undefined"); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> contextVariables.lastFile = " + contextVariables.lastFile); } diff --git a/Root.js b/Root.js index 710a8ee01..0b125f7c0 100644 --- a/Root.js +++ b/Root.js @@ -287,6 +287,11 @@ if(global.EXECUTION_CONFIG.timePeriod){ processConfig.timePeriod = global.EXECUTION_CONFIG.timePeriod } + + if (processConfig.framework.name === "Multi-Period-Daily") { + processConfig.framework.startDate.fixedDate = processConfig.startMode.noTime.beginDatetime; + processConfig.framework.startDate.resumeExecution = processConfig.startMode.noTime.resumeExecution; + } try { diff --git a/Run.js b/Run.js index d47d89476..97f972dfe 100644 --- a/Run.js +++ b/Run.js @@ -93,7 +93,8 @@ function readExecutionConfiguration() { } let noTime = { run: "false", - beginDatetime: process.env.BEGIN_DATE_TIME + beginDatetime: process.env.BEGIN_DATE_TIME, + resumeExecution: process.env.RESUME_EXECUTION } let fixedInterval = { run: "false", From 2e82e7e22821ded3317395e81d2dd39a7c47e37b Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 25 Mar 2019 18:11:29 +0100 Subject: [PATCH 75/76] Supports Begin Date and Resume Execution on Multi Period Daily Framework --- MultiPeriodDaily.js | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js index 562cd2f3f..5d54bc0b6 100644 --- a/MultiPeriodDaily.js +++ b/MultiPeriodDaily.js @@ -233,8 +233,13 @@ if (thisReport.lastFile !== undefined) { - contextVariables.lastFile = new Date(thisReport.lastFile); + if (bot.hasTheBotJustStarted === true && processConfig.framework.startDate.resumeExecution === "false") { + + startFromBegining(); + return; + } + contextVariables.lastFile = new Date(thisReport.lastFile); interExecutionMemoryArray = thisReport.interExecutionMemoryArray; processTimePeriods(); @@ -246,10 +251,16 @@ In the case when there is no status report, we assume like the last processed file is the one on the date of Begining of Market. */ + startFromBegining(); + return; + } + + function startFromBegining() { + contextVariables.lastFile = new Date(contextVariables.dateBeginOfMarket.getUTCFullYear() + "-" + (contextVariables.dateBeginOfMarket.getUTCMonth() + 1) + "-" + contextVariables.dateBeginOfMarket.getUTCDate() + " " + "00:00" + GMT_SECONDS); - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> thisReport.lastFile === undefined"); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> contextVariables.lastFile = " + contextVariables.lastFile); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> startFromBegining -> thisReport.lastFile === undefined"); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> startFromBegining -> contextVariables.lastFile = " + contextVariables.lastFile); } /* The first time the process is running is the right time to create the data structure that is going to be shared across different executions. @@ -258,14 +269,13 @@ interExecutionMemoryArray = []; - for (let i = 0; i < global.dailyFilePeriods.length; i++) - { + for (let i = 0; i < global.dailyFilePeriods.length; i++) { let emptyObject = {}; interExecutionMemoryArray.push(emptyObject); } processTimePeriods(); - return; + } } catch (err) { @@ -734,6 +744,7 @@ thisReport.file.interExecutionMemoryArray = interExecutionMemoryArray; thisReport.save(callBack); + bot.hasTheBotJustStarted = false; } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.message); From ada66e41c837d6335d4a0cf6aa7879320056d9e5 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 26 Mar 2019 13:35:20 +0100 Subject: [PATCH 76/76] BUG corrected. Framework is not required on every bot --- Root.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Root.js b/Root.js index 0b125f7c0..158a8ac82 100644 --- a/Root.js +++ b/Root.js @@ -288,11 +288,13 @@ processConfig.timePeriod = global.EXECUTION_CONFIG.timePeriod } - if (processConfig.framework.name === "Multi-Period-Daily") { - processConfig.framework.startDate.fixedDate = processConfig.startMode.noTime.beginDatetime; - processConfig.framework.startDate.resumeExecution = processConfig.startMode.noTime.resumeExecution; + if (processConfig.framework !== undefined) { + if (processConfig.framework.name === "Multi-Period-Daily") { + processConfig.framework.startDate.fixedDate = processConfig.startMode.noTime.beginDatetime; + processConfig.framework.startDate.resumeExecution = processConfig.startMode.noTime.resumeExecution; + } } - + try { /* We test each type of start Mode to get what to run and how. */