From ef189dc76d7b935b9f2f6a574827ddf365a8ac48 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 14 Nov 2019 12:27:53 +0100 Subject: [PATCH] IndicatorBot working with Multi Period Market after reorg --- IndicatorBotMarket.js => IndicatorBot.js | 278 ++++++++++++++-- IndicatorBotCommons.js | 201 ----------- IndicatorBotDaily.js | 405 ----------------------- MultiPeriodDaily.js | 15 +- MultiPeriodMarket.js | 15 +- Project.njsproj | 10 +- 6 files changed, 268 insertions(+), 656 deletions(-) rename IndicatorBotMarket.js => IndicatorBot.js (50%) delete mode 100644 IndicatorBotCommons.js delete mode 100644 IndicatorBotDaily.js diff --git a/IndicatorBotMarket.js b/IndicatorBot.js similarity index 50% rename from IndicatorBotMarket.js rename to IndicatorBot.js index ec7b1e019..ab38cd4c0 100644 --- a/IndicatorBotMarket.js +++ b/IndicatorBot.js @@ -1,29 +1,22 @@ -exports.newIndicatorBotMarket = function newIndicatorBotMarket(bot, logger, COMMONS, UTILITIES, FILE_STORAGE) { +exports.newIndicatorBot = function newIndicatorBot(bot, logger, UTILITIES, FILE_STORAGE) { const FULL_LOG = true; const LOG_FILE_CONTENT = false; const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; - const MODULE_NAME = "User Bot"; - - const BOLLINGER_CHANNELS_FOLDER_NAME = "Bollinger-Channels"; - const BOLLINGER_STANDARD_CHANNELS_FOLDER_NAME = "Bollinger-Standard-Channels"; - const BOLLINGER_SUB_CHANNELS_FOLDER_NAME = "Bollinger-Sub-Channels"; - const BOLLINGER_STANDARD_SUB_CHANNELS_FOLDER_NAME = "Bollinger-Standard-Sub-Channels"; - - const commons = COMMONS.newIndicatorBotCommons(bot, logger, UTILITIES); + const MODULE_NAME = "Indicator Bot"; thisObject = { initialize: initialize, start: start }; + let utilities = UTILITIES.newCloudUtilities(logger); let fileStorage = FILE_STORAGE.newFileStorage(logger); - let processConfig; return thisObject; - function initialize(pProcessConfig, callBackFunction) { + function initialize(callBackFunction) { try { @@ -32,7 +25,6 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } - processConfig = pProcessConfig; callBackFunction(global.DEFAULT_OK_RESPONSE); } catch (err) { @@ -41,7 +33,7 @@ } } - function start(dataFiles, timePeriod, outputPeriodLabel, startDate, endDate, callBackFunction) { + function start(dataFiles, timePeriod, outputPeriodLabel, currentDay, startDate, endDate, interExecutionMemory, callBackFunction) { try { @@ -50,6 +42,13 @@ let market = global.MARKET; let products = {} let mainDependency + let processingDailyFiles + + if (currentDay !== undefined) { + processingDailyFiles = true + } else { + processingDailyFiles = false + } /* The first phase is about transforming the inputs into a format that can be used to apply the user defined code. */ let dataDependencies = bot.processNode.referenceParent.processDependencies.dataDependencies @@ -88,10 +87,10 @@ recordDefinition = dataDependencyNode.parentNode.record singularVariableName = dataDependencyNode.parentNode.code.singularVariableName /* Transform the raw data into JSON objects */ - jsonData = commons.jsonifyDataFile(dataFile, recordDefinition) + jsonData = jsonifyDataFile(dataFile, recordDefinition) /* Add the calculated properties */ if (dataDependencyNode.parentNode.calculations !== undefined) { - inputData = commons.calculationsProcedure(jsonData, recordDefinition, dataDependencyNode.parentNode.calculations, singularVariableName, timePeriod) + inputData = calculationsProcedure(jsonData, recordDefinition, dataDependencyNode.parentNode.calculations, singularVariableName, timePeriod) } else { inputData = jsonData } @@ -108,11 +107,12 @@ for (let i = 0; i < outputDatasets.length; i++) { let outputDatasetNode = outputDatasets[i] - let jsonData // Just build data as Json objects - let outputData // Data built as a result of applying user defined code and formulas at the Data Building Procedure - let singularVariableName // Name of the variable for this product - let recordDefinition // Record as defined by the user at the UI - let fileContent // Here we store the contents of the new data built just before writing it to a file. + let jsonData // Just build data as Json objects + let outputData // Data built as a result of applying user defined code and formulas at the Data Building Procedure + let singularVariableName // Name of the variable for this product + let recordDefinition // Record as defined by the user at the UI + let fileContent // Here we store the contents of the new data built just before writing it to a file. + let resultsWithIrregularPeriods // A product will have irregular periods when the User Code inserts new result records at will, in contrast with normal procedure where the platform insert one record per loop execution. /* For each outputDatasetNode in our process output, we will build the information based on our input products. @@ -148,12 +148,17 @@ recordDefinition = outputDatasetNode.referenceParent.parentNode.record singularVariableName = outputDatasetNode.referenceParent.parentNode.code.singularVariableName + /* Check Irregular Periods */ + if (outputDatasetNode.referenceParent.parentNode.dataBuilding.loop.code.code.indexOf('results.push') >= 0) { + resultsWithIrregularPeriods = true + } + /* Build the data */ - jsonData = commons.dataBuildingProcedure(products, mainDependency, recordDefinition, outputDatasetNode.referenceParent.parentNode.dataBuilding, singularVariableName, timePeriod) + jsonData = dataBuildingProcedure(products, mainDependency, recordDefinition, outputDatasetNode.referenceParent.parentNode.dataBuilding, singularVariableName, timePeriod, resultsWithIrregularPeriods) /* Add the calculated properties */ if (outputDatasetNode.referenceParent.parentNode.calculations !== undefined) { - outputData = commons.calculationsProcedure(jsonData, recordDefinition, outputDatasetNode.referenceParent.parentNode.calculations, singularVariableName, timePeriod) + outputData = calculationsProcedure(jsonData, recordDefinition, outputDatasetNode.referenceParent.parentNode.calculations, singularVariableName, timePeriod) } else { outputData = jsonData } @@ -165,6 +170,7 @@ for (let i = 0; i < outputDatasets.length; i++) { let outputDatasetNode = outputDatasets[i] let outputData = products[outputDatasetNode.referenceParent.parentNode.code.pluralVariableName] + let resultsWithIrregularPeriods // A product will have irregular periods when the User Code inserts new result records at will, in contrast with normal procedure where the platform insert one record per loop execution. let contextSummary = {} /* Some very basic validations that we have all the information needed. */ @@ -210,6 +216,11 @@ return } + /* Check Irregular Periods */ + if (outputDatasetNode.referenceParent.parentNode.dataBuilding.loop.code.code.indexOf('results.push') >= 0) { + resultsWithIrregularPeriods = true + } + /* Simplifying the access to basic info */ contextSummary.dataset = outputDatasetNode.referenceParent.code.codeName @@ -224,18 +235,202 @@ } contextSummary.dataSetVersion = "dataSet.V1" - let fileContent = generateFileContent(outputData, outputDatasetNode.referenceParent.parentNode.record) + let fileContent = generateFileContent(outputData, outputDatasetNode.referenceParent.parentNode.record, resultsWithIrregularPeriods) writeFile(contextSummary, fileContent) } + function jsonifyDataFile(dataFile, recordDefinition) { + + /* + This function has as an input the raw data on files and creates with it an array of JSON objects + with not calculated properties for later being consumed by Formulas + */ + + let jsonifiedArray = [] + + for (let i = 0; i < dataFile.length; i++) { + + let record = {} + for (let j = 0; j < recordDefinition.properties.length; j++) { + let property = recordDefinition.properties[j] + if (property.code.isCalculated !== true) { + record[property.code.codeName] = dataFile[i][j] + } + } + + jsonifiedArray.push(record); + } + + return jsonifiedArray + } + + function calculationsProcedure(jsonArray, recordDefinition, calculationsProcedure, variableName, timePeriod) { + + /* + This function has as an input an array of JSON objects, and it adds calculated properties to + complete the set of properties that will be available for Formulas. + */ + + let system = { // These are the available system variables to be used in User Code and Formulas + timePeriod: timePeriod, + ONE_DAY_IN_MILISECONDS: ONE_DAY_IN_MILISECONDS + } + let variable = {} // This is the structure where the user will define its own variables that will be shared across different code blocks and formulas. + let results = [] + + /* This is Initialization Code */ + if (calculationsProcedure.initialization !== undefined) { + if (calculationsProcedure.initialization.code !== undefined) { + try { + eval(calculationsProcedure.initialization.code.code) + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> initialization -> Error executing User Code. Error = " + err.stack) + logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> initialization -> Error executing User Code. Code = " + calculationsProcedure.initialization.code.code); + throw ("Error Executing User Code.") + } + } + } + + /* This is Initialization Code */ + if (calculationsProcedure.loop !== undefined) { + if (calculationsProcedure.loop.code !== undefined) { + for (let index = 0; index < jsonArray.length; index++) { + + let product = {} + product[variableName] = jsonArray[index] + + /* This is Loop Code */ + try { + eval(calculationsProcedure.loop.code.code) + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> loop -> Error executing User Code. Error = " + err.stack) + logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> loop -> Error executing User Code. product = " + JSON.stringify(product)) + logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> loop -> Error executing User Code. Code = " + calculationsProcedure.loop.code.code); + throw ("Error Executing User Code.") + } + + /* For each calculated property we apply its formula*/ + for (let j = 0; j < recordDefinition.properties.length; j++) { + let property = recordDefinition.properties[j] + if (property.code.isCalculated === true) { + if (property.formula !== undefined) { + if (property.formula.code !== undefined) { + try { + let newValue = eval(property.formula.code) + let currentRecord = product[variableName] + currentRecord[property.code.codeName] = newValue + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> loop -> formula -> Error executing User Code. Error = " + err.stack) + logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> loop -> formula -> Error executing User Code. product = " + JSON.stringify(product)) + logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> loop -> formula -> Error executing User Code. Code = " + property.formula.code); + throw ("Error Executing User Code.") + } + } + } + } + } + + /* Adding the new element to the resulting array */ + results.push(product[variableName]); + } + } + } + return results + } + + function dataBuildingProcedure(products, mainDependency, recordDefinition, dataBuildingProcedure, variableName, timePeriod, resultsWithIrregularPeriods) { + + /* + This function has as an input the products object, with all the information + of all products calculated so far by the process. Based on that information + the function will evaluate user supplied code and formulas in order to build + a new set of information. + */ + + let system = { // These are the available system variables to be used in User Code and Formulas + timePeriod: timePeriod, + ONE_DAY_IN_MILISECONDS: ONE_DAY_IN_MILISECONDS + } + let variable = {} // This is the structure where the user will define its own variables that will be shared across different code blocks and formulas. + let results = [] + + /* This is Initialization Code */ + if (dataBuildingProcedure.initialization !== undefined) { + if (dataBuildingProcedure.initialization.code !== undefined) { + try { + eval(dataBuildingProcedure.initialization.code.code) + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> initialization -> Error executing User Code. Error = " + err.stack) + logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> initialization -> Error executing User Code. Code = " + dataBuildingProcedure.initialization.code.code); + throw ("Error Executing User Code.") + } + } + } + + /* This is Initialization Code */ + if (dataBuildingProcedure.loop !== undefined) { + if (dataBuildingProcedure.loop.code !== undefined) { + for (let index = 0; index < mainDependency.length; index++) { + + let record = { + previous: mainDependency[index - 1], + current: mainDependency[index], + next: mainDependency[index + 1] + } + + let product = {} + product[variableName] = {} + + /* This is Loop Code */ + try { + eval(dataBuildingProcedure.loop.code.code) + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> loop -> Error executing User Code. Error = " + err.stack) + logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> loop -> Error executing User Code. product = " + JSON.stringify(product)) + logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> loop -> Error executing User Code. Code = " + dataBuildingProcedure.loop.code.code); + throw ("Error Executing User Code.") + } + + /* For each non-calculated property we apply its formula*/ + for (let j = 0; j < recordDefinition.properties.length; j++) { + let property = recordDefinition.properties[j] + if (property.code.isCalculated !== true) { + if (property.formula !== undefined) { + if (property.formula.code !== undefined) { + try { + let newValue = eval(property.formula.code) + let currentRecord = product[variableName] + currentRecord[property.code.codeName] = newValue + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> loop -> formula -> Error executing User Code. Error = " + err.stack) + logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> loop -> formula -> Error executing User Code. product = " + JSON.stringify(product)) + logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> loop -> formula -> Error executing User Code. Code = " + property.formula.code); + throw ("Error Executing User Code.") + } + } + } + } + } + + /* If within the code the new data structure was not yet pushed to the results array, we do it */ + if (resultsWithIrregularPeriods !== true) { + /* Adding the new element to the resulting array */ + results.push(product[variableName]); + } + } + } + } + return results + } + function anotherFileWritten() { totalFilesWritten++ - if (totalFilesWritten === processConfig.updatesDatasets.length) { + if (totalFilesWritten === outputDatasets.length) { callBackFunction(global.DEFAULT_OK_RESPONSE); } } - function generateFileContent(records, recordDefinition) { + function generateFileContent(records, recordDefinition, resultsWithIrregularPeriods) { try { @@ -246,6 +441,32 @@ for (let i = 0; i < records.length; i++) { let record = records[i]; + + if (processingDailyFiles === true) { + + if (resultsWithIrregularPeriods === true) { + /* + Here we have an special problem that occurs when an object spans several time peridos. If not taken care of + it can happen that the object gets splitted between 2 days, which we dont want since it would loose some of + its properties. + + To solve this issue, we wont save objects which ends at the last candle of the day, because we will save it + at the next day, in whole, even if it starts in the previous day. + */ + + let lastInstantOdDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1; + + if (record.end < currentDay.valueOf() - 1) { continue; } + if (record.end === lastInstantOdDay) { continue; } + } else { + /* + The normal situation is that objects are respecting the time size of its main dependency, in which case we only + care of not adding objects of the previous day we are currently processing (while on daily files) + */ + if (record.end < currentDay.valueOf()) { continue; } + } + } + fileContent = fileContent + recordSeparator + '[' let propertySeparator = "" for (let j = 0; j < recordDefinition.properties.length; j++) { @@ -281,9 +502,14 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFile -> Entering function."); } let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + let dateForPath = '' + + if (processingDailyFiles === true) { + dateForPath = "/" + currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); + } let filePathRoot = contextSummary.devTeam + "/" + contextSummary.bot + "." + contextSummary.botVersion.major + "." + contextSummary.botVersion.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + contextSummary.dataSetVersion; - let filePath = filePathRoot + "/Output/" + contextSummary.product + "/" + contextSummary.dataset + "/" + outputPeriodLabel; + let filePath = filePathRoot + "/Output/" + contextSummary.product + "/" + contextSummary.dataset + "/" + outputPeriodLabel + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(contextSummary.devTeam, filePath, fileContent + '\n', onFileCreated); diff --git a/IndicatorBotCommons.js b/IndicatorBotCommons.js deleted file mode 100644 index 384cf0a2f..000000000 --- a/IndicatorBotCommons.js +++ /dev/null @@ -1,201 +0,0 @@ -exports.newIndicatorBotCommons = function newIndicatorBotCommons(bot, logger, UTILITIES) { - - const FULL_LOG = true; - const LOG_FILE_CONTENT = false; - - const MODULE_NAME = "Commons"; - const GMT_SECONDS = ':00.000 GMT+0000'; - const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; - - let thisObject = { - jsonifyDataFile: jsonifyDataFile, - calculationsProcedure: calculationsProcedure, - dataBuildingProcedure: dataBuildingProcedure - }; - - return thisObject; - - function jsonifyDataFile(dataFile, recordDefinition) { - - /* - This function has as an input the raw data on files and creates with it an array of JSON objects - with not calculated properties for later being consumed by Formulas - */ - - let jsonifiedArray = [] - - for (let i = 0; i < dataFile.length; i++) { - - let record = {} - for (let j = 0; j < recordDefinition.properties.length; j++) { - let property = recordDefinition.properties[j] - if (property.code.isCalculated !== true) { - record[property.code.codeName] = dataFile[i][j] - } - } - - jsonifiedArray.push(record); - } - - return jsonifiedArray - } - - function calculationsProcedure(jsonArray, recordDefinition, calculationsProcedure, variableName, timePeriod) { - - /* - This function has as an input an array of JSON objects, and it adds calculated properties to - complete the set of properties that will be available for Formulas. - */ - - let system = { // These are the available system variables to be used in User Code and Formulas - timePeriod: timePeriod, - ONE_DAY_IN_MILISECONDS: ONE_DAY_IN_MILISECONDS - } - let variable = {} // This is the structure where the user will define its own variables that will be shared across different code blocks and formulas. - let results = [] - - /* This is Initialization Code */ - if (calculationsProcedure.initialization !== undefined) { - if (calculationsProcedure.initialization.code !== undefined) { - try { - eval(calculationsProcedure.initialization.code.code) - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> initialization -> Error executing User Code. Error = " + err.stack) - logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> initialization -> Error executing User Code. Code = " + calculationsProcedure.initialization.code.code); - throw("Error Executing User Code.") - } - } - } - - /* This is Initialization Code */ - if (calculationsProcedure.loop !== undefined) { - if (calculationsProcedure.loop.code !== undefined) { - for (let index = 0; index < jsonArray.length; index++) { - - let product = {} - product[variableName] = jsonArray[index] - - /* This is Loop Code */ - try { - eval(calculationsProcedure.loop.code.code) - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> loop -> Error executing User Code. Error = " + err.stack) - logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> loop -> Error executing User Code. product = " + JSON.stringify(product)) - logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> loop -> Error executing User Code. Code = " + calculationsProcedure.loop.code.code); - throw ("Error Executing User Code.") - } - - /* For each calculated property we apply its formula*/ - for (let j = 0; j < recordDefinition.properties.length; j++) { - let property = recordDefinition.properties[j] - if (property.code.isCalculated === true) { - if (property.formula !== undefined) { - if (property.formula.code !== undefined) { - try { - let newValue = eval(property.formula.code) - let currentRecord = product[variableName] - currentRecord[property.code.codeName] = newValue - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> loop -> formula -> Error executing User Code. Error = " + err.stack) - logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> loop -> formula -> Error executing User Code. product = " + JSON.stringify(product)) - logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> loop -> formula -> Error executing User Code. Code = " + property.formula.code); - throw ("Error Executing User Code.") - } - } - } - } - } - - /* Adding the new element to the resulting array */ - results.push(product[variableName]); - } - } - } - return results - } - - function dataBuildingProcedure(products, mainDependency, recordDefinition, dataBuildingProcedure, variableName, timePeriod) { - - /* - This function has as an input the products object, with all the information - of all products calculated so far by the process. Based on that information - the function will evaluate user supplied code and formulas in order to build - a new set of information. - */ - - let system = { // These are the available system variables to be used in User Code and Formulas - timePeriod: timePeriod, - ONE_DAY_IN_MILISECONDS: ONE_DAY_IN_MILISECONDS - } - let variable = {} // This is the structure where the user will define its own variables that will be shared across different code blocks and formulas. - let results = [] - - /* This is Initialization Code */ - if (dataBuildingProcedure.initialization !== undefined) { - if (dataBuildingProcedure.initialization.code !== undefined) { - try { - eval(dataBuildingProcedure.initialization.code.code) - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> initialization -> Error executing User Code. Error = " + err.stack) - logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> initialization -> Error executing User Code. Code = " + dataBuildingProcedure.initialization.code.code); - throw ("Error Executing User Code.") - } - } - } - - /* This is Initialization Code */ - if (dataBuildingProcedure.loop !== undefined) { - if (dataBuildingProcedure.loop.code !== undefined) { - for (let index = 0; index < mainDependency.length; index++) { - - let record = { - previous: mainDependency[index-1], - current: mainDependency[index], - next: mainDependency[index+1] - } - - let product = {} - product[variableName] = {} - - /* This is Loop Code */ - try { - eval(dataBuildingProcedure.loop.code.code) - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> loop -> Error executing User Code. Error = " + err.stack) - logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> loop -> Error executing User Code. product = " + JSON.stringify(product)) - logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> loop -> Error executing User Code. Code = " + dataBuildingProcedure.loop.code.code); - throw ("Error Executing User Code.") - } - - /* For each non-calculated property we apply its formula*/ - for (let j = 0; j < recordDefinition.properties.length; j++) { - let property = recordDefinition.properties[j] - if (property.code.isCalculated !== true) { - if (property.formula !== undefined) { - if (property.formula.code !== undefined) { - try { - let newValue = eval(property.formula.code) - let currentRecord = product[variableName] - currentRecord[property.code.codeName] = newValue - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> loop -> formula -> Error executing User Code. Error = " + err.stack) - logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> loop -> formula -> Error executing User Code. product = " + JSON.stringify(product)) - logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> loop -> formula -> Error executing User Code. Code = " + property.formula.code); - throw ("Error Executing User Code.") - } - } - } - } - } - - /* If within the code the new data structure was not yet pushed to the results array, we do it */ - if (dataBuildingProcedure.loop.code.code.indexOf('results.push') < 0) { - /* Adding the new element to the resulting array */ - results.push(product[variableName]); - } - } - } - } - return results - } -}; diff --git a/IndicatorBotDaily.js b/IndicatorBotDaily.js deleted file mode 100644 index c06f99347..000000000 --- a/IndicatorBotDaily.js +++ /dev/null @@ -1,405 +0,0 @@ -exports.newIndicatorBotDaily = function newIndicatorBotDaily(bot, logger, COMMONS, UTILITIES, FILE_STORAGE) { - - const FULL_LOG = true; - const LOG_FILE_CONTENT = false; - const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; - - const MODULE_NAME = "User Bot"; - - const BOLLINGER_CHANNELS_FOLDER_NAME = "Bollinger-Channels"; - const BOLLINGER_STANDARD_CHANNELS_FOLDER_NAME = "Bollinger-Standard-Channels"; - const BOLLINGER_SUB_CHANNELS_FOLDER_NAME = "Bollinger-Sub-Channels"; - const BOLLINGER_STANDARD_SUB_CHANNELS_FOLDER_NAME = "Bollinger-Standard-Sub-Channels"; - - const commons = COMMONS.newIndicatorBotCommons(bot, logger, UTILITIES); - - thisObject = { - initialize: initialize, - start: start - }; - - let utilities = UTILITIES.newCloudUtilities(bot, logger); - - let fileStorage = FILE_STORAGE.newFileStorage(logger); - let processConfig; - - return thisObject; - - function initialize(pProcessConfig, callBackFunction) { - - try { - - logger.fileName = MODULE_NAME; - logger.initialize(); - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } - - processConfig = pProcessConfig; - callBackFunction(global.DEFAULT_OK_RESPONSE); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function start(dataFiles, timePeriod, outputPeriodLabel, currentDay, startDate, endDate, interExecutionMemory, callBackFunction) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); } - - let market = global.MARKET; - let dataFile; - - let bands = []; - let channels = []; - let standardChannels = []; - let subChannels = []; - let standardSubChannels = []; - - dataFile = dataFiles[0]; // We only need the bollinger bands. - - commons.buildBandsArray(dataFile, bands, timePeriod, callBackFunction); - commons.buildChannels(bands, channels, callBackFunction); - commons.buildStandardChannels(bands, standardChannels, callBackFunction); - commons.buildSubChannels(bands, subChannels, callBackFunction); - commons.buildStandardSubChannels(bands, standardSubChannels, callBackFunction); - - writeChannelsFile(); - - function writeChannelsFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeChannelsFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < channels.length; i++) { - - let channel = channels[i]; - - /* - Here we have an special problem that occurs when an object spans several time peridos. If not taken care of - it can happen that the object gets splitted between 2 days, which we dont want since it would loose some of - its properties. - - To solve this issue, we wont save objects which ends at the last candle of the day, because we will save it - at the next day, in whole, even if it starts in the previous day. - */ - - let lastInstantOdDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1; - - if (channel.end < currentDay.valueOf() - 1) { continue; } - if (channel.end === lastInstantOdDay) { continue; } - - fileContent = fileContent + separator + '[' + - - channel.begin + "," + - channel.end + "," + - '"' + channel.direction + '"' + "," + - channel.period + "," + - channel.firstMovingAverage + "," + - channel.lastMovingAverage + "," + - channel.firstDeviation + "," + - channel.lastDeviation + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + BOLLINGER_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeChannelsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeChannelsFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeChannelsFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeChannelsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeChannelsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - writeStandardChannelsFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeChannelsFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeChannelsFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeStandardChannelsFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStandardChannelsFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (i = 0; i < standardChannels.length; i++) { - - let channel = standardChannels[i]; - - if (channel.end < currentDay.valueOf()) { continue; } - - fileContent = fileContent + separator + '[' + - - channel.begin + "," + - channel.end + "," + - '"' + channel.direction + '"' + "," + - channel.period + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + BOLLINGER_STANDARD_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStandardChannelsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStandardChannelsFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeStandardChannelsFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeStandardChannelsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeStandardChannelsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - writeSubChannelsFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStandardChannelsFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStandardChannelsFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeSubChannelsFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeSubChannelsFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (i = 0; i < subChannels.length; i++) { - - let channel = subChannels[i]; - - /* - Here we have an special problem that occurs when an object spans several time peridos. If not taken care of - it can happen that the object gets splitted between 2 days, which we dont want since it would loose some of - its properties. - - To solve this issue, we wont save objects which ends at the last candle of the day, because we will save it - at the next day, in whole, even if it starts in the previous day. - */ - - let lastInstantOdDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1; - - if (channel.end < currentDay.valueOf() - 1) { continue; } - if (channel.end === lastInstantOdDay) { continue; } - - fileContent = fileContent + separator + '[' + - - channel.begin + "," + - channel.end + "," + - '"' + channel.direction + '"' + "," + - '"' + channel.slope + '"' + "," + - channel.period + "," + - channel.firstMovingAverage + "," + - channel.lastMovingAverage + "," + - channel.firstDeviation + "," + - channel.lastDeviation + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + BOLLINGER_SUB_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeSubChannelsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeSubChannelsFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeSubChannelsFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeSubChannelsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeSubChannelsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - writeStandardSubChannelsFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeSubChannelsFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeSubChannelsFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeStandardSubChannelsFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStandardSubChannelsFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (i = 0; i < standardSubChannels.length; i++) { - - let channel = standardSubChannels[i]; - - if (channel.end < currentDay.valueOf()) { continue; } - - fileContent = fileContent + separator + '[' + - - channel.begin + "," + - channel.end + "," + - '"' + channel.direction + '"' + "," + - '"' + channel.slope + '"' + "," + - channel.period + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - } - - fileContent = "[" + fileContent + "]"; - - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + BOLLINGER_STANDARD_SUB_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStandardSubChannelsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStandardSubChannelsFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeStandardSubChannelsFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeStandardSubChannelsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeStandardSubChannelsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - callBackFunction(global.DEFAULT_OK_RESPONSE); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStandardSubChannelsFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStandardSubChannelsFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } -}; diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js index 33588ac3b..e9c5c10df 100644 --- a/MultiPeriodDaily.js +++ b/MultiPeriodDaily.js @@ -19,7 +19,7 @@ let datasets = []; let dataFiles = []; - let usertBot; + let botInstance; let fileStorage = FILE_STORAGE.newFileStorage(logger); @@ -46,7 +46,7 @@ let key; let dataset; - let dependency = dataDependencies.config[i]; + let dependency = dataDependencies.nodeArray[i]; key = dependency.devTeam + "-" + dependency.bot + "-" + @@ -60,11 +60,10 @@ } - let COMMONS_MODULE = require("./IndicatorBotCommons") - let USER_BOT_MODULE = require("./IndicatorBotDaily") + let USER_BOT_MODULE = require("./IndicatorBot") - usertBot = USER_BOT_MODULE.newIndicatorBotDaily(bot, logger, COMMONS_MODULE, UTILITIES, FILE_STORAGE); - usertBot.initialize(processConfig, callBackFunction); + botInstance = USER_BOT_MODULE.newIndicatorBot(bot, logger, UTILITIES, FILE_STORAGE); + botInstance.initialize(callBackFunction); } catch (err) { logger.write(MODULE_NAME, "[ERROR] initialize -> err = "+ err.stack); @@ -77,7 +76,7 @@ dataFiles = undefined statusDependencies = undefined dataDependencies = undefined - usertBot = undefined + botInstance = undefined fileStorage = undefined processConfig = undefined thisObject = undefined @@ -602,7 +601,7 @@ const timePeriod = global.dailyFilePeriods[n][0]; const outputPeriodLabel = global.dailyFilePeriods[n][1]; - usertBot.start( + botInstance.start( dataFiles, timePeriod, outputPeriodLabel, diff --git a/MultiPeriodMarket.js b/MultiPeriodMarket.js index a5f286233..8133547bb 100644 --- a/MultiPeriodMarket.js +++ b/MultiPeriodMarket.js @@ -17,7 +17,7 @@ let datasets = []; let dataFiles = []; - let usertBot; + let botInstance; let processConfig; @@ -54,11 +54,10 @@ } - let COMMONS_MODULE = require("./IndicatorBotCommons") - let USER_BOT_MODULE = require("./IndicatorBotMarket") + let USER_BOT_MODULE = require("./IndicatorBot") - usertBot = USER_BOT_MODULE.newIndicatorBotMarket(bot, logger, COMMONS_MODULE, UTILITIES, FILE_STORAGE); - usertBot.initialize(processConfig, callBackFunction); + botInstance = USER_BOT_MODULE.newIndicatorBot(bot, logger, UTILITIES, FILE_STORAGE); + botInstance.initialize(callBackFunction); } catch (err) { logger.write(MODULE_NAME, "[ERROR] initialize -> err = "+ err.stack); @@ -71,7 +70,7 @@ dataFiles = undefined statusDependencies = undefined dataDependencies = undefined - usertBot = undefined + botInstance = undefined processConfig = undefined thisObject = undefined } @@ -256,12 +255,14 @@ const timePeriod = global.marketFilesPeriods[n][0]; const outputPeriodLabel = global.marketFilesPeriods[n][1]; - usertBot.start( + botInstance.start( dataFiles, timePeriod, outputPeriodLabel, + undefined, contextVariables.dateBeginOfMarket, contextVariables.dateEndOfMarket, + undefined, onBotFinished); function onBotFinished(err) { diff --git a/Project.njsproj b/Project.njsproj index 5128f194e..bfe531e65 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -25,17 +25,9 @@ Code - - Code - - - Code - + - - Code - Code