diff --git a/Commons.js b/Commons.js index 0678ae4ba..917df2f7c 100644 --- a/Commons.js +++ b/Commons.js @@ -8,11 +8,9 @@ const GMT_SECONDS = ':00.000 GMT+0000'; let thisObject = { - initializeData: initializeData, runSimulation: runSimulation, - buildLRC: buildLRC, - buildPercentageBandwidthMap: buildPercentageBandwidthMap, - buildBollingerBandsMap: buildBollingerBandsMap, + buildPercentageBandwidthArray: buildPercentageBandwidthArray, + buildBollingerBandsArray: buildBollingerBandsArray, buildBollingerChannelsArray: buildBollingerChannelsArray, buildBollingerSubChannelsArray: buildBollingerSubChannelsArray, buildCandles: buildCandles @@ -20,30 +18,19 @@ let utilities = UTILITIES.newCloudUtilities(bot, logger); - let LRCMap = new Map(); - let percentageBandwidthMap = new Map(); - let bollingerBandsMap = new Map(); - let bollingerChannelsArray = []; - let bollingerSubChannelsArray = []; + let percentageBandwidthAt = {} + let bollingerBandsAt = {} + let bollingerChannelsAt = {} + let bollingerSubChannelsAt = {} + let candlesAt = {} - let candles = []; const definition = global.DEFINITION return thisObject; - function initializeData() { - - LRCMap = new Map(); - percentageBandwidthMap = new Map(); - bollingerBandsMap = new Map(); - bollingerChannelsArray = []; - bollingerSubChannelsArray = []; - - candles = []; - } - async function runSimulation( timePeriod, + timePeriodLabel, currentDay, startDate, endDate, @@ -241,7 +228,6 @@ /* In some cases we need to know if we are positioned at the last candle of the calendar day, for that we need these variables. */ let lastInstantOfTheDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1; - let lastCandle = candles[candles.length - 1]; /* The following counters need to survive multiple executions of the similator and keep themselves reliable. @@ -550,9 +536,18 @@ yesterday.anualizedRateOfReturn = anualizedRateOfReturn; } - /* Main Simulation Loop: We go thourgh all the candles at this time period. */ - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Main Simulation Loop -> candles.length = " + candles.length); } + /* Main Array and Maps */ + let candles = candlesAt[timePeriodLabel] + let percentageBandwidthArray = percentageBandwidthAt[timePeriodLabel] + let bollingerBandsArray = bollingerBandsAt[timePeriodLabel] + let bollingerChannelsArray = bollingerChannelsAt[timePeriodLabel] + let bollingerSubChannelsArray = bollingerSubChannelsAt[timePeriodLabel] + + /* Last Candle */ + let lastCandle = candles[candles.length - 1]; + + /* Main Simulation Loop: We go thourgh all the candles at this time period. */ let i initializeLoop() @@ -568,16 +563,29 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Processing candle # " + i); } let candle = candles[i]; + let percentageBandwidth = getElement(percentageBandwidthArray, candle); + let bollingerBand = getElement(bollingerBandsArray, candle); + let bollingerChannel = getElement(bollingerChannelsArray, candle); + let bollingerSubChannel = getElement(bollingerSubChannelsArray, candle); + + let chart = {} + + for (let j = 0; j < global.dailyFilePeriods.length; j++) { + + let mapKey = dailyFilePeriods[j][1] + chart[mapKey] = {} + chart[mapKey].candle = getElement(candlesAt[mapKey], candle); + chart[mapKey].percentageBandwidth = getElement(percentageBandwidthAt[mapKey], candle); + chart[mapKey].bollingerBand = getElement(bollingerBandsAt[mapKey], candle); + chart[mapKey].bollingerChannel = getElement(bollingerChannelsAt[mapKey], candle); + chart[mapKey].bollingerSubChannel = getElement(bollingerSubChannelsAt[mapKey], candle); + } + + let positionedAtYesterday = (candle.end < currentDay.valueOf()) if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Candle Begin @ " + (new Date(candle.begin)).toLocaleString()) } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Candle End @ " + (new Date(candle.end)).toLocaleString()) } - let percentageBandwidth = percentageBandwidthMap.get(candle.begin); - let bollingerBand = bollingerBandsMap.get(candle.begin); - let bollingerChannel = getElement(bollingerChannelsArray, candle.begin, candle.end); - let bollingerSubChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); - let positionedAtYesterday = (candle.end < currentDay.valueOf()) - /* Assistant Info */ let ticker = { @@ -586,8 +594,6 @@ last: candle.close } - //let LRC = LRCMap.get(candle.begin); - /* If any of the needed indicators is missing, then that period is not calculated */ if (candle.end < initialDate.valueOf()) { @@ -1088,12 +1094,14 @@ */ value = false - if (node.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { + if (node.code.indexOf('previous') > -1 && err.message.indexOf('of undefined') > -1 || + node.code.indexOf('chart') > -1 && err.message.indexOf('of undefined') > -1 + ) { /* We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. */ } else { - node.error = err.message + node.error = err.message + " @ " + (new Date(candle.begin)).toLocaleString() } } @@ -1201,10 +1209,10 @@ } else { let stopRunningDate = new Date(candle.begin) if (balance < minimumBalance) { - tradingSystem.error = "Min Balance @ " + stopRunningDate.toUTCString() + tradingSystem.error = "Min Balance @ " + stopRunningDate.toLocaleString() } if (balance > maximumBalance) { - tradingSystem.error = "Max Balance @ " + stopRunningDate.toUTCString() + tradingSystem.error = "Max Balance @ " + stopRunningDate.toLocaleString() } } } @@ -2612,19 +2620,36 @@ } - function getElement(pArray, begin, end) { + function getElement(pArray, currentCandle) { let element; - for (let i = 0; i < pArray.length; i++) { - element = pArray[i]; - if (begin >= element.begin && end <= element.end) { + if (currentCandle.end === element.end) { // when there is an exact match at the end we take that element return element - } + } else { + if ( + i > 0 && + element.end > currentCandle.end + ) + { + let previousElement = pArray[i - 1] + if (previousElement.end < currentCandle.end) { + return previousElement // If one elements goes into the future of currentCandle, then we stop and take the previous element. + } else { + return + } + } + if ( + i === pArray.length - 1 // If we reach the end of the array, then we return the last element. + && + element.end < currentCandle.end + ) { + return element + } + } } - return } } @@ -2634,58 +2659,13 @@ } } - function buildLRC(dataFile, callBackFunction) { + function buildPercentageBandwidthArray(dataFile, timePeriodLabel, callBackFunction) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildLRC -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildPercentageBandwidthArray -> Entering function."); } try { - let previous; - - for (let i = 0; i < dataFile.length; i++) { - - let LRC = { - begin: dataFile[i][0], - end: dataFile[i][1], - _15: dataFile[i][2], - _30: dataFile[i][3], - _60: dataFile[i][4] - }; - - if (previous !== undefined) { - - if (previous._15 > LRC._15) { LRC.direction15 = 'Down'; } - if (previous._15 < LRC._15) { LRC.direction15 = 'Up'; } - if (previous._15 === LRC._15) { LRC.direction15 = 'Side'; } - - if (previous._30 > LRC._30) { LRC.direction30 = 'Down'; } - if (previous._30 < LRC._30) { LRC.direction30 = 'Up'; } - if (previous._30 === LRC._30) { LRC.direction30 = 'Side'; } - - if (previous._60 > LRC._60) { LRC.direction60 = 'Down'; } - if (previous._60 < LRC._60) { LRC.direction60 = 'Up'; } - if (previous._60 === LRC._60) { LRC.direction60 = 'Side'; } - - } - - LRC.previous = previous; - - LRCMap.set(LRC.begin, LRC); - - previous = LRC; - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] buildLRC -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildPercentageBandwidthMap(dataFile, callBackFunction) { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildPercentageBandwidthMap -> Entering function."); } - - try { + let percentageBandwidthArray = []; let previous; @@ -2709,23 +2689,29 @@ percentageBandwidth.previous = previous; - percentageBandwidthMap.set(percentageBandwidth.begin, percentageBandwidth); + percentageBandwidthArray.push(percentageBandwidth); previous = percentageBandwidth; + } + + percentageBandwidthAt[timePeriodLabel] = percentageBandwidthArray + } catch (err) { - logger.write(MODULE_NAME, "[ERROR] buildPercentageBandwidthMap -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] buildPercentageBandwidthArray -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - function buildBollingerBandsMap(dataFile, callBackFunction) { + function buildBollingerBandsArray(dataFile, timePeriodLabel, callBackFunction) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildBollingerBandsMap -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildBollingerBandsArray -> Entering function."); } try { + let bollingerBandsArray = []; + let previous; for (let i = 0; i < dataFile.length; i++) { @@ -2748,23 +2734,28 @@ bollingerBand.previous = previous; - bollingerBandsMap.set(bollingerBand.begin, bollingerBand); + bollingerBandsArray.push(bollingerBand); previous = bollingerBand; } + + bollingerBandsAt[timePeriodLabel] = bollingerBandsArray + } catch (err) { - logger.write(MODULE_NAME, "[ERROR] buildBollingerBandsMap -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] buildBollingerBandsArray -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - function buildBollingerChannelsArray(dataFile, callBackFunction) { + function buildBollingerChannelsArray(dataFile, timePeriodLabel, callBackFunction) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildBollingerChannelsArray -> Entering function."); } try { + let bollingerChannelsArray = []; + let previous; for (let i = 0; i < dataFile.length; i++) { @@ -2782,6 +2773,9 @@ previous = bollingerChannel; } + + bollingerChannelsAt[timePeriodLabel] = bollingerChannelsArray + } catch (err) { logger.write(MODULE_NAME, "[ERROR] buildBollingerChannelsArray -> err = " + err.stack); @@ -2789,11 +2783,12 @@ } } - function buildBollingerSubChannelsArray(dataFile, callBackFunction) { + function buildBollingerSubChannelsArray(dataFile, timePeriodLabel, callBackFunction) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildBollingerSubChannelsArray -> Entering function."); } try { + let bollingerSubChannelsArray = []; let previous; @@ -2817,6 +2812,9 @@ previous = bollingerSubChannel; } + + bollingerSubChannelsAt[timePeriodLabel] = bollingerSubChannelsArray + } catch (err) { logger.write(MODULE_NAME, "[ERROR] buildBollingerSubChannelsArray -> err = " + err.stack); @@ -2824,11 +2822,12 @@ } } - function buildCandles(dataFile, callBackFunction) { + function buildCandles(dataFile, timePeriodLabel, callBackFunction) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildCandles -> Entering function."); } try { + let candles = []; let previous; @@ -2863,6 +2862,8 @@ previous = candle; } + + candlesAt[timePeriodLabel] = candles } catch (err) { logger.write(MODULE_NAME, "[ERROR] buildCandles -> err = " + err.stack); diff --git a/Multi-Period/User.Bot.js b/Multi-Period/User.Bot.js index d2d1ad6a0..5b47ac467 100644 --- a/Multi-Period/User.Bot.js +++ b/Multi-Period/User.Bot.js @@ -47,7 +47,7 @@ } } - function start(dataFiles, timePeriod, outputPeriodLabel, currentDay, startDate, endDate, interExecutionMemory, callBackFunction) { + function start(multiPeriodDataFiles, timePeriod, timePeriodLabel, currentDay, startDate, endDate, interExecutionMemory, callBackFunction) { try { @@ -64,44 +64,48 @@ let tradingSystem = {}; - commons.initializeData(); + for (let j = 0; j < global.dailyFilePeriods.length; j++) { - for (let i = 0; i < dataDependencies.config.length; i++) { + let mapKey = dailyFilePeriods[j][1] + let dataFiles = multiPeriodDataFiles.get(mapKey) - let dependency = dataDependencies.config[i]; - dataFile = dataFiles[i]; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Building Dataset for timePeriod = " + mapKey); } - switch (i) { - /* - case 0: { - commons.buildLRC(dataFile, callBackFunction); - break; - }*/ - case 0: { - commons.buildPercentageBandwidthMap(dataFile, callBackFunction); - break; - } - case 1: { - commons.buildBollingerBandsMap(dataFile, callBackFunction); - break; - } - case 2: { - commons.buildBollingerChannelsArray(dataFile, callBackFunction); - break; - } - case 3: { - commons.buildBollingerSubChannelsArray(dataFile, callBackFunction); - break; - } - case 4: { - commons.buildCandles(dataFile, callBackFunction); - break; + if (dataFiles) { + for (let i = 0; i < dataDependencies.config.length; i++) { + + let dependency = dataDependencies.config[i]; + dataFile = dataFiles[i]; + + switch (i) { + case 0: { + commons.buildPercentageBandwidthArray(dataFile, mapKey, callBackFunction); + break; + } + case 1: { + commons.buildBollingerBandsArray(dataFile, mapKey, callBackFunction); + break; + } + case 2: { + commons.buildBollingerChannelsArray(dataFile, mapKey, callBackFunction); + break; + } + case 3: { + commons.buildBollingerSubChannelsArray(dataFile, mapKey, callBackFunction); + break; + } + case 4: { + commons.buildCandles(dataFile, mapKey, callBackFunction); + break; + } + } } } } commons.runSimulation( timePeriod, + timePeriodLabel, currentDay, startDate, endDate, @@ -159,7 +163,7 @@ 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/" + EXECUTION_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + EXECUTION_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -274,7 +278,7 @@ 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/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -381,7 +385,7 @@ 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/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -469,7 +473,7 @@ 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/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -546,7 +550,7 @@ 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/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -626,7 +630,7 @@ 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/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); diff --git a/Project.njsproj b/Project.njsproj index 4cab6c556..6289f096d 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -38,6 +38,7 @@ + @@ -45,6 +46,9 @@ + + Code + diff --git a/this.bot.config.json b/this.bot.config.json index 34fc6f3b7..72f028270 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -313,7 +313,7 @@ "major": 1, "minor": 0 }, - "process": "Multi-Period-Daily", + "process": "Multi-Period", "dataSetVersion": "dataSet.V1" }, {