From 4aaeb1dd273adf8d77679eb6d7ec938847fdf15d Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 20 Mar 2020 14:13:25 +0100 Subject: [PATCH] Status implementation --- .../FloatingSpace/CircularProgressBar.js | 10 +- CanvasApp/FloatingSpace/FloatingObject.js | 8 +- CanvasApp/FloatingSpace/UiObject.js | 160 +++++++++++++++++- .../Multi-Period-Daily/User.Bot.js | 13 +- .../Multi-Period-Market/User.Bot.js | 10 ++ .../Multi-Period-Daily/User.Bot.js | 13 +- .../Multi-Period-Market/User.bot.js | 17 +- .../Historic-OHLCVs/User.Bot.js | 14 +- .../Multi-Period-Daily/User.Bot.js | 13 +- .../Multi-Period-Market/User.Bot.js | 10 ++ TaskServer/DebugLog.js | 17 +- TaskServer/FileStorage.js | 5 +- TaskServer/IndicatorBotProcessMainLoop.js | 15 +- TaskServer/MultiPeriodDaily.js | 17 +- TaskServer/MultiPeriodMarket.js | 10 +- TaskServer/ProcessExecutionEvents.js | 4 + TaskServer/SensorBotProcessMainLoop.js | 45 +++-- TaskServer/TradingBotProcessMainLoop.js | 15 +- TaskServer/TradingSimulation.js | 2 +- TaskServer/server.js | 24 +++ 20 files changed, 357 insertions(+), 65 deletions(-) diff --git a/CanvasApp/FloatingSpace/CircularProgressBar.js b/CanvasApp/FloatingSpace/CircularProgressBar.js index be412c47d..2fa62cfbb 100644 --- a/CanvasApp/FloatingSpace/CircularProgressBar.js +++ b/CanvasApp/FloatingSpace/CircularProgressBar.js @@ -55,7 +55,15 @@ function newCircularProgressBar () { if (thisObject.payload === undefined) { return } if (thisObject.payload.uiObject === undefined) { return } opacityCounters[message.event.seconds] = 2000 - thisObject.payload.uiObject.setValue(message.event.processingDate) + if (message.event.processingDate !== undefined) { + thisObject.payload.uiObject.setValue(message.event.processingDate, 2000) + } + if (message.event.percentage !== undefined) { + thisObject.payload.uiObject.setPercentage(message.event.percentage, 2000) + } + if (message.event.status !== undefined) { + thisObject.payload.uiObject.setStatus(message.event.status, 200000) + } } function getContainer (point) { diff --git a/CanvasApp/FloatingSpace/FloatingObject.js b/CanvasApp/FloatingSpace/FloatingObject.js index dd939259f..70dc25f4c 100644 --- a/CanvasApp/FloatingSpace/FloatingObject.js +++ b/CanvasApp/FloatingSpace/FloatingObject.js @@ -339,11 +339,11 @@ function newFloatingObject () { function thisObjectPhysics () { // The radius also have a target. - if (Math.abs(thisObject.container.frame.radius - thisObject.targetRadius) >= 15) { + if (Math.abs(thisObject.container.frame.radius - thisObject.targetRadius) >= 10) { if (thisObject.container.frame.radius < thisObject.targetRadius) { - thisObject.container.frame.radius = thisObject.container.frame.radius + 15 + thisObject.container.frame.radius = thisObject.container.frame.radius + 10 } else { - thisObject.container.frame.radius = thisObject.container.frame.radius - 15 + thisObject.container.frame.radius = thisObject.container.frame.radius - 10 } thisObject.container.eventHandler.raiseEvent('Dimmensions Changed', event) } @@ -479,7 +479,7 @@ function newFloatingObject () { thisObject.rawRadius = radius thisObject.targetRadius = radius - thisObject.container.frame.radius = radius / 3 + thisObject.container.frame.radius = radius / 5 thisObject.container.eventHandler.raiseEvent('Dimmensions Changed', event) } diff --git a/CanvasApp/FloatingSpace/UiObject.js b/CanvasApp/FloatingSpace/UiObject.js index 97d398271..ea74d27e8 100644 --- a/CanvasApp/FloatingSpace/UiObject.js +++ b/CanvasApp/FloatingSpace/UiObject.js @@ -32,6 +32,8 @@ function newUiObject () { highlight: highlight, setErrorMessage: setErrorMessage, setValue: setValue, + setPercentage: setPercentage, + setStatus: setStatus, physics: physics, drawBackground: drawBackground, drawMiddleground: drawMiddleground, @@ -68,6 +70,12 @@ function newUiObject () { let hasValue let valueCounter = 0 + let hasPercentage + let percentageCounter = 0 + + let hasStatus + let statusCounter = 0 + let previousDistanceToChainParent let readyToChainAttachDisplayCounter = 5 let readyToChainAttachDisplayIncrement = 0.1 @@ -92,6 +100,8 @@ function newUiObject () { let errorMessage = '' let currentValue = 0 + let currentPercentage = '' + let currentStatus = '' let rightDragging = false let eventSubscriptionIdHeartbeat @@ -278,6 +288,8 @@ function newUiObject () { highlightPhisycs() errorMessagePhisycs() valuePhisycs() + percentagePhisycs() + statusPhisycs() chainDetachingPhysics() chainAttachingPhysics() referenceDetachingPhysics() @@ -639,6 +651,22 @@ function newUiObject () { } } + function percentagePhisycs () { + percentageCounter-- + if (percentageCounter < 0) { + percentageCounter = 0 + hasPercentage = false + } + } + + function statusPhisycs () { + statusCounter-- + if (statusCounter < 0) { + statusCounter = 0 + hasStatus = false + } + } + function highlight () { isHighlighted = true highlightCounter = 30 @@ -653,11 +681,39 @@ function newUiObject () { } } - function setValue (value) { + function setValue (value, counter) { if (value !== undefined) { currentValue = value hasValue = true - valueCounter = 100 + if (counter !== undefined) { + valueCounter = counter + } else { + valueCounter = 100 + } + } + } + + function setPercentage (percentage, counter) { + if (percentage !== undefined) { + currentPercentage = percentage + hasPercentage = true + if (counter !== undefined) { + percentageCounter = counter + } else { + percentageCounter = 100 + } + } + } + + function setStatus (status, counter) { + if (status !== undefined) { + currentStatus = status + hasStatus = true + if (counter !== undefined) { + statusCounter = counter + } else { + statusCounter = 100 + } } } @@ -730,6 +786,9 @@ function newUiObject () { thisObject.circularProgressBar = undefined } thisObject.isRunning = false + hasValue = false + hasPercentage = false + hasStatus = false lastHeartBeat = undefined } } @@ -858,6 +917,8 @@ function newUiObject () { function drawMiddleground () { if (thisObject.isOnFocus === false) { drawValue() + drawPercentage() + drawStatus() drawText() thisObject.uiObjectTitle.draw() } @@ -936,6 +997,8 @@ function newUiObject () { drawErrorMessage() drawValue() + drawPercentage() + drawStatus() drawText() if (drawTitle === true) { @@ -1187,7 +1250,7 @@ function newUiObject () { position = canvas.floatingSpace.transformPointToMap(position) } - let radius = thisObject.container.frame.radius * 1.5 + let radius = thisObject.container.frame.radius * 1.35 /* Label Text */ let labelPoint let fontSize = thisObject.payload.floatingObject.currentFontSize * 6 / 4 @@ -1208,6 +1271,10 @@ function newUiObject () { label = label.substring(0, MAX_LABEL_LENGTH) + '...' } + if (label.length > 30) { + fontSize = fontSize / 2 + } + labelPoint = { x: position.x - label.length / 2 * fontSize * FONT_ASPECT_RATIO - 5, y: position.y + radius * 7 / 5 + fontSize * FONT_ASPECT_RATIO + 15 @@ -1220,6 +1287,92 @@ function newUiObject () { } } + function drawPercentage () { + if (hasPercentage === false) { return } + if (canvas.floatingSpace.inMapMode === true) { return } + + let position = { + x: 0, + y: 0 + } + + position = thisObject.container.frame.frameThisPoint(position) + + if (canvas.floatingSpace.inMapMode === true) { + position = canvas.floatingSpace.transformPointToMap(position) + } + + let radius = thisObject.container.frame.radius * 1.75 + /* Label Text */ + let labelPoint + let fontSize = thisObject.payload.floatingObject.currentFontSize * 6 / 4 + let label + + if (radius > 6) { + const MAX_LABEL_LENGTH = 65 + + label = Number(currentPercentage).toFixed(0) + '%' + + if (label !== undefined) { + if (label.length > MAX_LABEL_LENGTH) { + label = label.substring(0, MAX_LABEL_LENGTH) + '...' + } + + labelPoint = { + x: position.x - label.length / 2 * fontSize * FONT_ASPECT_RATIO - 5, + y: position.y + radius * 7 / 5 + fontSize * FONT_ASPECT_RATIO + 15 + } + + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY + browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TURQUOISE + ', 1)' + browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y) + } + } + } + + function drawStatus () { + if (hasStatus === false) { return } + if (canvas.floatingSpace.inMapMode === true) { return } + + let position = { + x: 0, + y: 0 + } + + position = thisObject.container.frame.frameThisPoint(position) + + if (canvas.floatingSpace.inMapMode === true) { + position = canvas.floatingSpace.transformPointToMap(position) + } + + let radius = thisObject.container.frame.radius * 1.4 + /* Label Text */ + let labelPoint + let fontSize = thisObject.payload.floatingObject.currentFontSize * 6 / 4 / 2 + let label + + if (radius > 6) { + const MAX_LABEL_LENGTH = 65 + + label = currentStatus + + if (label !== undefined) { + if (label.length > MAX_LABEL_LENGTH) { + label = label.substring(0, MAX_LABEL_LENGTH) + '...' + } + + labelPoint = { + x: position.x - label.length / 2 * fontSize * FONT_ASPECT_RATIO - 10, + y: position.y - radius * 7 / 5 + fontSize * FONT_ASPECT_RATIO + 15 + } + + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY + browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', 1)' + browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y) + } + } + } + function addIndexNumber (label) { switch (thisObject.payload.node.type) { case 'Phase': { @@ -1539,3 +1692,4 @@ function newUiObject () { } } } + diff --git a/Legacy-Code/Masters/bots/Bollinger-Bands-Indicator-Bot/Multi-Period-Daily/User.Bot.js b/Legacy-Code/Masters/bots/Bollinger-Bands-Indicator-Bot/Multi-Period-Daily/User.Bot.js index a8e65157a..8c27945fd 100644 --- a/Legacy-Code/Masters/bots/Bollinger-Bands-Indicator-Bot/Multi-Period-Daily/User.Bot.js +++ b/Legacy-Code/Masters/bots/Bollinger-Bands-Indicator-Bot/Multi-Period-Daily/User.Bot.js @@ -247,6 +247,9 @@ let n; processDate = new Date(contextVariables.lastBandFile.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(processDate.valueOf()) + let lastDate = new Date() + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> processDate = " + processDate); } advanceTime(); @@ -275,6 +278,15 @@ } + /* Telling the world we are alive and doing well */ + let currentDateString = processDate.getUTCFullYear() + '-' + utilities.pad(processDate.getUTCMonth() + 1, 2) + '-' + utilities.pad(processDate.getUTCDate(), 2); + let currentDate = new Date(processDate) + 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); + } periodsLoop(); } catch (err) { @@ -864,7 +876,6 @@ thisReport.file.beginingOfMarket = beginingOfMarket.toUTCString() thisReport.save(callBack); - logger.newInternalLoop(bot.codeName, bot.process, lastFileDate); } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.stack); diff --git a/Legacy-Code/Masters/bots/Bollinger-Bands-Indicator-Bot/Multi-Period-Market/User.Bot.js b/Legacy-Code/Masters/bots/Bollinger-Bands-Indicator-Bot/Multi-Period-Market/User.Bot.js index e85e3a4b1..f5bd3cb5f 100644 --- a/Legacy-Code/Masters/bots/Bollinger-Bands-Indicator-Bot/Multi-Period-Market/User.Bot.js +++ b/Legacy-Code/Masters/bots/Bollinger-Bands-Indicator-Bot/Multi-Period-Market/User.Bot.js @@ -17,6 +17,7 @@ }; let statusDependencies; + let utilities = UTILITIES.newCloudUtilities(bot, logger); let fileStorage = FILE_STORAGE.newFileStorage(logger); return thisObject; @@ -470,6 +471,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/Legacy-Code/Masters/bots/Candles-Volumes-Indicator-Bot/Multi-Period-Daily/User.Bot.js b/Legacy-Code/Masters/bots/Candles-Volumes-Indicator-Bot/Multi-Period-Daily/User.Bot.js index 92edb34fa..7329782c2 100644 --- a/Legacy-Code/Masters/bots/Candles-Volumes-Indicator-Bot/Multi-Period-Daily/User.Bot.js +++ b/Legacy-Code/Masters/bots/Candles-Volumes-Indicator-Bot/Multi-Period-Daily/User.Bot.js @@ -229,7 +229,8 @@ Read the candles and volumes from Exchange Raw Data and produce a file for each function buildCandles() { try { - + let fromDate = new Date(contextVariables.lastCandleFile.valueOf()) + let lastDate = new Date() if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> Entering function."); } let outputCandles; @@ -255,6 +256,15 @@ Read the candles and volumes from Exchange Raw Data and produce a file for each return; } + /* Telling the world we are alive and doing well */ + let currentDateString = contextVariables.lastCandleFile.getUTCFullYear() + '-' + utilities.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '-' + utilities.pad(contextVariables.lastCandleFile.getUTCDate(), 2); + let currentDate = new Date(contextVariables.lastCandleFile) + 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); + } /* We prepere the arrays that will accumulate all the information for each output file. @@ -784,7 +794,6 @@ Read the candles and volumes from Exchange Raw Data and produce a file for each thisReport.file.beginingOfMarket = beginingOfMarket.toUTCString() thisReport.save(callBack); - logger.newInternalLoop(bot.codeName, bot.process, lastFileDate); } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.stack); diff --git a/Legacy-Code/Masters/bots/Candles-Volumes-Indicator-Bot/Multi-Period-Market/User.bot.js b/Legacy-Code/Masters/bots/Candles-Volumes-Indicator-Bot/Multi-Period-Market/User.bot.js index 71e16bd6c..b7664236e 100644 --- a/Legacy-Code/Masters/bots/Candles-Volumes-Indicator-Bot/Multi-Period-Market/User.bot.js +++ b/Legacy-Code/Masters/bots/Candles-Volumes-Indicator-Bot/Multi-Period-Market/User.bot.js @@ -378,6 +378,9 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> Entering function."); } + let fromDate = new Date(contextVariables.lastCandleFile.valueOf()) + let lastDate = new Date() + /* Firstly we prepere the arrays that will accumulate all the information for each output file. */ @@ -404,9 +407,7 @@ contextVariables.lastCandleFile = new Date(contextVariables.lastCandleFile.valueOf() + ONE_DAY_IN_MILISECONDS); if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> advanceTime -> New processing time @ " + contextVariables.lastCandleFile.getUTCFullYear() + "/" + (contextVariables.lastCandleFile.getUTCMonth() + 1) + "/" + contextVariables.lastCandleFile.getUTCDate() + "."); } - - logger.newInternalLoop(bot.codeName, bot.process, contextVariables.lastCandleFile); - + /* Validation that we are not going past the head of the market. */ if (contextVariables.lastCandleFile.valueOf() > contextVariables.maxCandleFile.valueOf()) { @@ -417,6 +418,16 @@ return; } + /* Telling the world we are alive and doing well */ + let currentDateString = contextVariables.lastCandleFile.getUTCFullYear() + '-' + utilities.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '-' + utilities.pad(contextVariables.lastCandleFile.getUTCDate(), 2); + let currentDate = new Date(contextVariables.lastCandleFile) + 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); + } + periodsLoop(); } diff --git a/Legacy-Code/Masters/bots/Exchange-Raw-Data-Sensor-Bot/Historic-OHLCVs/User.Bot.js b/Legacy-Code/Masters/bots/Exchange-Raw-Data-Sensor-Bot/Historic-OHLCVs/User.Bot.js index f1e24bc01..e0f8897b8 100644 --- a/Legacy-Code/Masters/bots/Exchange-Raw-Data-Sensor-Bot/Historic-OHLCVs/User.Bot.js +++ b/Legacy-Code/Masters/bots/Exchange-Raw-Data-Sensor-Bot/Historic-OHLCVs/User.Bot.js @@ -240,6 +240,8 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S let lastOHLCVKey = '' let params = undefined let previousSince + let fromDate = new Date(since) + let lastDate = new Date() while (true) { @@ -247,7 +249,14 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S let processingDate = new Date(since) processingDate = processingDate.getUTCFullYear() + '-' + utilities.pad(processingDate.getUTCMonth() + 1, 2) + '-' + utilities.pad(processingDate.getUTCDate(), 2); if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getOHLCVs -> Fetching OHLCVs @ " + processingDate + "-> exchange = " + bot.exchange + " -> symbol = " + symbol + " -> since = " + since + " -> limit = " + limit) } - bot.processHeartBeat("Fetching " + allOHLCVs.length.toFixed(0) + " OHLCVs from " + bot.exchange + " " + symbol + " @ " + processingDate) // tell the world we are alive and doing well + let heartBeatText = "Fetching " + allOHLCVs.length.toFixed(0) + " OHLCVs from " + bot.exchange + " " + symbol + " @ " + processingDate + let currentDate = new Date(since) + let percentage = global.getPercentage(fromDate, currentDate, lastDate) + bot.processHeartBeat(heartBeatText, percentage) // tell the world we are alive and doing well + + if (global.areEqualDates(currentDate, new Date()) === false) { + logger.newInternalLoop(bot.codeName, bot.process, currentDate, percentage); + } /* Defining if we will query the exchange by Date or Id */ if (fetchType === "by Id") { @@ -291,7 +300,8 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S let OHLCV = OHLCVs[0] initialProcessTimestamp = OHLCV[0] // 'timestamp' - beginingOfMarket = new Date(Math.trunc (OHLCV[0] / ONE_DAY) * ONE_DAY) // 'timestamp' + beginingOfMarket = new Date(Math.trunc(OHLCV[0] / ONE_DAY) * ONE_DAY) // 'timestamp' + fromDate = new Date(beginingOfMarket.valueOf()) fisrtTimeThisProcessRun = false } } diff --git a/Legacy-Code/Masters/bots/Stairs-Patterns-Indicator-Bot/Multi-Period-Daily/User.Bot.js b/Legacy-Code/Masters/bots/Stairs-Patterns-Indicator-Bot/Multi-Period-Daily/User.Bot.js index b81b302d0..355c49f61 100644 --- a/Legacy-Code/Masters/bots/Stairs-Patterns-Indicator-Bot/Multi-Period-Daily/User.Bot.js +++ b/Legacy-Code/Masters/bots/Stairs-Patterns-Indicator-Bot/Multi-Period-Daily/User.Bot.js @@ -255,6 +255,8 @@ let n; processDate = new Date(contextVariables.lastCandleFile.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(processDate.valueOf()) + let lastDate = new Date() if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildStairs -> processDate = " + processDate); } advanceTime(); @@ -283,6 +285,16 @@ } + /* Telling the world we are alive and doing well */ + let currentDateString = processDate.getUTCFullYear() + '-' + utilities.pad(processDate.getUTCMonth() + 1, 2) + '-' + utilities.pad(processDate.getUTCDate(), 2); + let currentDate = new Date(processDate) + 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); + } + periodsLoop(); } catch (err) { @@ -1620,7 +1632,6 @@ thisReport.file.beginingOfMarket = beginingOfMarket.toUTCString() thisReport.save(callBack); - logger.newInternalLoop(bot.codeName, bot.process, lastFileDate); } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.stack); diff --git a/Legacy-Code/Masters/bots/Stairs-Patterns-Indicator-Bot/Multi-Period-Market/User.Bot.js b/Legacy-Code/Masters/bots/Stairs-Patterns-Indicator-Bot/Multi-Period-Market/User.Bot.js index f0e976090..a8f1d8f15 100644 --- a/Legacy-Code/Masters/bots/Stairs-Patterns-Indicator-Bot/Multi-Period-Market/User.Bot.js +++ b/Legacy-Code/Masters/bots/Stairs-Patterns-Indicator-Bot/Multi-Period-Market/User.Bot.js @@ -23,6 +23,7 @@ }; let statusDependencies; + let utilities = UTILITIES.newCloudUtilities(bot, logger); let fileStorage = FILE_STORAGE.newFileStorage(logger); return thisObject; @@ -793,6 +794,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/TaskServer/DebugLog.js b/TaskServer/DebugLog.js index ba2c83788..7098aea4a 100644 --- a/TaskServer/DebugLog.js +++ b/TaskServer/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(0) + "%" + } 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/TaskServer/FileStorage.js b/TaskServer/FileStorage.js index 374ab653a..2ec8a47ec 100644 --- a/TaskServer/FileStorage.js +++ b/TaskServer/FileStorage.js @@ -51,7 +51,7 @@ exports.newFileStorage = function newFileStorage(logger) { function onFileRead(err, text) { let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS - if (currentRetryGetTextFile < MAX_RETRY - 3) { + if (currentRetryGetTextFile > MAX_RETRY - 2) { retryTimeToUse = SLOW_RETRY_TIME_IN_MILISECONDS } if (err) { @@ -96,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) @@ -150,7 +151,7 @@ exports.newFileStorage = function newFileStorage(logger) { function onFileWritenn(err) { let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS - if (currentRetryWriteTextFile < MAX_RETRY - 3) { + if (currentRetryWriteTextFile > MAX_RETRY - 2) { retryTimeToUse = SLOW_RETRY_TIME_IN_MILISECONDS } if (err) { diff --git a/TaskServer/IndicatorBotProcessMainLoop.js b/TaskServer/IndicatorBotProcessMainLoop.js index 17eceba01..a99c9e97b 100644 --- a/TaskServer/IndicatorBotProcessMainLoop.js +++ b/TaskServer/IndicatorBotProcessMainLoop.js @@ -145,8 +145,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)); + 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. */ @@ -964,6 +964,7 @@ logger.persist(); } + processStopped() callBackFunction(global.DEFAULT_OK_RESPONSE); return; @@ -982,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(); } @@ -993,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; @@ -1076,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/TaskServer/MultiPeriodDaily.js b/TaskServer/MultiPeriodDaily.js index c9e9acc25..516737d4c 100644 --- a/TaskServer/MultiPeriodDaily.js +++ b/TaskServer/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(); @@ -334,6 +336,16 @@ } + /* 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) { @@ -371,10 +383,6 @@ 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. @@ -808,7 +816,6 @@ bot.hasTheBotJustStarted = false; - logger.newInternalLoop(bot.codeName, bot.process, bot.multiPeriodDailyProcessDatetime); } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = "+ err.stack); diff --git a/TaskServer/MultiPeriodMarket.js b/TaskServer/MultiPeriodMarket.js index 66cf11951..4df897da6 100644 --- a/TaskServer/MultiPeriodMarket.js +++ b/TaskServer/MultiPeriodMarket.js @@ -338,7 +338,15 @@ thisReport.file.lastExecution = bot.processDatetime; thisReport.save(callBack); - logger.newInternalLoop(bot.codeName, bot.process, bot.processDatetime); + 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/TaskServer/ProcessExecutionEvents.js b/TaskServer/ProcessExecutionEvents.js index ed79e1be7..72741eba4 100644 --- a/TaskServer/ProcessExecutionEvents.js +++ b/TaskServer/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/TaskServer/SensorBotProcessMainLoop.js b/TaskServer/SensorBotProcessMainLoop.js index 669a503b9..f73961f20 100644 --- a/TaskServer/SensorBotProcessMainLoop.js +++ b/TaskServer/SensorBotProcessMainLoop.js @@ -113,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; @@ -148,8 +148,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) ) + 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. */ @@ -655,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); @@ -676,6 +673,7 @@ clearTimeout(nextLoopTimeoutHandle); clearTimeout(checkLoopHealthHandle); bot.enableCheckLoopHealth = false; + processStopped() callBackFunction(global.DEFAULT_OK_RESPONSE); return; @@ -689,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; @@ -716,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; @@ -727,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(); } } @@ -739,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(); } } @@ -812,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/TaskServer/TradingBotProcessMainLoop.js b/TaskServer/TradingBotProcessMainLoop.js index fa1168f52..752f94e8a 100644 --- a/TaskServer/TradingBotProcessMainLoop.js +++ b/TaskServer/TradingBotProcessMainLoop.js @@ -157,8 +157,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 */ @@ -880,6 +880,7 @@ } global.SYSTEM_EVENT_HANDLER.raiseEvent(bot.sessionKey, 'Stopped') + processStopped() callBackFunction(global.DEFAULT_OK_RESPONSE); return; @@ -905,6 +906,7 @@ checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.deadWaitTime, bot.loopCounter); } nextLoopTimeoutHandle = setTimeout(loop, waitTime); + processHeartBeat(undefined, undefined, "Waiting " + processConfig.waitTime / 1000 + " seconds for next execution.") if (global.WRITE_LOGS_TO_FILES === 'true') { logger.persist(); } @@ -916,18 +918,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; @@ -1000,10 +1005,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/TaskServer/TradingSimulation.js b/TaskServer/TradingSimulation.js index bb3de5360..358068502 100644 --- a/TaskServer/TradingSimulation.js +++ b/TaskServer/TradingSimulation.js @@ -4,7 +4,7 @@ const LOG_FILE_CONTENT = false; const MODULE_NAME = "Trading Simulation -> " + bot.SESSION.name; - const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; + const GMT_SECONDS = ':00.000 GMT+0000'; let thisObject = { diff --git a/TaskServer/server.js b/TaskServer/server.js index c7523ea32..947341e30 100644 --- a/TaskServer/server.js +++ b/TaskServer/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) { @@ -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 + } +} +