diff --git a/Commons.js b/Commons.js index 5ad2fb509..8bf6a01da 100644 --- a/Commons.js +++ b/Commons.js @@ -469,14 +469,14 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFile -> Entering function."); } let market = bot.market; - let fileName = '' + market.baseAsset + '_' + market.quotedAsset + '.json'; + let fileName = 'Data.json'; let dateForPath = '' if (processingDailyFiles === true) { dateForPath = "/" + currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); } - let filePathRoot = contextSummary.dataMine + "/" + contextSummary.bot + "/" + bot.exchange; + let filePathRoot = bot.exchange + "/" + bot.market.baseAsset + "-" + bot.market.quotedAsset + "/" + contextSummary.dataMine + "/" + contextSummary.bot; let filePath = filePathRoot + "/Output/" + contextSummary.product + "/" + contextSummary.dataset + "/" + timeFrameLabel + dateForPath; filePath += '/' + fileName diff --git a/DataSet.js b/DataSet.js index 4ecbbb6b3..ee04b4a21 100644 --- a/DataSet.js +++ b/DataSet.js @@ -104,7 +104,7 @@ exports.newDataSet = function newDataSet(BOT, logger) { if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getTextFile -> Entering function."); } - let filePathRoot = dataDependencyNode.dataMine + "/" + dataDependencyNode.bot + "/" + bot.exchange; + let filePathRoot = bot.exchange + "/" + bot.market.baseAsset + "-" + bot.market.quotedAsset + "/" + dataDependencyNode.dataMine + "/" + dataDependencyNode.bot; let filePath = filePathRoot + "/Output/" + pFolderPath; filePath += '/' + pFileName @@ -146,7 +146,7 @@ exports.newDataSet = function newDataSet(BOT, logger) { return; } - let filePathRoot = dataDependencyNode.dataMine + "/" + dataDependencyNode.bot + "/" + bot.exchange; + let filePathRoot = bot.exchange + "/" + bot.market.baseAsset + "-" + bot.market.quotedAsset + "/" + dataDependencyNode.dataMine + "/" + dataDependencyNode.bot; let filePath = filePathRoot + "/Output/" + pFolderPath + '/' + pFileName; fileStorage.createTextFile(filePath, pFileContent, onFileCreated); diff --git a/DebugLog.js b/DebugLog.js index ba2c83788..123a45006 100644 --- a/DebugLog.js +++ b/DebugLog.js @@ -37,18 +37,25 @@ exports.newDebugLog = function newDebugLog() { } } - function newInternalLoop(pBot, pProcess, date) { + function newInternalLoop(pBot, pProcess, date, percentage) { + if (percentage === undefined) { + percentage = "" + } else { + percentage = percentage.toFixed(2) + " %" + } if (date === undefined) { date = thisObject.bot.processDatetime } + date = date.getUTCFullYear() + '-' + strPad(date.getUTCMonth() + 1, 2, "0") + '-' + strPad(date.getUTCDate(), 2, "0"); - console.log(new Date().toISOString() + " " + strPad(pBot, 20) + " " + strPad(pProcess, 30) + " " + strPad(thisObject.bot.exchange, 20) + " " + strPad(thisObject.bot.market.baseAsset + '/' + thisObject.bot.market.quotedAsset, 10) - + " Entered into Internal Loop # " + strPad(internalLoopCounter + 1, 8) + " " + strPad(date.toISOString(), 30)) + console.log(new Date().toISOString() + " " + strPad(thisObject.bot.exchange, 20) + " " + strPad(thisObject.bot.market.baseAsset + '/' + thisObject.bot.market.quotedAsset, 10) + " " + strPad(pBot, 20) + " " + strPad(pProcess, 30) + + " Internal Loop # " + strPad(internalLoopCounter + 1, 8) + " " + strPad(date, 30) + " " + strPad(percentage, 10)) persist(); - function strPad(str, max) { + function strPad(str, max, fill) { + if (fill === undefined) {fill = " "} str = str.toString(); - return str.length < max ? strPad(" " + str, max) : str; + return str.length < max ? strPad(fill + str, max) : str; } } diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 356128e9b..000000000 --- a/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM node:8.16-alpine - -RUN mkdir -p /usr/src/app -WORKDIR /usr/src/app - -COPY package.json ./ -RUN npm install - -COPY . . diff --git a/FileStorage.js b/FileStorage.js index 8bca500eb..2ec8a47ec 100644 --- a/FileStorage.js +++ b/FileStorage.js @@ -5,9 +5,11 @@ exports.newFileStorage = function newFileStorage(logger) { const MODULE_NAME = 'FileStorage' const MAX_RETRY = 30 - const RETRY_TIME_IN_MILISECONDS = 250 + const FAST_RETRY_TIME_IN_MILISECONDS = 500 + const SLOW_RETRY_TIME_IN_MILISECONDS = 5000 let currentRetryGetTextFile = 0 let currentRetryWriteTextFile = 0 + let currentRetryDeleteTextFile = 0 if (logger === undefined) { // Dummy logger logger = {} @@ -48,7 +50,10 @@ exports.newFileStorage = function newFileStorage(logger) { fs.readFile(fileLocation, onFileRead) function onFileRead(err, text) { - + let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS + if (currentRetryGetTextFile > MAX_RETRY - 2) { + retryTimeToUse = SLOW_RETRY_TIME_IN_MILISECONDS + } if (err) { if (err.code === 'ENOENT') { // since files are deleted before being replaced, it can happen that it does not exist and after a retry it does. @@ -63,7 +68,7 @@ exports.newFileStorage = function newFileStorage(logger) { } else { fileDoesNotExist = true logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> File does not exist. Retrying. ') - setTimeout(retry, RETRY_TIME_IN_MILISECONDS) + setTimeout(retry, retryTimeToUse) return } } @@ -71,13 +76,13 @@ exports.newFileStorage = function newFileStorage(logger) { logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> err = ' + err.stack) logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> filePath = ' + filePath) logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> err = ' + err.stack) - setTimeout(retry, RETRY_TIME_IN_MILISECONDS) + setTimeout(retry, retryTimeToUse) return } if (text.toString() === "") { logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Read and Empty File -> filePath = ' + filePath) - setTimeout(retry, RETRY_TIME_IN_MILISECONDS) + setTimeout(retry, retryTimeToUse) return } @@ -91,6 +96,7 @@ exports.newFileStorage = function newFileStorage(logger) { } function retry() { + //console.log(new Date(), ' Retry #: ' + currentRetryGetTextFile, fileLocation ) if (currentRetryGetTextFile < MAX_RETRY) { currentRetryGetTextFile++ logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> retry -> Will try to read the file again -> Retry #: ' + currentRetryGetTextFile) @@ -144,10 +150,14 @@ exports.newFileStorage = function newFileStorage(logger) { fs.writeFile(fileLocation + '.tmp', fileContent, onFileWritenn) function onFileWritenn(err) { + let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS + if (currentRetryWriteTextFile > MAX_RETRY - 2) { + retryTimeToUse = SLOW_RETRY_TIME_IN_MILISECONDS + } if (err) { logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> Error writing file -> file = ' + fileLocation) logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> Error writing file -> err = ' + err.stack) - setTimeout(retry, RETRY_TIME_IN_MILISECONDS) + setTimeout(retry, retryTimeToUse) } else { const fs = require('fs') @@ -161,7 +171,7 @@ exports.newFileStorage = function newFileStorage(logger) { if (code !== '' && code !== 'ENOENT') { logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error renaming file -> file = ' + fileLocation) logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error renaming file -> err = ' + err.stack) - setTimeout(retry, RETRY_TIME_IN_MILISECONDS) + setTimeout(retry, retryTimeToUse) } else { const fs = require('fs') @@ -171,7 +181,7 @@ exports.newFileStorage = function newFileStorage(logger) { if (err) { logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onRenamed -> Error renaming file -> file = ' + fileLocation + '.tmp') logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onRenamed -> Error renaming file -> err = ' + err.stack) - setTimeout(retry, RETRY_TIME_IN_MILISECONDS) + setTimeout(retry, retryTimeToUse) } else { callBackFunction(global.DEFAULT_OK_RESPONSE) @@ -242,14 +252,14 @@ exports.newFileStorage = function newFileStorage(logger) { } function retry() { - if (currentRetryWriteTextFile < MAX_RETRY) { - currentRetryWriteTextFile++ - logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> retry -> Will try to write the file again -> Retry #: ' + currentRetryWriteTextFile) + if (currentRetryDeleteTextFile < MAX_RETRY) { + currentRetryDeleteTextFile++ + logger.write(MODULE_NAME, '[WARN] FileStorage -> deleteTextFile -> retry -> Will try to delete the file again -> Retry #: ' + currentRetryDeleteTextFile) createTextFile(filePath, fileContent, callBackFunction) } else { - currentRetryWriteTextFile = 0 - logger.write(MODULE_NAME, '[ERROR] FileStorage -> createTextFile -> retry -> Max retries reached writting a file. Giving up.') - logger.write(MODULE_NAME, '[ERROR] FileStorage -> createTextFile -> retry -> file = ' + fileLocation) + currentRetryDeleteTextFile = 0 + logger.write(MODULE_NAME, '[ERROR] FileStorage -> deleteTextFile -> retry -> Max retries reached deleting a file. Giving up.') + logger.write(MODULE_NAME, '[ERROR] FileStorage -> deleteTextFile -> retry -> file = ' + fileLocation) callBackFunction(global.DEFAULT_FAIL_RESPONSE) } } diff --git a/IndicatorBotProcessMainLoop.js b/IndicatorBotProcessMainLoop.js index aa2cd6ac2..a99c9e97b 100644 --- a/IndicatorBotProcessMainLoop.js +++ b/IndicatorBotProcessMainLoop.js @@ -145,12 +145,11 @@ /* High level log entry */ - console.log(new Date().toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(bot.exchange, 20) + " " + pad(bot.market.baseAsset + '/' + bot.market.quotedAsset, 10) - + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8)); + console.log(new Date().toISOString() + " " + pad(bot.exchange, 20) + " " + pad(bot.market.baseAsset + '/' + bot.market.quotedAsset, 10) + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + + " 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 processOutput let processExecutionEvents let userBot; let processFramework; @@ -315,7 +314,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeStatusDependencies -> Entering function."); } - statusDependencies = STATUS_DEPENDENCIES.newStatusDependencies(bot, logger, STATUS_REPORT, UTILITIES); + statusDependencies = STATUS_DEPENDENCIES.newStatusDependencies(bot, logger, STATUS_REPORT, UTILITIES, PROCESS_OUTPUT); statusDependencies.initialize(onInizialized); @@ -494,7 +493,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeUserBot -> Entering function."); } - usertBot = USER_BOT_MODULE.newUserBot(bot, logger, COMMONS_MODULE, UTILITIES, fileStorage); + usertBot = USER_BOT_MODULE.newUserBot(bot, logger, COMMONS_MODULE, UTILITIES, FILE_STORAGE); usertBot.initialize(statusDependencies, onInizialized); @@ -595,7 +594,7 @@ switch (err.result) { case global.DEFAULT_OK_RESPONSE.result: { logger.write(MODULE_NAME, "[INFO] run -> loop -> startUserBot -> onFinished -> Execution finished well."); - raiseEventsProcessOutput() + finishProcessExecutionEvents() return; } case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time. @@ -785,7 +784,7 @@ switch (err.result) { case global.DEFAULT_OK_RESPONSE.result: { logger.write(MODULE_NAME, "[INFO] run -> loop -> startProcessFramework -> onFinished -> Execution finished well."); - raiseEventsProcessOutput() + finishProcessExecutionEvents() return; } case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time. @@ -868,81 +867,6 @@ } } - function raiseEventsProcessOutput() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> raiseEventsProcessOutput -> Entering function."); } - - processOutput = PROCESS_OUTPUT.newProcessOutput(bot, logger) - - processOutput.raiseEvents(statusDependencies, onFinished); - - function onFinished(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> raiseEventsProcessOutput -> onFinished -> Entering function."); } - - switch (err.result) { - case global.DEFAULT_OK_RESPONSE.result: { - logger.write(MODULE_NAME, "[INFO] run -> loop -> raiseEventsProcessOutput -> onFinished -> Execution finished well."); - finishProcessExecutionEvents() - 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, "[WARN] run -> loop -> raiseEventsProcessOutput -> 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. - processStopped() - logger.write(MODULE_NAME, "[ERROR] run -> loop -> raiseEventsProcessOutput -> onFinished -> 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 -> raiseEventsProcessOutput -> onFinished -> Unhandled err.result received. -> err.result = " + err.result); - logger.write(MODULE_NAME, "[ERROR] run -> loop -> raiseEventsProcessOutput -> onFinished -> Unhandled err.result received. -> err = " + 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 -> raiseEventsProcessOutput -> onFinished -> err = " + err.stack); - logger.persist(); - clearInterval(fixedTimeLoopIntervalHandle); - clearTimeout(nextLoopTimeoutHandle); - clearTimeout(checkLoopHealthHandle); - bot.enableCheckLoopHealth = false; - callBackFunction(err); - } - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> raiseEventsProcessOutput -> err = " + err.stack); - logger.persist(); - clearInterval(fixedTimeLoopIntervalHandle); - clearTimeout(nextLoopTimeoutHandle); - clearTimeout(checkLoopHealthHandle); - bot.enableCheckLoopHealth = false; - callBackFunction(err); - } - } - function finishProcessExecutionEvents() { try { @@ -1040,6 +964,7 @@ logger.persist(); } + processStopped() callBackFunction(global.DEFAULT_OK_RESPONSE); return; @@ -1058,6 +983,7 @@ checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.deadWaitTime, bot.loopCounter); } nextLoopTimeoutHandle = setTimeout(loop, processConfig.normalWaitTime); + processHeartBeat(undefined, undefined, "Waiting " + processConfig.normalWaitTime / 1000 + " seconds for next execution.") if(global.WRITE_LOGS_TO_FILES === 'true'){ logger.persist(); } @@ -1069,18 +995,21 @@ checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.deadWaitTime, bot.loopCounter); } nextLoopTimeoutHandle = setTimeout(loop, processConfig.retryWaitTime); + processHeartBeat(undefined, undefined, "Trying to recover from some problem. Waiting " + processConfig.retryWaitTime / 1000 + " seconds for next execution.") logger.persist(); } break; case 'Sleep': { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.sleepWaitTime / 60000) + " minutes."); } nextLoopTimeoutHandle = setTimeout(loop, processConfig.sleepWaitTime); + processHeartBeat(undefined, undefined, "Waiting " + processConfig.sleepWaitTime / 60000 + " minutes for next execution.") logger.persist(); } break; case 'Coma': { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.comaWaitTime / 3600000) + " hours."); } nextLoopTimeoutHandle = setTimeout(loop, processConfig.comaWaitTime); + processHeartBeat(undefined, undefined, "Waiting " + processConfig.comaWaitTime / 3600000 + " hours for next execution.") logger.persist(); } break; @@ -1152,10 +1081,12 @@ } } - function processHeartBeat(processingDate) { + function processHeartBeat(processingDate, percentage, status) { let event = { seconds: (new Date()).getSeconds(), - processingDate: processingDate + processingDate: processingDate, + percentage: percentage, + status: status } global.SYSTEM_EVENT_HANDLER.raiseEvent(bot.processKey, 'Heartbeat', event) } diff --git a/MultiPeriod.js b/MultiPeriod.js index 6364f346a..d9047fb3f 100644 --- a/MultiPeriod.js +++ b/MultiPeriod.js @@ -312,7 +312,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimeFramesMarketFiles -> periodsLoopBody -> dependencyLoopBody -> getFile -> Entering function."); } - let fileName = market.baseAsset + '_' + market.quotedAsset + ".json"; + let fileName = "Data.json"; if (dependency.dataSet !== "Multi-Period-Market") { @@ -452,11 +452,7 @@ bot.multiPeriodProcessDatetime = new Date(bot.multiPeriodProcessDatetime.valueOf() + ONE_DAY_IN_MILISECONDS); previousDay = new Date(bot.multiPeriodProcessDatetime.valueOf() - ONE_DAY_IN_MILISECONDS); - - if (global.WRITE_LOGS_TO_FILES === 'true') { - logger.newInternalLoop(bot.codeName, bot.process); - } - + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimeFramesDailyFiles -> advanceTime -> bot.multiPeriodProcessDatetime = " + bot.multiPeriodProcessDatetime); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimeFramesDailyFiles -> advanceTime -> previousDay = " + previousDay); } @@ -636,7 +632,7 @@ } else { filePath = dependency.product + '/' + dependency.dataSet + "/" + dateForPath; } - let fileName = market.baseAsset + '_' + market.quotedAsset + ".json"; + let fileName = "Data.json"; dataset.getTextFile(filePath, fileName, onFileReceived); @@ -712,7 +708,7 @@ } else { filePath = dependency.product + '/' + dependency.dataSet + "/" + dateForPath; } - let fileName = market.baseAsset + '_' + market.quotedAsset + ".json"; + let fileName = "Data.json"; dataset.getTextFile(filePath, fileName, onFileReceived); @@ -990,7 +986,7 @@ let fileContent = JSON.stringify(dataRange); - let fileName = '/Data.Range.' + market.baseAsset + '_' + market.quotedAsset + '.json'; + let fileName = '/Data.Range.json'; let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + productCodeName + "/" + 'Multi-Period-Daily' + fileName; fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); @@ -1009,7 +1005,7 @@ logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Content written = " + fileContent); } - let key = bot.dataMine + "-" + bot.codeName + "-" + productCodeName + "-" + currentOutputPeriodName + let key = bot.dataMine + "-" + bot.codeName + "-" + productCodeName + "-" + bot.exchange + "-" + bot.market.baseAsset + '/' + bot.market.quotedAsset let event = { dateRange: dataRange } @@ -1061,6 +1057,7 @@ thisReport.file.lastExecution = bot.processDatetime; thisReport.save(callBack); + logger.newInternalLoop(bot.codeName, bot.process, bot.multiPeriodProcessDatetime); } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> writeMarketStatusReport -> err = " + err.stack); diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js index 71ad6181a..516737d4c 100644 --- a/MultiPeriodDaily.js +++ b/MultiPeriodDaily.js @@ -307,6 +307,8 @@ let botNeverRan = true; bot.multiPeriodDailyProcessDatetime = 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 fromDate = new Date(bot.multiPeriodDailyProcessDatetime.valueOf()) + let lastDate = new Date() advanceTime(); @@ -318,11 +320,7 @@ bot.multiPeriodDailyProcessDatetime = new Date(bot.multiPeriodDailyProcessDatetime.valueOf() + ONE_DAY_IN_MILISECONDS); previousDay = new Date(bot.multiPeriodDailyProcessDatetime.valueOf() - ONE_DAY_IN_MILISECONDS); - - if (global.WRITE_LOGS_TO_FILES === 'true') { - logger.newInternalLoop(bot.codeName, bot.process); - } - + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimeFrames -> advanceTime -> bot.multiPeriodDailyProcessDatetime = " + bot.multiPeriodDailyProcessDatetime); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimeFrames -> advanceTime -> previousDay = " + previousDay); } @@ -338,7 +336,17 @@ } - periodsLoop(); + /* Telling the world we are alive and doing well */ + let currentDateString = bot.multiPeriodDailyProcessDatetime.getUTCFullYear() + '-' + utilities.pad(bot.multiPeriodDailyProcessDatetime.getUTCMonth() + 1, 2) + '-' + utilities.pad(bot.multiPeriodDailyProcessDatetime.getUTCDate(), 2); + let currentDate = new Date(bot.multiPeriodDailyProcessDatetime) + let percentage = global.getPercentage(fromDate, currentDate, lastDate) + bot.processHeartBeat(currentDateString, percentage) + + if (global.areEqualDates(currentDate, new Date()) === false) { + logger.newInternalLoop(bot.codeName, bot.process, currentDate, percentage); + } + + checkStopTaskGracefully(); } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> advanceTime -> err = "+ err.stack); @@ -346,16 +354,35 @@ } } + function checkStopTaskGracefully() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimeFramesDailyFiles -> checkStopTaskGracefully -> Entering function."); } + + /* Validation that we dont need to stop. */ + + if (global.STOP_TASK_GRACEFULLY === true) { + + callBackFunction(global.DEFAULT_OK_RESPONSE); + return; + + } + + periodsLoop(); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFramesDailyFiles -> checkStopTaskGracefully -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + function periodsLoop() { try { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimeFrames -> periodsLoop -> Entering function."); } - /* Telling the world we are alive and doing well */ - let processingDate = bot.multiPeriodDailyProcessDatetime.getUTCFullYear() + '-' + utilities.pad(bot.multiPeriodDailyProcessDatetime.getUTCMonth() + 1, 2) + '-' + utilities.pad(bot.multiPeriodDailyProcessDatetime.getUTCDate(), 2); - bot.processHeartBeat(processingDate) - /* We will iterate through all posible periods. @@ -432,7 +459,7 @@ } else { filePath = dependency.product + '/' + dependency.dataSet + "/" + dateForPath; } - let fileName = market.baseAsset + '_' + market.quotedAsset + ".json"; + let fileName = "Data.json"; dataset.getTextFile(filePath, fileName, onFileReceived); @@ -502,7 +529,7 @@ } else { filePath = dependency.product + '/' + dependency.dataSet + "/" + dateForPath; } - let fileName = market.baseAsset + '_' + market.quotedAsset + ".json"; + let fileName = "Data.json"; dataset.getTextFile(filePath, fileName, onFileReceived); @@ -736,7 +763,7 @@ let fileContent = JSON.stringify(dataRange); - let fileName = '/Data.Range.' + market.baseAsset + '_' + market.quotedAsset + '.json'; + let fileName = '/Data.Range.json'; let filePath = bot.filePathRoot + "/Output/" + productCodeName + "/" + bot.process + fileName; fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); @@ -755,6 +782,13 @@ logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Content written = " + fileContent); } + let key = bot.dataMine + "-" + bot.codeName + "-" + productCodeName + "-" + bot.exchange + "-" + bot.market.baseAsset + '/' + bot.market.quotedAsset + let event = { + dateRange: dataRange + } + + global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Data Range Updated', event) + callBack(global.DEFAULT_OK_RESPONSE); } } @@ -781,6 +815,7 @@ thisReport.save(callBack); bot.hasTheBotJustStarted = false; + } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = "+ err.stack); diff --git a/MultiPeriodMarket.js b/MultiPeriodMarket.js index 9ba755bb1..4df897da6 100644 --- a/MultiPeriodMarket.js +++ b/MultiPeriodMarket.js @@ -173,7 +173,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getFile -> Entering function."); } let dateForPath = bot.processDatetime.getUTCFullYear() + '/' + utilities.pad(bot.processDatetime.getUTCMonth() + 1, 2) + '/' + utilities.pad(bot.processDatetime.getUTCDate(), 2); - let fileName = market.baseAsset + '_' + market.quotedAsset + ".json"; + let fileName = "Data.json"; let filePath if (dependency.dataSet === "Multi-Period-Market") { @@ -338,6 +338,15 @@ thisReport.file.lastExecution = bot.processDatetime; thisReport.save(callBack); + if (global.areEqualDates(bot.processDatetime, new Date()) === false) { + logger.newInternalLoop(bot.codeName, bot.process, bot.processDatetime); + } + + /* Telling the world we are alive and doing well */ + let currentDateString = bot.processDatetime.getUTCFullYear() + '-' + utilities.pad(bot.processDatetime.getUTCMonth() + 1, 2) + '-' + utilities.pad(bot.processDatetime.getUTCDate(), 2); + let currentDate = new Date(bot.processDatetime) + let lastDate = new Date() + bot.processHeartBeat(currentDateString, global.getPercentage(currentDate, currentDate, lastDate)) } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = "+ err.stack); diff --git a/ProcessExecutionEvents.js b/ProcessExecutionEvents.js index ed79e1be7..72741eba4 100644 --- a/ProcessExecutionEvents.js +++ b/ProcessExecutionEvents.js @@ -83,6 +83,8 @@ global.SYSTEM_EVENT_HANDLER.listenToEvent(key, 'Process Execution Finished', undefined, callerId, responseCallBack, eventsCallBack) + bot.processHeartBeat(undefined, undefined, "Waiting for " + processThisDependsOn.parentNode.parentNode.name + "->" + processThisDependsOn.parentNode.code.codeName + "->" + processThisDependsOn.code.codeName) + function responseCallBack(message) { if (message.result !== global.DEFAULT_OK_RESPONSE.result) { logger.write(MODULE_NAME, "[ERROR] start -> responseCallBack -> message = " + JSON.stringify(message)) @@ -110,6 +112,8 @@ global.SYSTEM_EVENT_HANDLER.createEventHandler(currentProcessKey, 'Process Execution Started') global.SYSTEM_EVENT_HANDLER.raiseEvent(currentProcessKey, 'Process Execution Started', event) + bot.processHeartBeat(undefined, undefined,"Running...") + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] start -> eventsCallBack -> " + currentProcessKey + " Process Execution Started because " + key + " Finished."); } } diff --git a/ProcessOutput.js b/ProcessOutput.js index 6a07bbc34..4d2369ece 100644 --- a/ProcessOutput.js +++ b/ProcessOutput.js @@ -14,7 +14,7 @@ return thisObject; - function raiseEvents(statusDependencies, callBackFunction) { + function raiseEvents(lastFile, callBackFunction) { try { if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] raiseEvents -> Entering function."); } @@ -81,11 +81,9 @@ let product = outputDataset.referenceParent.parentNode.code.codeName let dataset = outputDataset.referenceParent.code.codeName - let statusReport = statusDependencies.reportsByMainUtility.get("Self Reference") - - key = dataMine + "-" + botName + "-" + product + "-" + dataset + key = dataMine + "-" + botName + "-" + product + "-" + dataset + "-" + bot.exchange + "-" + bot.market.baseAsset + '/' + bot.market.quotedAsset let event = { - lastFile: statusReport.file.lastFile + lastFile: lastFile } global.SYSTEM_EVENT_HANDLER.createEventHandler(key, 'Dataset Updated') global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Dataset Updated', event) diff --git a/Root.js b/Root.js index 41e18541b..7ed96f1c7 100644 --- a/Root.js +++ b/Root.js @@ -205,13 +205,14 @@ /* Simplifying the access to basic info */ botConfig.dataMine = global.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.code.codeName - botConfig.exchange = global.TASK_NODE.bot.processes[processIndex].marketReference.referenceParent.parentNode.parentNode.code.codeName + botConfig.exchange = global.TASK_NODE.bot.processes[processIndex].marketReference.referenceParent.parentNode.parentNode.name botConfig.exchangeNode = global.TASK_NODE.bot.processes[processIndex].marketReference.referenceParent.parentNode.parentNode botConfig.market = { baseAsset: global.TASK_NODE.bot.processes[processIndex].marketReference.referenceParent.baseAsset.referenceParent.code.codeName, quotedAsset: global.TASK_NODE.bot.processes[processIndex].marketReference.referenceParent.quotedAsset.referenceParent.code.codeName } botConfig.uiStartDate = global.TASK_NODE.bot.code.startDate + botConfig.code = global.TASK_NODE.bot.code /* This stuff is still hardcoded and unresolved. */ botConfig.version = { @@ -224,7 +225,7 @@ botConfig.loopCounter = 0; /* File Path Root */ - botConfig.filePathRoot = botConfig.dataMine + "/" + botConfig.codeName + "/" + botConfig.exchange; + botConfig.filePathRoot = botConfig.exchange + "/" + botConfig.market.baseAsset + "-" + botConfig.market.quotedAsset + "/" + botConfig.dataMine + "/" + botConfig.codeName ; /* Process Key */ botConfig.processKey = global.TASK_NODE.bot.processes[processIndex].name + '-' + global.TASK_NODE.bot.processes[processIndex].type + '-' + global.TASK_NODE.bot.processes[processIndex].id @@ -386,7 +387,6 @@ logger.write(MODULE_NAME, "[INFO] start -> bootingBot -> runSensorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); logger.write(MODULE_NAME, "[INFO] start -> bootingBot -> runSensorBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); - console.log(logDisplace + "Root : [INFO] start -> bootingBot -> runSensorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); logger.persist(); } else { @@ -451,8 +451,6 @@ logger.write(MODULE_NAME, "[INFO] start -> bootingBot -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); logger.write(MODULE_NAME, "[INFO] start -> bootingBot -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); - - console.log(logDisplace + "Root : [INFO] start -> bootingBot -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); logger.persist(); } else { @@ -517,8 +515,6 @@ logger.write(MODULE_NAME, "[INFO] start -> bootingBot -> runTradingBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); logger.write(MODULE_NAME, "[INFO] start -> bootingBot -> runTradingBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId); - console.log(logDisplace + "Root : [INFO] start -> bootingBot -> runTradingBot -> onInitializeReady -> whenStartFinishes -> botId = " + botId); - console.log(logDisplace + "Root : [INFO] start -> bootingBot -> runTradingBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); logger.persist(); } else { @@ -557,7 +553,7 @@ function exitProcessInstance() { global.ENDED_PROCESSES_COUNTER++ - console.log("[INFO] Task Server -> " + global.TASK_NODE.name + " -> exitProcessInstance -> Process #" + global.ENDED_PROCESSES_COUNTER + " from " + global.TOTAL_PROCESS_INSTANCES_CREATED + " exiting."); + //console.log("[INFO] Task Server -> " + global.TASK_NODE.name + " -> exitProcessInstance -> Process #" + global.ENDED_PROCESSES_COUNTER + " from " + global.TOTAL_PROCESS_INSTANCES_CREATED + " exiting."); if (global.ENDED_PROCESSES_COUNTER === global.TOTAL_PROCESS_INSTANCES_CREATED) { global.EXIT_NODE_PROCESS() diff --git a/SensorBotProcessMainLoop.js b/SensorBotProcessMainLoop.js index b8e2c49fc..f73961f20 100644 --- a/SensorBotProcessMainLoop.js +++ b/SensorBotProcessMainLoop.js @@ -56,9 +56,7 @@ return; } USER_BOT_MODULE = {} - if (bot.process === "Hole-Fixing") { - //USER_BOT_MODULE.newUserBot = require(process.env.BOTS_PATH + '/aamasters/AAMasters/bots/AACharly-Sensor-Bot/Hole-Fixing/User.Bot').newUserBot - } + try { USER_BOT_MODULE.newUserBot = eval(text); // TODO This needs to be changed function } catch (err) { @@ -115,7 +113,7 @@ function loop() { try { - + processHeartBeat(undefined, undefined, "Running...") function pad(str, max) { str = str.toString(); return str.length < max ? pad(" " + str, max) : str; @@ -150,12 +148,11 @@ /* High level log entry */ - console.log(new Date().toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(bot.exchange, 20) + " " + pad(bot.market.baseAsset + '/' + bot.market.quotedAsset, 10) - + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8) ) + console.log(new Date().toISOString() + " " + pad(bot.exchange, 20) + " " + pad(bot.market.baseAsset + '/' + bot.market.quotedAsset, 10) + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + + " Main Loop # " + pad(Number(bot.loopCounter), 8) ) /* We will prepare first the infraestructure needed for the bot to run. There are 4 modules we need to sucessfullly initialize first. */ - let processOutput let processExecutionEvents let userBot; let statusDependencies; @@ -319,7 +316,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeStatusDependencies -> Entering function."); } - statusDependencies = STATUS_DEPENDENCIES.newStatusDependencies(bot, logger, STATUS_REPORT, UTILITIES); + statusDependencies = STATUS_DEPENDENCIES.newStatusDependencies(bot, logger, STATUS_REPORT, UTILITIES, PROCESS_OUTPUT); statusDependencies.initialize(onInizialized); @@ -394,7 +391,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeUserBot -> Entering function."); } - usertBot = USER_BOT_MODULE.newUserBot(bot, logger, COMMONS_MODULE, UTILITIES, fileStorage, STATUS_REPORT, exchangeAPI); + usertBot = USER_BOT_MODULE.newUserBot(bot, logger, COMMONS_MODULE, UTILITIES, FILE_STORAGE, STATUS_REPORT, exchangeAPI); usertBot.initialize(statusDependencies, onInizialized); @@ -495,7 +492,7 @@ switch (err.result) { case global.DEFAULT_OK_RESPONSE.result: { logger.write(MODULE_NAME, "[INFO] run -> loop -> startUserBot -> onFinished > Execution finished well."); - raiseEventsProcessOutput() + finishProcessExecutionEvents() return; } case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time. @@ -578,81 +575,6 @@ } } - function raiseEventsProcessOutput() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> raiseEventsProcessOutput -> Entering function."); } - - processOutput = PROCESS_OUTPUT.newProcessOutput(bot, logger) - - processOutput.raiseEvents(statusDependencies, onFinished); - - function onFinished(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> raiseEventsProcessOutput -> onFinished -> Entering function."); } - - switch (err.result) { - case global.DEFAULT_OK_RESPONSE.result: { - logger.write(MODULE_NAME, "[INFO] run -> loop -> raiseEventsProcessOutput -> onFinished -> Execution finished well."); - finishProcessExecutionEvents() - 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, "[WARN] run -> loop -> raiseEventsProcessOutput -> 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. - processStopped() - logger.write(MODULE_NAME, "[ERROR] run -> loop -> raiseEventsProcessOutput -> onFinished -> 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 -> raiseEventsProcessOutput -> onFinished -> Unhandled err.result received. -> err.result = " + err.result); - logger.write(MODULE_NAME, "[ERROR] run -> loop -> raiseEventsProcessOutput -> onFinished -> Unhandled err.result received. -> err = " + 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 -> raiseEventsProcessOutput -> onFinished -> err = " + err.stack); - logger.persist(); - clearInterval(fixedTimeLoopIntervalHandle); - clearTimeout(nextLoopTimeoutHandle); - clearTimeout(checkLoopHealthHandle); - bot.enableCheckLoopHealth = false; - callBackFunction(err); - } - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> raiseEventsProcessOutput -> err = " + err.stack); - logger.persist(); - clearInterval(fixedTimeLoopIntervalHandle); - clearTimeout(nextLoopTimeoutHandle); - clearTimeout(checkLoopHealthHandle); - bot.enableCheckLoopHealth = false; - callBackFunction(err); - } - } - function finishProcessExecutionEvents() { try { @@ -733,9 +655,6 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> nextWaitTime = " + nextWaitTime); } /* We show we reached the end of the loop. */ - - processHeartBeat() - /* Here we check if we must stop the loop gracefully. */ shallWeStop(onStop, onContinue); @@ -754,6 +673,7 @@ clearTimeout(nextLoopTimeoutHandle); clearTimeout(checkLoopHealthHandle); bot.enableCheckLoopHealth = false; + processStopped() callBackFunction(global.DEFAULT_OK_RESPONSE); return; @@ -767,24 +687,14 @@ switch (nextWaitTime) { case 'Normal': { - if (bot.runAtFixedInterval === true) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Fixed Interval Normal exit point reached."); } - if (processConfig.deadWaitTime > 0) { - checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.deadWaitTime, bot.loopCounter); - } - if(global.WRITE_LOGS_TO_FILES === 'true'){ - logger.persist(); - } - return; - } else { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.normalWaitTime / 1000) + " seconds."); } - if (processConfig.deadWaitTime > 0) { - checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.deadWaitTime, bot.loopCounter); - } - nextLoopTimeoutHandle = setTimeout(loop, processConfig.normalWaitTime); - if(global.WRITE_LOGS_TO_FILES === 'true'){ - logger.persist(); - } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.normalWaitTime / 1000) + " seconds."); } + if (processConfig.deadWaitTime > 0) { + checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.deadWaitTime, bot.loopCounter); + } + nextLoopTimeoutHandle = setTimeout(loop, processConfig.normalWaitTime); + processHeartBeat(undefined, undefined, "Waiting " + processConfig.normalWaitTime / 1000 + " seconds for next execution.") + if(global.WRITE_LOGS_TO_FILES === 'true'){ + logger.persist(); } } break; @@ -794,6 +704,7 @@ checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.retryWaitTime * 5, bot.loopCounter); } nextLoopTimeoutHandle = setTimeout(loop, processConfig.retryWaitTime); + processHeartBeat(undefined, undefined, "Trying to recover from some problem. Waiting " + processConfig.retryWaitTime / 1000 + " seconds for next execution.") logger.persist(); } break; @@ -805,6 +716,7 @@ } else { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.sleepWaitTime / 60000) + " minutes."); } nextLoopTimeoutHandle = setTimeout(loop, processConfig.sleepWaitTime); + processHeartBeat(undefined, undefined, "Waiting " + processConfig.sleepWaitTime / 60000 + " minutes for next execution.") logger.persist(); } } @@ -817,6 +729,7 @@ } else { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.comaWaitTime / 3600000) + " hours."); } nextLoopTimeoutHandle = setTimeout(loop, processConfig.comaWaitTime); + processHeartBeat(undefined, undefined, "Waiting " + processConfig.comaWaitTime / 3600000 + " hours for next execution.") logger.persist(); } } @@ -890,10 +803,12 @@ } } - function processHeartBeat(processingDate) { + function processHeartBeat(processingDate, percentage, status) { let event = { seconds: (new Date()).getSeconds(), - processingDate: processingDate + processingDate: processingDate, + percentage: percentage, + status: status } global.SYSTEM_EVENT_HANDLER.raiseEvent(bot.processKey, 'Heartbeat', event) } diff --git a/Session.js b/Session.js index 3d61e42aa..872258aad 100644 --- a/Session.js +++ b/Session.js @@ -287,6 +287,22 @@ } } + /* Quoted Asset */ + { + if (tradingSystem.parameters.quotedAsset !== undefined) { + if (tradingSystem.parameters.quotedAsset.referenceParent !== undefined) { + if (tradingSystem.parameters.quotedAsset.referenceParent.referenceParent !== undefined) { + + let code = tradingSystem.parameters.quotedAsset.referenceParent.referenceParent.code + + if (code.codeName !== undefined) { + bot.VALUES_TO_USE.quotedAsset = code.codeName; + } + } + } + } + } + /* Time Frame */ if (tradingSystem.parameters.timeFrame !== undefined) { bot.VALUES_TO_USE.timeFrame = tradingSystem.parameters.timeFrame.code.value @@ -398,6 +414,22 @@ } } + /* Quoted Asset. */ + { + if (bot.SESSION.parameters.quotedAsset !== undefined) { + if (bot.SESSION.parameters.quotedAsset.referenceParent !== undefined) { + if (bot.SESSION.parameters.quotedAsset.referenceParent.referenceParent !== undefined) { + + let code = bot.SESSION.parameters.quotedAsset.referenceParent.referenceParent.code + + if (code.codeName !== undefined) { + bot.VALUES_TO_USE.quotedAsset = code.codeName; + } + } + } + } + } + /* Time Frame */ if (bot.SESSION.parameters.timeFrame !== undefined) { bot.VALUES_TO_USE.timeFrame = bot.SESSION.parameters.timeFrame.code.value diff --git a/StatusDependencies.js b/StatusDependencies.js index 176188c16..19e7485ca 100644 --- a/StatusDependencies.js +++ b/StatusDependencies.js @@ -1,4 +1,4 @@ -exports.newStatusDependencies = function newStatusDependencies(BOT, logger, STATUS_REPORT, UTILITIES) { +exports.newStatusDependencies = function newStatusDependencies(BOT, logger, STATUS_REPORT, UTILITIES, PROCESS_OUTPUT) { const FULL_LOG = true; const LOG_FILE_CONTENT = false; @@ -53,7 +53,7 @@ for (let i = 0; i < dependenciesToProcess.length; i++) { - let statusReportModule = STATUS_REPORT.newStatusReport(BOT, logger, UTILITIES); + let statusReportModule = STATUS_REPORT.newStatusReport(BOT, logger, UTILITIES, PROCESS_OUTPUT); logger.write(MODULE_NAME, "[INFO] initialize -> onInitilized -> Initializing Status Report # " + (i + 1)); let statusDependency = dependenciesToProcess[i] diff --git a/StatusReport.js b/StatusReport.js index d6cd7210e..4e1eec387 100644 --- a/StatusReport.js +++ b/StatusReport.js @@ -1,4 +1,4 @@ -exports.newStatusReport = function newStatusReport(BOT, logger, UTILITIES) { +exports.newStatusReport = function newStatusReport(BOT, logger, UTILITIES, PROCESS_OUTPUT) { /* @@ -136,14 +136,16 @@ if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] load -> Entering function."); } - let fileName = "Status.Report." + bot.market.baseAsset + '_' + bot.market.quotedAsset + ".json"; + let fileName = "Status.Report.json"; let filePath; let ownerId = statusDependencyNode.dataMine + "-" + statusDependencyNode.bot + "-" + statusDependencyNode.botVersion.major + "-" + statusDependencyNode.botVersion.minor + "-" + statusDependencyNode.process + "-" + statusDependencyNode.dataSetVersion; let botId = bot.dataMine + "-" + bot.codeName + "-" + bot.version.major + "-" + bot.version.minor + "-" + bot.process + "-" + bot.dataSetVersion; if (ownerId !== botId) { - let rootPath = statusDependencyNode.dataMine + "/" + statusDependencyNode.bot + "/" + bot.exchange; + + let rootPath = bot.exchange + "/" + bot.market.baseAsset + "-" + bot.market.quotedAsset + "/" + statusDependencyNode.dataMine + "/" + statusDependencyNode.bot + filePath = rootPath + "/Reports/" + sessionPath + statusDependencyNode.process ; } else { filePath = bot.filePathRoot + "/Reports/" + sessionPath + statusDependencyNode.process ; @@ -233,7 +235,7 @@ return; } - let fileName = "Status.Report." + bot.market.baseAsset + '_' + bot.market.quotedAsset + ".json"; + let fileName = "Status.Report.json"; let filePath = bot.filePathRoot + "/Reports/" + sessionPath + statusDependencyNode.process; filePath += '/' + fileName @@ -255,7 +257,12 @@ logger.write(MODULE_NAME, "[INFO] save -> onFileCreated -> Content written = " + fileContent); } - callBackFunction(global.DEFAULT_OK_RESPONSE); + /* All good, lets emit the event that means data has been updated. */ + + let processOutput = PROCESS_OUTPUT.newProcessOutput(bot, logger) + + processOutput.raiseEvents(thisObject.file.lastFile, callBackFunction); + return; } diff --git a/TradingBot.js b/TradingBot.js index 3129df6d7..7dacf7836 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -103,7 +103,7 @@ } } - /* From here we have more or less the same we used to have at JASON */ + const TRADING_SIMULATION = require('./TradingSimulation.js'); let tradingSimulation = TRADING_SIMULATION.newTradingSimulation(bot, logger, UTILITIES); @@ -204,6 +204,7 @@ record.minimumBalanceB + "," + record.maximumBalanceB + "," + record.baseAsset + "," + + record.quotedAsset + "," + record.positionPeriods + "," + record.positionDays + "," + record.distanceToLastTriggerOn + "," + @@ -219,10 +220,8 @@ fileContent = "[" + fileContent + "]"; - let fileName = '' + market.baseAsset + '_' + market.quotedAsset + '.json'; - - let filePathRoot = bot.dataMine + "/" + bot.codeName + "/" + bot.exchange; - let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timeFrameLabel; + let fileName = 'Data.json'; + let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timeFrameLabel; filePath += '/' + fileName fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); @@ -297,10 +296,9 @@ fileContent = "[" + fileContent + "]"; fileContent = "[" + JSON.stringify(tradingSystem) + "," + fileContent + "]"; - let fileName = '' + market.baseAsset + '_' + market.quotedAsset + '.json'; - let filePathRoot = bot.dataMine + "/" + bot.codeName + "/" + bot.exchange; - let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timeFrameLabel; + let fileName = 'Data.json'; + let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timeFrameLabel; filePath += '/' + fileName fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); @@ -367,10 +365,9 @@ } fileContent = "[" + fileContent + "]"; - let fileName = '' + market.baseAsset + '_' + market.quotedAsset + '.json'; - let filePathRoot = bot.dataMine + "/" + bot.codeName + "/" + bot.exchange; - let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timeFrameLabel; + let fileName = 'Data.json'; + let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timeFrameLabel; filePath += '/' + fileName fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); @@ -440,10 +437,9 @@ } fileContent = "[" + fileContent + "]"; - let fileName = '' + market.baseAsset + '_' + market.quotedAsset + '.json'; - let filePathRoot = bot.dataMine + "/" + bot.codeName + "/" + bot.exchange; - let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timeFrameLabel; + let fileName = 'Data.json'; + let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timeFrameLabel; filePath += '/' + fileName fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); @@ -466,9 +462,6 @@ } - /* Emit event that signals that simulation files were updated */ - global.SYSTEM_EVENT_HANDLER.raiseEvent('Jason-Multi-Period', 'Simulation Files Updated') - callBackFunction(global.DEFAULT_OK_RESPONSE); } @@ -555,6 +548,7 @@ record.minimumBalanceB + "," + record.maximumBalanceB + "," + record.baseAsset + "," + + record.quotedAsset + "," + record.positionPeriods + "," + record.positionDays + "]"; @@ -566,10 +560,8 @@ fileContent = "[" + fileContent + "]"; - let fileName = '' + market.baseAsset + '_' + market.quotedAsset + '.json'; - - let filePathRoot = bot.dataMine + "/" + bot.codeName + "/" + bot.exchange; - let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timeFrameLabel; + let fileName = 'Data.json'; + let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timeFrameLabel; filePath += '/' + fileName fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); @@ -661,6 +653,7 @@ record.minimumBalanceB + "," + record.maximumBalanceB + "," + record.baseAsset + "," + + record.quotedAsset + "," + record.positionPeriods + "," + record.positionDays + "]"; @@ -673,10 +666,8 @@ fileContent = "[" + fileContent + "]"; let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.baseAsset + '_' + market.quotedAsset + '.json'; - - let filePathRoot = bot.dataMine + "/" + bot.codeName + "/" + bot.exchange; - let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timeFrameLabel + "/" + dateForPath; + let fileName = 'Data.json'; + let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timeFrameLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); @@ -761,10 +752,8 @@ fileContent = "[" + JSON.stringify(tradingSystem) + "," + fileContent + "]"; let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.baseAsset + '_' + market.quotedAsset + '.json'; - - let filePathRoot = bot.dataMine + "/" + bot.codeName + "/" + bot.exchange; - let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timeFrameLabel + "/" + dateForPath; + let fileName = 'Data.json'; + let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timeFrameLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); @@ -838,10 +827,8 @@ fileContent = "[" + fileContent + "]"; let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.baseAsset + '_' + market.quotedAsset + '.json'; - - let filePathRoot = bot.dataMine + "/" + bot.codeName + "/" + bot.exchange; - let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timeFrameLabel + "/" + dateForPath; + let fileName = 'Data.json'; + let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timeFrameLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); @@ -918,10 +905,8 @@ fileContent = "[" + fileContent + "]"; let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.baseAsset + '_' + market.quotedAsset + '.json'; - - let filePathRoot = bot.dataMine + "/" + bot.codeName + "/" + bot.exchange; - let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timeFrameLabel + "/" + dateForPath; + let fileName = 'Data.json'; + let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timeFrameLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); @@ -944,9 +929,6 @@ } - /* Emit event that signals that simulation files were updated */ - global.SYSTEM_EVENT_HANDLER.raiseEvent('Jason-Multi-Period', 'Simulation Files Updated') - callBackFunction(global.DEFAULT_OK_RESPONSE); } diff --git a/TradingBotProcessMainLoop.js b/TradingBotProcessMainLoop.js index 85ae4182d..3820e6d33 100644 --- a/TradingBotProcessMainLoop.js +++ b/TradingBotProcessMainLoop.js @@ -69,7 +69,6 @@ } USER_BOT_MODULE = {} - //USER_BOT_MODULE.newUserBot = require(process.env.BOTS_PATH + '/aamasters/AAMasters/bots/AAJason-Trading-Engine-Bot/Multi-Period/User.Bot').newUserBot // Use this for a better debugging experience. You need to bring this js module to this folder in order to work. USER_BOT_MODULE.newUserBot = eval(text); // Use this for production filePath = bot.dataMine + "/" + "bots" + "/" + bot.repo; @@ -86,7 +85,6 @@ } USER_BOT_COMMONS = {} - //USER_BOT_COMMONS.newCommons = require(process.env.BOTS_PATH + '/aamasters/AAMasters/bots/AAJason-Trading-Engine-Bot/Commons').newCommons // Use this for a better debugging experience. You need to bring this js module to this folder in order to work. USER_BOT_COMMONS.newCommons = eval(text); // Use this for production session.initialize(onSessionInitialized) @@ -119,6 +117,7 @@ try { + processHeartBeat(undefined, undefined, "Running...") function pad(str, max) { str = str.toString(); return str.length < max ? pad(" " + str, max) : str; @@ -159,8 +158,8 @@ /* High level log entry */ - console.log(new Date().toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(bot.exchange, 20) + " " + pad(bot.market.baseAsset + '/' + bot.market.quotedAsset, 10) - + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8) + " " + bot.sessionKey ) + console.log(new Date().toISOString() + " " + pad(bot.exchange, 20) + " " + pad(bot.market.baseAsset + '/' + bot.market.quotedAsset, 10) + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + + " Main Loop # " + pad(Number(bot.loopCounter), 8) + " " + bot.sessionKey) /* Checking if we need to need to emit any event */ @@ -189,7 +188,6 @@ /* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */ - let processOutput let processExecutionEvents let userBot; let processFramework; @@ -352,7 +350,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeStatusDependencies -> Entering function."); } - statusDependencies = STATUS_DEPENDENCIES.newStatusDependencies(bot, logger, STATUS_REPORT, UTILITIES); + statusDependencies = STATUS_DEPENDENCIES.newStatusDependencies(bot, logger, STATUS_REPORT, UTILITIES, PROCESS_OUTPUT); statusDependencies.initialize(onInizialized); @@ -701,7 +699,7 @@ case global.DEFAULT_OK_RESPONSE.result: { logger.write(MODULE_NAME, "[INFO] run -> loop -> startProcessFramework -> onFinished -> Execution finished well."); nextWaitTime = 'Normal'; - raiseEventsProcessOutput() + finishProcessExecutionEvents() return; } case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time. @@ -785,81 +783,6 @@ } } - function raiseEventsProcessOutput() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> raiseEventsProcessOutput -> Entering function."); } - - processOutput = PROCESS_OUTPUT.newProcessOutput(bot, logger) - - processOutput.raiseEvents(statusDependencies, onFinished); - - function onFinished(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> raiseEventsProcessOutput -> onFinished -> Entering function."); } - - switch (err.result) { - case global.DEFAULT_OK_RESPONSE.result: { - logger.write(MODULE_NAME, "[INFO] run -> loop -> raiseEventsProcessOutput -> onFinished -> Execution finished well."); - finishProcessExecutionEvents() - 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, "[WARN] run -> loop -> raiseEventsProcessOutput -> 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. - processStopped() - logger.write(MODULE_NAME, "[ERROR] run -> loop -> raiseEventsProcessOutput -> onFinished -> 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 -> raiseEventsProcessOutput -> onFinished -> Unhandled err.result received. -> err.result = " + err.result); - logger.write(MODULE_NAME, "[ERROR] run -> loop -> raiseEventsProcessOutput -> onFinished -> Unhandled err.result received. -> err = " + 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 -> raiseEventsProcessOutput -> onFinished -> err = " + err.stack); - logger.persist(); - clearInterval(fixedTimeLoopIntervalHandle); - clearTimeout(nextLoopTimeoutHandle); - clearTimeout(checkLoopHealthHandle); - bot.enableCheckLoopHealth = false; - callBackFunction(err); - } - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> raiseEventsProcessOutput -> err = " + err.stack); - logger.persist(); - clearInterval(fixedTimeLoopIntervalHandle); - clearTimeout(nextLoopTimeoutHandle); - clearTimeout(checkLoopHealthHandle); - bot.enableCheckLoopHealth = false; - callBackFunction(err); - } - } - function finishProcessExecutionEvents() { try { @@ -958,6 +881,7 @@ } global.SYSTEM_EVENT_HANDLER.raiseEvent(bot.sessionKey, 'Stopped') + processStopped() callBackFunction(global.DEFAULT_OK_RESPONSE); return; @@ -983,6 +907,7 @@ checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.deadWaitTime, bot.loopCounter); } nextLoopTimeoutHandle = setTimeout(loop, waitTime); + processHeartBeat(undefined, undefined, "Waiting " + waitTime / 1000 + " seconds for next execution.") if (global.WRITE_LOGS_TO_FILES === 'true') { logger.persist(); } @@ -994,18 +919,21 @@ checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.deadWaitTime, bot.loopCounter); } nextLoopTimeoutHandle = setTimeout(loop, processConfig.retryWaitTime); + processHeartBeat(undefined, undefined, "Trying to recover from some problem. Waiting " + processConfig.retryWaitTime / 1000 + " seconds for next execution.") logger.persist(); } break; case 'Sleep': { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.sleepWaitTime / 60000) + " minutes."); } nextLoopTimeoutHandle = setTimeout(loop, processConfig.sleepWaitTime); + processHeartBeat(undefined, undefined, "Waiting " + processConfig.sleepWaitTime / 60000 + " minutes for next execution.") logger.persist(); } break; case 'Coma': { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.comaWaitTime / 3600000) + " hours."); } nextLoopTimeoutHandle = setTimeout(loop, processConfig.comaWaitTime); + processHeartBeat(undefined, undefined, "Waiting " + processConfig.comaWaitTime / 3600000 + " hours for next execution.") logger.persist(); } break; @@ -1078,10 +1006,12 @@ } } - function processHeartBeat(processingDate) { + function processHeartBeat(processingDate, percentage, status) { let event = { seconds: (new Date()).getSeconds(), - processingDate: processingDate + processingDate: processingDate, + percentage: percentage, + status: status } global.SYSTEM_EVENT_HANDLER.raiseEvent(bot.processKey, 'Heartbeat', event) } diff --git a/TradingSimulation.js b/TradingSimulation.js index 06c48ab4a..59413023f 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -2,9 +2,9 @@ const FULL_LOG = true; const LOG_FILE_CONTENT = false; - - const MODULE_NAME = "Trading Simulation -> " + bot.SESSION.name; const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; + const MODULE_NAME = "Trading Simulation -> " + bot.SESSION.name; + const GMT_SECONDS = ':00.000 GMT+0000'; let thisObject = { @@ -570,7 +570,7 @@ let processingDate = loopingDay.getUTCFullYear() + '-' + utilities.pad(loopingDay.getUTCMonth() + 1, 2) + '-' + utilities.pad(loopingDay.getUTCDate(), 2); if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Simulation " + bot.sessionKey + " Loop # " + currentCandleIndex + " @ " + processingDate) } - console.log("Jason -> " + MODULE_NAME + " -> runSimulation -> loop -> Simulation " + bot.sessionKey + " Loop # " + currentCandleIndex + " @ " + processingDate) + console.log("Trading-Engine -> " + MODULE_NAME + " -> runSimulation -> loop -> Simulation " + bot.sessionKey + " Loop # " + currentCandleIndex + " @ " + processingDate) bot.sessionHeartBeat(processingDate) // tell the world we are alive and doing well } @@ -658,7 +658,7 @@ let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode); + newCondition(key, condition.javascriptCode, chart); } } } @@ -676,7 +676,7 @@ let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode); + newCondition(key, condition.javascriptCode, chart); } } } @@ -694,7 +694,7 @@ let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode); + newCondition(key, condition.javascriptCode, chart); } } } @@ -825,7 +825,7 @@ let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode); + newCondition(key, condition.javascriptCode, chart); } } } @@ -891,7 +891,7 @@ let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode); + newCondition(key, condition.javascriptCode, chart); } } } @@ -967,7 +967,7 @@ let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode); + newCondition(key, condition.javascriptCode, chart); } } } @@ -1034,7 +1034,7 @@ let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode); + newCondition(key, condition.javascriptCode, chart); } } } @@ -1043,7 +1043,7 @@ } } - function newCondition(key, node) { + function newCondition(key, node, chart) { let condition; let error = '' @@ -1103,6 +1103,14 @@ maximumBalance = bot.VALUES_TO_USE.maximumBalanceB } + if (minimumBalance === undefined) { + minimumBalance = 0 + } + + if (maximumBalance === undefined) { + maximumBalance = 10000000000000000 + } + if (balance > minimumBalance && balance < maximumBalance) { /* @@ -2488,6 +2496,7 @@ } let quotedBaseAsset = '"' + bot.VALUES_TO_USE.baseAsset + '"' + let quotedQuotedAsset = '"' + bot.VALUES_TO_USE.quotedAsset + '"' simulationRecord = { begin: candle.begin, @@ -2524,6 +2533,7 @@ minimumBalanceB: bot.VALUES_TO_USE.minimumBalanceB, maximumBalanceB: bot.VALUES_TO_USE.maximumBalanceB, baseAsset: quotedBaseAsset, + quotedAsset: quotedQuotedAsset, positionPeriods: positionPeriods, positionDays: positionDays, distanceToLastTriggerOn: distanceToLast.triggerOn, diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 0a18fee7b..000000000 --- a/docker-compose.yml +++ /dev/null @@ -1,12 +0,0 @@ -version: '3' -services: - node: - image: superalgos/clone-executor:1.0.51 - build: - context: . - dockerfile: ./Dockerfile - container_name: clone-executor - tty: true - stdin_open: true - command: node Run.js - restart: always diff --git a/server.js b/server.js index 8d5c2d432..947341e30 100644 --- a/server.js +++ b/server.js @@ -25,6 +25,8 @@ global.CUSTOM_FAIL_RESPONSE = { message: "Custom Message" }; +const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; + /* Process Events */ process.on('uncaughtException', function (err) { @@ -177,7 +179,7 @@ function bootLoader() { } if (global.TASK_NODE.bot.processes[processIndex].marketReference.referenceParent === undefined) { - console.log("[WARN] Task Server -> server -> bootLoader -> Market Reference without a Reference Parent. This process will not be executed. -> Process Instance = " + JSON.stringify(global.TASK_NODE.bot.processes[processIndex].marketReference)); + console.log("[WARN] Task Server -> server -> bootLoader -> Market Reference without a Reference Parent. This process will not be executed. -> Process Instance = " + JSON.stringify(global.TASK_NODE.bot.processes[processIndex].marketReference) + ", bot = " + global.TASK_NODE.bot.name); continue } @@ -260,3 +262,25 @@ function startRoot(processIndex) { } } +global.getPercentage = function (fromDate, currentDate, lastDate) { + let fromDays = Math.trunc(fromDate.valueOf() / ONE_DAY_IN_MILISECONDS) + let currentDays = Math.trunc(currentDate.valueOf() / ONE_DAY_IN_MILISECONDS) + let lastDays = Math.trunc(lastDate.valueOf() / ONE_DAY_IN_MILISECONDS) + let percentage = (currentDays - fromDays) * 100 / (lastDays - fromDays) + if ((lastDays - fromDays) === 0) { + percentage = 100 + } + return percentage +} + +global.areEqualDates = function (date1, date2) { + let day1Days = Math.trunc(date1.valueOf() / ONE_DAY_IN_MILISECONDS) + let day2Days = Math.trunc(date2.valueOf() / ONE_DAY_IN_MILISECONDS) + + if (day1Days === day2Days) { + return true + } else { + return false + } +} +