diff --git a/.vs/AACloudPlatform/v15/.suo b/.vs/AACloudPlatform/v15/.suo index 56df7e052..d00fbcd3a 100644 Binary files a/.vs/AACloudPlatform/v15/.suo and b/.vs/AACloudPlatform/v15/.suo differ diff --git a/Indicator Bot Main Loop.js b/Indicator Bot Main Loop.js new file mode 100644 index 000000000..f8e432170 --- /dev/null +++ b/Indicator Bot Main Loop.js @@ -0,0 +1,375 @@ +exports.newIndicatorBotMainLoop = function newIndicatorBotMainLoop(BOT) { + + let bot = BOT; + const ROOT_DIR = './'; + + const MODULE_NAME = "Indicator Bot Main Loop"; + const FULL_LOG = true; + + let USER_BOT_MODULE; + + const DEBUG_MODULE = require(ROOT_DIR + 'Debug Log'); + const logger = DEBUG_MODULE.newDebugLog(); + logger.fileName = MODULE_NAME; + logger.bot = bot; + + let thisObject = { + initialize: initialize, + run: run + }; + + let processConfig; + + return thisObject; + + function initialize(pBotPath, pProcessConfig, callBackFunction) { + + try { + if (FULL_LOG === true) { logger.write("[INFO] initialize -> Entering function."); } + processConfig = pProcessConfig; + + USER_BOT_MODULE = require(pBotPath + "/" + pProcessConfig.name + "/" + 'User.Bot'); + + callBackFunction(global.DEFAULT_OK_RESPONSE); + + } catch (err) { + logger.write("[ERROR] initialize -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function run(callBackFunction) { + + try { + if (FULL_LOG === true) { logger.write("[INFO] run -> Entering function."); } + + loop(); + + function loop() { + + try { + if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> Entering function."); } + + /* We define here all the modules that the rest of the infraestructure, including the bots themselves can consume. */ + + const UTILITIES = require(ROOT_DIR + 'Utilities'); + const AZURE_FILE_STORAGE = require(ROOT_DIR + 'Azure File Storage'); + const DEBUG_MODULE = require(ROOT_DIR + 'Debug Log'); + const POLONIEX_CLIENT_MODULE = require(ROOT_DIR + 'Poloniex API Client'); + const EXCHANGE_API = require(ROOT_DIR + 'ExchangeAPI'); + const CONTEXT = require(ROOT_DIR + 'Context'); + const DATASOURCE = require(ROOT_DIR + 'Datasource'); + const ASSISTANT = require(ROOT_DIR + 'Assistant'); + const STATUS_REPORT = require(ROOT_DIR + 'Status Report'); + + /* We define the datetime for the process that we are running now. This will be the official processing time for both the infraestructure and the bot. */ + + global.processDatetime = new Date(); // This will be considered the process date and time, so as to have it consistenly all over the execution. + global.processDatetime = new Date(global.processDatetime.valueOf() - 30 * 24 * 60 * 60 * 1000); // we go 30 days back in time since candles are currently not up to date. + + /* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */ + + let context; + let datasource; + let exchangeAPI; + let assistant; + let userBot; + + let nextWaitTime; + + initializeContext(); + + function initializeContext() { + + if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> initializeContext -> Entering function."); } + + context = CONTEXT.newContext(bot, DEBUG_MODULE, AZURE_FILE_STORAGE, UTILITIES, STATUS_REPORT); + context.initialize(onInizialized); + + function onInizialized(err) { + + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + logger.write("[INFO] run -> loop -> initializeContext -> onInizialized > Execution finished well. :-)"); + initializeDatasource(); + return; + } + break; + 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("[ERROR] run -> loop -> initializeContext -> onInizialized > Retry Later. Requesting Execution Retry."); + nextWaitTime = 'Retry'; + loopControl(nextWaitTime); + return; + } + break; + case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. + logger.write("[ERROR] run -> loop -> initializeContext -> onInizialized > Operation Failed. Aborting the process."); + callBackFunction(err); + return; + } + break; + } + } + } + + function initializeDatasource() { + + if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> initializeDatasource -> Entering function."); } + + datasource = DATASOURCE.newDatasource(bot, DEBUG_MODULE, AZURE_FILE_STORAGE, UTILITIES); + datasource.initialize(onInizialized); + + function onInizialized(err) { + + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + logger.write("[INFO] run -> loop -> initializeDatasource -> onInizialized > Execution finished well. :-)"); + initializeExchangeAPI(); + return; + } + break; + 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("[ERROR] run -> loop -> initializeDatasource -> onInizialized > Retry Later. Requesting Execution Retry."); + nextWaitTime = 'Retry'; + loopControl(nextWaitTime); + return; + } + break; + case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. + logger.write("[ERROR] run -> loop -> initializeDatasource -> onInizialized > Operation Failed. Aborting the process."); + callBackFunction(err); + return; + } + break; + } + } + } + + function initializeExchangeAPI() { + + if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> initializeExchangeAPI -> Entering function."); } + + exchangeAPI = EXCHANGE_API.newExchangeAPI(bot, DEBUG_MODULE, POLONIEX_CLIENT_MODULE); + exchangeAPI.initialize(onInizialized); + + function onInizialized(err) { + + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + logger.write("[INFO] run -> loop -> initializeExchangeAPI -> onInizialized > Execution finished well. :-)"); + initializeAssistant(); + return; + } + break; + 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("[ERROR] run -> loop -> initializeExchangeAPI -> onInizialized > Retry Later. Requesting Execution Retry."); + nextWaitTime = 'Retry'; + loopControl(nextWaitTime); + return; + } + break; + case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. + logger.write("[ERROR] run -> loop -> initializeExchangeAPI -> onInizialized > Operation Failed. Aborting the process."); + callBackFunction(err); + return; + } + break; + } + } + } + + function initializeAssistant() { + + if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> initializeAssistant -> Entering function."); } + + assistant = ASSISTANT.newAssistant(bot, DEBUG_MODULE); + assistant.initialize(context, exchangeAPI, datasource, onInizialized); + + function onInizialized(err) { + + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + logger.write("[INFO] run -> loop -> initializeAssistant -> onInizialized > Execution finished well. :-)"); + initializeUserBot(); + return; + } + break; + 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("[ERROR] run -> loop -> initializeAssistant -> onInizialized > Retry Later. Requesting Execution Retry."); + nextWaitTime = 'Retry'; + loopControl(nextWaitTime); + return; + } + break; + case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. + logger.write("[ERROR] run -> loop -> initializeAssistant -> onInizialized > Operation Failed. Aborting the process."); + callBackFunction(err); + return; + } + break; + } + } + } + + function initializeUserBot() { + + if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> initializeUserBot -> Entering function."); } + + usertBot = USER_BOT_MODULE.newUserBot(bot, DEBUG_MODULE); + + let platform = { + datasource: datasource, + assistant: assistant + }; + + usertBot.initialize(platform, onInizialized); + + function onInizialized(err) { + + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + logger.write("[INFO] run -> loop -> initializeUserBot -> onInizialized > Execution finished well. :-)"); + startUserBot(); + return; + } + break; + 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("[ERROR] run -> loop -> initializeUserBot -> onInizialized > Retry Later. Requesting Execution Retry."); + nextWaitTime = 'Retry'; + loopControl(nextWaitTime); + return; + } + break; + case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. + logger.write("[ERROR] run -> loop -> initializeUserBot -> onInizialized > Operation Failed. Aborting the process."); + callBackFunction(err); + return; + } + break; + } + } + } + + function startUserBot() { + + if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> startUserBot -> Entering function."); } + + usertBot.start(onFinished); + + function onFinished(err) { + + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + logger.write("[INFO] run -> loop -> startUserBot -> onFinished > Execution finished well. :-)"); + saveContext(); + return; + } + break; + 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("[ERROR] run -> loop -> startUserBot -> onFinished > Retry Later. Requesting Execution Retry."); + nextWaitTime = 'Retry'; + loopControl(nextWaitTime); + return; + } + break; + case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. + logger.write("[ERROR] run -> loop -> startUserBot -> onFinished > Operation Failed. Aborting the process."); + callBackFunction(err); + return; + } + break; + } + } + } + + function saveContext() { + + if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> saveContext -> Entering function."); } + + context.saveThemAll(onFinished); + + function onFinished(err) { + + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + logger.write("[INFO] run -> loop -> saveContext -> onFinished > Execution finished well. :-)"); + nextWaitTime = 'Normal'; + loopControl(nextWaitTime); + return; + } + break; + 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("[ERROR] run -> loop -> saveContext -> onFinished > Can not retry at this point."); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return; + } + break; + case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. + logger.write("[ERROR] run -> loop -> saveContext -> onFinished > Operation Failed. Aborting the process."); + callBackFunction(err); + return; + } + break; + } + } + } + + } catch (err) { + logger.write("[ERROR] run -> loop -> err = " + err.message); + callBackFunction(err); + } + } + + function loopControl(nextWaitTime) { + + if (FULL_LOG === true) { logger.write("[INFO] run -> loopControl -> nextWaitTime = " + nextWaitTime); } + + /* Here we check if we must stop the loop gracefully. */ + + if (shallWeStop() === true) { + + if (FULL_LOG === true) { logger.write("[INFO] run -> loopControl -> Stopping the Loop Gracefully. See you next time! :-)"); } + callBackFunction(global.DEFAULT_OK_RESPONSE); + return; + + } + + /* Indicator bots are going to be executed after a configured period of time after the last execution ended. This is to avoid overlapping executions. */ + + switch (nextWaitTime) { + case 'Normal': { + if (FULL_LOG === true) { logger.write("[INFO] run -> loopControl -> Restarting Loop in " + (processConfig.executionWaitTime / 1000) + " seconds."); } + setTimeout(loop, processConfig.executionWaitTime); + } + break; + case 'Retry': { + if (FULL_LOG === true) { logger.write("[INFO] run -> loopControl -> Restarting Loop in " + (processConfig.retryWaitTime / 1000) + " seconds."); } + setTimeout(loop, processConfig.retryWaitTime); + } + break; + } + } + + function shallWeStop() { + + var fs = require('fs'); + + try { + + global.PLATFORM_CONFIG = JSON.parse(fs.readFileSync('platform.config.json', 'utf8')); + return JSON.parse(global.PLATFORM_CONFIG.stopGracefully); + } + catch (err) { + const logText = "[ERROR] 'readConfig' - ERROR : " + err.message; + console.log(logText); + + return; + } + } + } + + catch (err) { + logger.write("[ERROR] run -> err = " + err.message); + } + } +}; diff --git a/Interval Executor.js b/Interval Executor.js index 70b4a433e..0219d8384 100644 --- a/Interval Executor.js +++ b/Interval Executor.js @@ -91,8 +91,6 @@ } - - let intervalId; if (processConfig.intervalMaxLoops === 0) { @@ -123,7 +121,6 @@ } - if (shutdownEvent.isShuttingDown() === false) { const UTILITIES = require(ROOT_DIR + 'Utilities'); @@ -192,9 +189,7 @@ logger.write("[WARN] Received the signal from last Interval execution to not call it anymore. Stopping execution. "); } - } - } catch (err) { const logText = "[ERROR] 'Start' - ERROR : " + err.message; diff --git a/Project.njsproj b/Project.njsproj index 45489f9dc..a46d74930 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -35,6 +35,9 @@ Code + + Code + diff --git a/Run.js b/Run.js index 355834c8a..4d6768d76 100644 --- a/Run.js +++ b/Run.js @@ -133,13 +133,9 @@ global.dailyFilePeriods = JSON.parse(global.dailyFilePeriods); /* Some LAGACY code starts here. Pending for clean up. */ - - -const START_ALL_MONTHS = false; -const START_ONE_MONTH = true; - const INTERVAL_EXECUTOR_MODULE = require('./Interval Executor'); const TRADING_BOT_MAIN_LOOP_MODULE = require('./Trading Bot Main Loop'); +const INDICATOR_BOT_MAIN_LOOP_MODULE = require('./Indicator Bot Main Loop'); /* Now we will see which are the script Arguments. We expect the name of the process to run, since that is what it should be defined at the Task Scheduller. */ @@ -164,7 +160,6 @@ for (let i = 0; i < botConfig.processes.length; i++) { for (let month = 12; month > 0; month--) { let timeDelay = Math.random() * 10 * 1000; // We introduce a short delay so as to not overload the machine. - setTimeout(startProcess, timeDelay); function startProcess() { @@ -176,15 +171,10 @@ for (let i = 0; i < botConfig.processes.length; i++) { function onInitializeReady() { newIntervalExecutor.start(); - } - } - } - } - } @@ -199,9 +189,7 @@ for (let i = 0; i < botConfig.processes.length; i++) { newIntervalExecutor.initialize(global.PLATFORM_CONFIG.bot.path, processConfig, processConfig.startMode.oneMonth.year, processConfig.startMode.oneMonth.month, onInitializeReady); function onInitializeReady() { - newIntervalExecutor.start(); - } } } @@ -214,9 +202,7 @@ for (let i = 0; i < botConfig.processes.length; i++) { function startProcess() { if (bot.type === "Trading") { - runTradingBot(processConfig); - return; } @@ -225,9 +211,7 @@ for (let i = 0; i < botConfig.processes.length; i++) { newIntervalExecutor.initialize(global.PLATFORM_CONFIG.bot.path, processConfig, undefined, undefined, onInitializeReady); function onInitializeReady() { - newIntervalExecutor.start(); - } } } @@ -241,6 +225,48 @@ for (let i = 0; i < botConfig.processes.length; i++) { } + +function runIndicatorBot(pProcessConfig) { + + try { + if (FULL_LOG === true) { logger.write("[INFO] runIndicatorBot -> Entering function."); } + + let indicatorBotMainLoop = INDICATOR_BOT_MAIN_LOOP_MODULE.newIndicatorBotMainLoop(botConfig); + indicatorBotMainLoop.initialize(global.PLATFORM_CONFIG.bot.path, pProcessConfig, onInitializeReady); + + function onInitializeReady(err) { + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + indicatorBotMainLoop.run(whenRunFinishes); + + function whenRunFinishes(err) { + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + logger.write("[INFO] runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully. :-)"); + console.log("Bot execution finished sucessfully. :-)"); + + } else { + + logger.write("[ERROR] runIndicatorBot -> onInitializeReady -> whenStartFinishes -> err = " + err.message); + logger.write("[ERROR] runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. "); + logger.write("[ERROR] runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bye. :-("); + } + } + + } else { + logger.write("[ERROR] runIndicatorBot -> onInitializeReady -> err = " + err.message); + logger.write("[ERROR] runIndicatorBot -> onInitializeReady -> Bot will not be started. "); + } + } + } + catch (err) { + logger.write("[ERROR] runIndicatorBot -> err = " + err.message); + } +} + + function runTradingBot(pProcessConfig) { try { @@ -259,20 +285,20 @@ function runTradingBot(pProcessConfig) { if (err.result === global.DEFAULT_OK_RESPONSE.result) { - logger.write("[INFO] trading bot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully. :-)"); + logger.write("[INFO] runTradingBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully. :-)"); console.log("Bot execution finished sucessfully. :-)"); } else { - logger.write("[ERROR] trading bot -> onInitializeReady -> whenStartFinishes -> err = " + err.message); - logger.write("[ERROR] trading bot -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. "); - logger.write("[ERROR] trading bot -> onInitializeReady -> whenStartFinishes -> Bye. :-("); + logger.write("[ERROR] runTradingBot -> onInitializeReady -> whenStartFinishes -> err = " + err.message); + logger.write("[ERROR] runTradingBot -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. "); + logger.write("[ERROR] runTradingBot -> onInitializeReady -> whenStartFinishes -> Bye. :-("); } } } else { - logger.write("[ERROR] trading bot -> onInitializeReady -> err = " + err.message); - logger.write("[ERROR] trading bot -> onInitializeReady -> Bot will not be started. "); + logger.write("[ERROR] runTradingBot -> onInitializeReady -> err = " + err.message); + logger.write("[ERROR] runTradingBot -> onInitializeReady -> Bot will not be started. "); } } }