diff --git a/.vs/AACloud/v15/.suo b/.vs/AACloud/v15/.suo index 7b1ba2e91..e9ba96e1d 100644 Binary files a/.vs/AACloud/v15/.suo and b/.vs/AACloud/v15/.suo differ diff --git a/Extraction Bot Main Loop.js b/Extraction Bot Main Loop.js new file mode 100644 index 000000000..6c11cfa21 --- /dev/null +++ b/Extraction Bot Main Loop.js @@ -0,0 +1,205 @@ +exports.newExtractionBotMainLoop = function newExtractionBotMainLoop(BOT) { + + let bot = BOT; + const ROOT_DIR = './'; + + const MODULE_NAME = "Extraction Bot Main Loop"; + const FULL_LOG = true; + + let USER_BOT_MODULE; + let COMMONS_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'); + + try { + COMMONS_MODULE = require(pBotPath + "/" + 'Commons'); + } catch (err) { + // Nothing happens since COMMONS modules are optional. + } + + 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 FILE_STORAGE = require(ROOT_DIR + 'File Storage'); + const DEBUG_MODULE = require(ROOT_DIR + 'Debug Log'); + const STATUS_REPORT = require(ROOT_DIR + 'Status Report'); + const POLONIEX_CLIENT_MODULE = require(ROOT_DIR + 'Poloniex API Client'); + + /* 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. + + /* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */ + + let userBot; + + let nextWaitTime; + + initializeUserBot(); + + function initializeUserBot() { + + if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> initializeUserBot -> Entering function."); } + + usertBot = USER_BOT_MODULE.newUserBot(bot, COMMONS_MODULE, UTILITIES, DEBUG_MODULE, FILE_STORAGE, STATUS_REPORT, POLONIEX_CLIENT_MODULE); + + usertBot.initialize(undefined, undefined, 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. :-)"); + 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 -> 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; + } + } + } + + } 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; + + } + + /* Extraction 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('this.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/Project.njsproj b/Project.njsproj index 6af1a8042..1e4cc3cba 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -13,7 +13,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) Project - Trading-Process + Poloniex-Live-Trades C:\Program Files\nodejs\node.exe False @@ -23,6 +23,9 @@ Code + + Code + diff --git a/Run.js b/Run.js index c5238708c..616bd6b7b 100644 --- a/Run.js +++ b/Run.js @@ -3,7 +3,7 @@ const FULL_LOG = true; /* The following global variable tells the system if it is running on test mode or production. */ -global.RUNNING_MODE = 'Production'; // 'Testnet', 'Mixed' or 'Production' +global.RUNNING_MODE = 'Testnet'; // 'Testnet', 'Mixed' or 'Production' /* You do not have funds at the exchange and still want run your bot? No problem activate the exchange simulation mode: */ @@ -149,6 +149,7 @@ global.FILE_PATH_ROOT = botConfig.devTeam + "/" + botConfig.codeName + "." + bot 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'); +const EXTRACTION_BOT_MAIN_LOOP_MODULE = require('./Extraction 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. */ @@ -214,14 +215,18 @@ for (let i = 0; i < botConfig.processes.length; i++) { function startProcess() { switch (bot.type) { - case 'Trading': { - runTradingBot(processConfig); + case 'Extraction': { + runExtractionBot(processConfig); return; } case 'Indicator': { runIndicatorBot(processConfig); return; } + case 'Trading': { + runTradingBot(processConfig); + return; + } } } } @@ -233,7 +238,45 @@ for (let i = 0; i < botConfig.processes.length; i++) { } } +function runExtractionBot(pProcessConfig) { + try { + if (FULL_LOG === true) { logger.write("[INFO] runExtractionBot -> Entering function."); } + + let extractionBotMainLoop = EXTRACTION_BOT_MAIN_LOOP_MODULE.newExtractionBotMainLoop(botConfig); + extractionBotMainLoop.initialize(global.PLATFORM_CONFIG.bot.path, pProcessConfig, onInitializeReady); + + function onInitializeReady(err) { + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + extractionBotMainLoop.run(whenRunFinishes); + + function whenRunFinishes(err) { + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + logger.write("[INFO] runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully. :-)"); + console.log("Bot execution finished sucessfully. :-)"); + + } else { + + logger.write("[ERROR] runExtractionBot -> onInitializeReady -> whenStartFinishes -> err = " + err.message); + logger.write("[ERROR] runExtractionBot -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. "); + logger.write("[ERROR] runExtractionBot -> onInitializeReady -> whenStartFinishes -> Bye. :-("); + } + } + + } else { + logger.write("[ERROR] runExtractionBot -> onInitializeReady -> err = " + err.message); + logger.write("[ERROR] runExtractionBot -> onInitializeReady -> Bot will not be started. "); + } + } + } + catch (err) { + logger.write("[ERROR] runExtractionBot -> err = " + err.message); + } +} function runIndicatorBot(pProcessConfig) { @@ -275,7 +318,6 @@ function runIndicatorBot(pProcessConfig) { } } - function runTradingBot(pProcessConfig) { try { diff --git a/this.config.json b/this.config.json index 53b059787..5d0bc2469 100644 --- a/this.config.json +++ b/this.config.json @@ -6,7 +6,7 @@ "patch": 0 }, "bot": { - "path": "../Bots/AAMasters/AAMariam-Trading-Bot" + "path": "../Bots/AAMasters/AACharly-Extraction-Bot" }, "stopGracefully": "false" } \ No newline at end of file