From bbcc247255636d5aa00a6d96bb08a99bec1ea2e4 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 8 Mar 2018 17:15:29 +0100 Subject: [PATCH] global.processDatetime --- .vs/AACloudPlatform/v15/.suo | Bin 67072 -> 74240 bytes Assistant.js | 6 +- Azure File Storage.js | 2 + Context.js | 11 ++-- Datasource.js | 120 +++++++++++++++++++++++++++-------- Run.js | 2 +- Trading Bot Main Loop.js | 32 ++++++---- 7 files changed, 123 insertions(+), 50 deletions(-) diff --git a/.vs/AACloudPlatform/v15/.suo b/.vs/AACloudPlatform/v15/.suo index f978ceb32b146aa8133e4125a786c0f495de70d3..5b165dc5ee96a7db7fd789679fe7010e9288eb0a 100644 GIT binary patch delta 4118 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 OejmK)Hi7sf(?0-;1l{}q diff --git a/Assistant.js b/Assistant.js index 3237cccd1..00584fab5 100644 --- a/Assistant.js +++ b/Assistant.js @@ -26,7 +26,6 @@ let openPositions = []; // These are the open positions the bot knows it made by itself. let botContext; - let processDatetime; let exchangeAPI; return thisObject; @@ -40,7 +39,6 @@ /* Store local values. */ botContext = pBotContext; - processDatetime = pProcessDatetime; exchangeAPI = pExchangeAPI; getPositionsAtExchange(onDone); @@ -439,7 +437,7 @@ rate: pRate, amountA: pAmountA, amountB: pAmountB, - date: (processDatetime.valueOf()), + date: (global.processDatetime.valueOf()), status: "open", trades: [] }; @@ -501,7 +499,7 @@ rate: pNewRate, amountA: pPosition.amountB * pNewRate, amountB: pPosition.amountB, - date: (processDatetime.valueOf()), + date: (global.processDatetime.valueOf()), status: "open", trades: [] }; diff --git a/Azure File Storage.js b/Azure File Storage.js index 518cf0080..af33c59d8 100644 --- a/Azure File Storage.js +++ b/Azure File Storage.js @@ -45,6 +45,8 @@ exports.newAzureFileStorage = function newAzureFileStorage(BOT) { dataOwner = pDataOwnerBotCodeName; } + logger.fileName = MODULE_NAME + '.' + dataOwner; + readConnectionStringConfigFile(onConnectionStringReady); function onConnectionStringReady(err, pConnObj) { diff --git a/Context.js b/Context.js index 1694892b9..5705fcd62 100644 --- a/Context.js +++ b/Context.js @@ -64,11 +64,9 @@ let cloudStorage = FILE_STORAGE.newAzureFileStorage(bot); - let processDatetime; - return thisObject; - function initialize(pProcessDatetime, callBackFunction) { + function initialize(callBackFunction) { try { @@ -90,8 +88,7 @@ if (err.result === global.DEFAULT_OK_RESPONSE.result) { - thisObject.newHistoryRecord.date = pProcessDatetime; - processDatetime = pProcessDatetime; + thisObject.newHistoryRecord.date = global.processDatetime; getStatusReport(onDone); @@ -372,7 +369,7 @@ try { let fileName = "Execution.Context.json" - let dateForPath = processDatetime.getUTCFullYear() + '/' + utilities.pad(processDatetime.getUTCMonth() + 1, 2) + '/' + utilities.pad(processDatetime.getUTCDate(), 2) + '/' + utilities.pad(processDatetime.getUTCHours(), 2) + '/' + utilities.pad(processDatetime.getUTCMinutes(), 2); + let dateForPath = global.processDatetime.getUTCFullYear() + '/' + utilities.pad(global.processDatetime.getUTCMonth() + 1, 2) + '/' + utilities.pad(global.processDatetime.getUTCDate(), 2) + '/' + utilities.pad(global.processDatetime.getUTCHours(), 2) + '/' + utilities.pad(global.processDatetime.getUTCMinutes(), 2); let filePath = bot.devTeam + "/" + bot.codeName + "/" + bot.version + "/" + bot.dataSetVersion + "/Output/" + bot.process + "/" + global.EXCHANGE_NAME + "/" + dateForPath; utilities.createFolderIfNeeded(filePath, cloudStorage, onFolderCreated); @@ -507,7 +504,7 @@ return; } - thisObject.statusReport.lastExecution = processDatetime; + thisObject.statusReport.lastExecution = global.processDatetime; let fileContent = JSON.stringify(thisObject.statusReport); diff --git a/Datasource.js b/Datasource.js index def11fc87..4f2c9b90e 100644 --- a/Datasource.js +++ b/Datasource.js @@ -140,7 +140,9 @@ function getMarketFiles() { try { - /* Now we will get the market files */ + + let filesOk = 0; + let filesNotOk = 0; for (i = 0; i < marketFilesPeriods.length; i++) { @@ -149,14 +151,27 @@ getFile(oliviaAzureFileStorage, "@AssetA_@AssetB.json", "@Exchange/Output/Candles/Multi-Period-Market/@Period", periodName, undefined, onFileReceived, callBack); - function onFileReceived(file) { + function onFileReceived(err, file) { - thisObject.candlesFiles.set(periodName, file); + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + filesOk++; + thisObject.candlesFiles.set(periodName, file); + } else { + filesNotOk++; + } - if (thisObject.candlesFiles.size === marketFilesPeriods.length) { + if (filesOk + filesNotOk === marketFilesPeriods.length) { - getDailyFiles(); + if (filesOk === marketFilesPeriods.length) { + getDailyFiles(); + + } else { + logger.write("[ERROR] getCandles -> getMarketFiles -> onFileReceived -> Some files are missing -> filesNotOk = " + filesNotOk); + logger.write("[ERROR] getCandles -> getMarketFiles -> onFileReceived -> Will abort the process and request a retry."); + callBack(global.DEFAULT_RETRY_RESPONSE); + return; + } } } } @@ -169,21 +184,38 @@ function getDailyFiles() { try { + + let filesOk = 0; + let filesNotOk = 0; + for (i = 0; i < dailyFilePeriods.length; i++) { let periodTime = dailyFilePeriods[i][0]; let periodName = dailyFilePeriods[i][1]; - getFile(oliviaAzureFileStorage, "@AssetA_@AssetB.json", "@Exchange/Output/Candles/Multi-Period-Daily/@Period/@Year/@Month/@Day", periodName, processDatetime, onFileReceived, callBack); + getFile(oliviaAzureFileStorage, "@AssetA_@AssetB.json", "@Exchange/Output/Candles/Multi-Period-Daily/@Period/@Year/@Month/@Day", periodName, global.processDatetime, onFileReceived, callBack); - function onFileReceived(file) { + function onFileReceived(err, file) { - thisObject.candlesFiles.set(periodName, file); + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + filesOk++; + thisObject.candlesFiles.set(periodName, file); + } else { + filesNotOk++; + } - if (thisObject.candlesFiles.size === dailyFilePeriods.length + marketFilesPeriods.length) { + if (filesOk + filesNotOk === dailyFilePeriods.length) { - getCandlesWeAreIn(); + if (filesOk === dailyFilePeriods.length) { + getCandlesWeAreIn(); + + } else { + logger.write("[ERROR] getCandles -> getDailyFiles -> onFileReceived -> Some files are missing -> filesNotOk = " + filesNotOk); + logger.write("[ERROR] getCandles -> getDailyFiles -> onFileReceived -> Will abort the process and request a retry."); + callBack(global.DEFAULT_RETRY_RESPONSE); + return; + } } } } @@ -233,7 +265,7 @@ let timePeriod = candle.end - candle.begin + 1; // In miliseconds. (remember each candle spans a period minus one milisecond) - if (candle.begin >= processDatetime.valueOf() - timePeriod * 10 && candle.end <= processDatetime.valueOf()) { + if (candle.begin >= global.processDatetime.valueOf() - timePeriod * 10 && candle.end <= global.processDatetime.valueOf()) { candlesArray.push(candle); @@ -277,7 +309,9 @@ function getMarketFiles() { try { - /* Now we will get the market files */ + + let filesOk = 0; + let filesNotOk = 0; for (i = 0; i < marketFilesPeriods.length; i++) { @@ -286,14 +320,27 @@ getFile(tomAzureFileStorage, "@AssetA_@AssetB.json", "@Exchange/Tom/dataSet.V1/Output/Candle-Stairs/Multi-Period-Market/@Period", periodName, undefined, onFileReceived, callBack); - function onFileReceived(file) { + function onFileReceived(err, file) { - thisObject.stairsFiles.set(periodName, file); + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + filesOk++; + thisObject.stairsFiles.set(periodName, file); + } else { + filesNotOk++; + } - if (thisObject.stairsFiles.size === marketFilesPeriods.length) { + if (filesOk + filesNotOk === marketFilesPeriods.length) { - getDailyFiles(); + if (filesOk === marketFilesPeriods.length) { + getDailyFiles(); + + } else { + logger.write("[ERROR] getPatterns -> getMarketFiles -> onFileReceived -> Some files are missing -> filesNotOk = " + filesNotOk); + logger.write("[ERROR] getPatterns -> getMarketFiles -> onFileReceived -> Will abort the process and request a retry."); + callBack(global.DEFAULT_RETRY_RESPONSE); + return; + } } } } @@ -306,21 +353,38 @@ function getDailyFiles() { try { + + let filesOk = 0; + let filesNotOk = 0; + for (i = 0; i < dailyFilePeriods.length; i++) { let periodTime = dailyFilePeriods[i][0]; let periodName = dailyFilePeriods[i][1]; - getFile(tomAzureFileStorage, "@AssetA_@AssetB.json", "@Exchange/Tom/dataSet.V1/Output/Candle-Stairs/Multi-Period-Daily/@Period/@Year/@Month/@Day", periodName, processDatetime, onFileReceived, callBack); + getFile(tomAzureFileStorage, "@AssetA_@AssetB.json", "@Exchange/Tom/dataSet.V1/Output/Candle-Stairs/Multi-Period-Daily/@Period/@Year/@Month/@Day", periodName, global.processDatetime, onFileReceived, callBack); - function onFileReceived(file) { + function onFileReceived(err, file) { - thisObject.stairsFiles.set(periodName, file); + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + filesOk++; + thisObject.stairsFiles.set(periodName, file); + } else { + filesNotOk++; + } - if (thisObject.stairsFiles.size === dailyFilePeriods.length + marketFilesPeriods.length) { + if (filesOk + filesNotOk === dailyFilePeriods.length) { - getStairsWeAreIn(); + if (filesOk === dailyFilePeriods.length) { + getStairsWeAreIn(); + + } else { + logger.write("[ERROR] getPatterns -> getDailyFiles -> onFileReceived -> Some files are missing -> filesNotOk = " + filesNotOk); + logger.write("[ERROR] getPatterns -> getDailyFiles -> onFileReceived -> Will abort the process and request a retry."); + callBack(global.DEFAULT_RETRY_RESPONSE); + return; + } } } } @@ -374,7 +438,7 @@ stairs.lastMin = pStairsFile[i][10]; stairs.lastMax = pStairsFile[i][11]; - if (processDatetime.valueOf() >= stairs.begin && processDatetime.valueOf() <= stairs.end) { + if (global.processDatetime.valueOf() >= stairs.begin && global.processDatetime.valueOf() <= stairs.end) { thisObject.stairsMap.set(pPeriodName, stairs); @@ -424,24 +488,30 @@ } + if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> final pFilePath = " + pFilePath); } + if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> final pFileName = " + pFileName); } + pFileStorage.getTextFile(pFilePath, pFileName, onFileReceived); function onFileReceived(err, text) { + if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> onFileReceived -> pFilePath = " + pFilePath); } + if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> onFileReceived -> pFileName = " + pFileName); } + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { logger.write("[ERROR] initialize -> getFile -> onFileReceived -> err = " + err.message); - outerCallBack(err); + innerCallBack(err); return; } try { let data = JSON.parse(text); - innerCallBack(data); + innerCallBack(global.DEFAULT_OK_RESPONSE, data); } catch (err) { logger.write("[ERROR] initialize -> getFile -> onFileReceived -> Parsing JSON -> err = " + err.message); - outerCallBack(err); + innerCallBack(err); return; } } diff --git a/Run.js b/Run.js index 7097f8ece..d6c2a999b 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 = 'Testnet'; // or 'Production' +global.RUNNING_MODE = 'Production'; // 'Testnet' or 'Production' /* First thing to do is to read the config and guess which bot we will be running. */ diff --git a/Trading Bot Main Loop.js b/Trading Bot Main Loop.js index 1fe7316b4..cd4c17c86 100644 --- a/Trading Bot Main Loop.js +++ b/Trading Bot Main Loop.js @@ -3,7 +3,7 @@ let bot = BOT; const ROOT_DIR = './'; - const MODULE_NAME = "Trading Bot"; + const MODULE_NAME = "Trading Bot Main Loop"; const FULL_LOG = true; let USER_BOT_MODULE; @@ -63,8 +63,8 @@ /* 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. */ - let processDatetime = new Date(); // This will be considered the process date and time, so as to have it consistenly all over the execution. - processDatetime = new Date(processDatetime.valueOf() - 30 * 24 * 60 * 60 * 1000); // we go 30 days back in time since candles are currently not up to date. + 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. */ @@ -83,7 +83,7 @@ if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> initializeContext -> Entering function."); } context = CONTEXT.newContext(bot, DEBUG_MODULE, AZURE_FILE_STORAGE); - context.initialize(processDatetime, onInizialized); + context.initialize(onInizialized); function onInizialized(err) { @@ -91,7 +91,13 @@ initializeDatasource(); } else { logger.write("[ERROR] run -> loop -> initializeContext -> err = " + err.message); - callBackFunction(err); + if (err.result === global.DEFAULT_RETRY_RESPONSE.result) { + nextWaitTime = 'Retry'; + loopControl(nextWaitTime); + } + else { + callBackFunction(err); + } } } } @@ -104,11 +110,12 @@ datasource.initialize(onInizialized); function onInizialized(err) { - - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - initializeExchangeAPI(); - } else { - logger.write("[ERROR] run -> loop -> initializeDatasource -> err = " + err.message); + logger.write("[ERROR] run -> loop -> initializeDatasource -> err = " + err.message); + if (err.result === global.DEFAULT_RETRY_RESPONSE.result) { + nextWaitTime = 'Retry'; + loopControl(nextWaitTime); + } + else { callBackFunction(err); } } @@ -137,7 +144,7 @@ if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> initializeAssistant -> Entering function."); } assistant = ASSISTANT.newAssistant(bot, DEBUG_MODULE); - assistant.initialize(processDatetime, context, exchangeAPI, onInizialized); + assistant.initialize(context, exchangeAPI, onInizialized); function onInizialized(err) { @@ -159,8 +166,7 @@ let platform = { context: context, datasource: datasource, - assistant: assistant, - processDatetime: processDatetime + assistant: assistant }; usertBot.initialize(platform, onInizialized);