diff --git a/LowFrequencyTrading/TradingProcess.js b/LowFrequencyTrading/TradingProcess.js index f0ca70066..94d35921e 100644 --- a/LowFrequencyTrading/TradingProcess.js +++ b/LowFrequencyTrading/TradingProcess.js @@ -103,11 +103,19 @@ This variable tell us which day we are standing at, specially while working with Daily Files. From this Date is that we are going to load the Daily Files. */ - bot.simulationState.tradingEngine.current.episode.processDate.value = bot.SESSION.parameters.timeRange.config.initialDatetime.valueOf() + bot.simulationState.tradingEngine.current.episode.processDate.value = global.REMOVE_TIME(bot.SESSION.parameters.timeRange.config.initialDatetime).valueOf() } - /* This is the Date that is going to be used across the execution of this Trading Process */ - let tradingProcessDate = new Date(bot.simulationState.tradingEngine.current.episode.processDate.value) + /* + This is the Date that is going to be used across the execution of this Trading Process. + We need this because it has a different life cycle than the processData stored at the + Trading Engine data structure. This date has to remain the same during the whole execution + of the Trading Process until the end, inclusind the writting of Data Ranges and Status Reports. + The processDate of the Trading Engine data structure on the other hand can be changed during + the simulation loop, once we discover that all candles from a certain date have benn processed. + Here is the point where we sync one and the other. + */ + let tradingProcessDate = global.REMOVE_TIME(bot.simulationState.tradingEngine.current.episode.processDate.value) await processSingleFiles() await processMarketFiles() @@ -144,8 +152,8 @@ use it to save Output Files and later the Data Ranges. This is the point where the date calculated by the Simulation is applied at the Trading Process Level. */ - tradingProcessDate = new Date(bot.simulationState.tradingEngine.current.episode.processDate.value) - + tradingProcessDate = global.REMOVE_TIME(bot.simulationState.tradingEngine.current.episode.processDate.value) + await processDailyFiles() buildCharts(chart) @@ -171,8 +179,7 @@ let statusReport; /* We are going to use the start date as beging of market date. */ - contextVariables.dateBeginOfMarket = new Date(bot.SESSION.parameters.timeRange.config.initialDatetime) - + contextVariables.dateBeginOfMarket = global.REMOVE_TIME(bot.SESSION.parameters.timeRange.config.initialDatetime) /* Here we get the status report from the bot who knows which is the end of the market. */ @@ -560,7 +567,7 @@ async function writeDataRange(productCodeName) { let dataRange = { begin: contextVariables.dateBeginOfMarket.valueOf(), - end: tradingProcessDate + global.ONE_DAY_IN_MILISECONDS + end: tradingProcessDate.valueOf() + global.ONE_DAY_IN_MILISECONDS } let fileContent = JSON.stringify(dataRange); diff --git a/LowFrequencyTrading/TradingSimulation.js b/LowFrequencyTrading/TradingSimulation.js index f52b1a617..bbd13f85a 100644 --- a/LowFrequencyTrading/TradingSimulation.js +++ b/LowFrequencyTrading/TradingSimulation.js @@ -365,27 +365,31 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, tradin function checkNextCandle() { /* - Before reaching the last candle of the loop, we need to check that the next candle it is not the last candle. - We skip the candle at the head of the market because it has not closed yet. - For the special case of Daily Files, this means that the last candle of each day will never be processed. + We need to check that the candle we have just processed it is not the last candle. + The candle at the head of the market is already skipped from the loop because it has not closed yet. + Note: for Daily Files, this means that the last candle of each day will never be processed. */ - if (tradingEngine.current.episode.candle.index.value + 1 === candles.length - 1) { + if (tradingEngine.current.episode.candle.index.value === candles.length - 1) { /* When processing daily files, we need a mechanism to turn from one day to the next one. That mechanism is the one implemented here. If we detect that the next candle is the last candle of the day, we will advance current process day one day. By doing so, during the next execution, the simulation will receive the candles and indicators files of the next day. + + The first +1 is because array indexes are based on 0. + The second +1 is because we need to compare the next candle (remember that the loops allways avoid the + last candle of the dataset available.) */ let candlesPerDay = global.ONE_DAY_IN_MILISECONDS / sessionParameters.timeFrame.config.value if ( bot.processingDailyFiles && - tradingEngine.current.episode.candle.index.value + 1 === candlesPerDay - 1 + tradingEngine.current.episode.candle.index.value + 1 + 1 === candlesPerDay ) { /* - Here we found that the next candle of the Simulation is the last candle of the day. - It is time to move to the next day so as to receive next, the indicator files from + Here we found that the next candle of the dataset is the last candle of the day. + It is time to move to the next day so as to receive at the next execution, the indicator files from the next day. At the same time we will reset the index to be pointing to - the first candle of the new set we receive. The first candle of the next day starts + the first candle of the new dataset we shall receive. The first candle of the next day starts at index 0, so we will position the index now at zero. */ tradingEngine.current.episode.candle.index.value = 0 diff --git a/Session.js b/Session.js index ccc5d4e3d..42c7e84e7 100644 --- a/Session.js +++ b/Session.js @@ -209,6 +209,11 @@ } function useDefaultDatetimes(initialDefault, finalDefault) { + /* + Note that inside the system, we are going to deal with these + dates in their numeric value representation. + */ + /* Initial Datetime */ if (bot.SESSION.parameters.timeRange.config.initialDatetime === undefined) { bot.SESSION.parameters.timeRange.config.initialDatetime = initialDefault diff --git a/server.js b/server.js index 4aa0957d2..7717daf28 100644 --- a/server.js +++ b/server.js @@ -45,6 +45,11 @@ global.PRECISE = function (floatNumber, precision) { return this.parseFloat(floatNumber.toFixed(precision)) } +global.REMOVE_TIME = function (datetime) { + let date = new Date(datetime) + return new Date(date.getUTCFullYear() + "-" + (date.getUTCMonth() + 1) + "-" + date.getUTCDate() + " " + "00:00" + GMT_SECONDS); +} + process.on('uncaughtException', function (err) { console.log('[ERROR] Task Server -> server -> uncaughtException -> err.message = ' + err.message) console.log('[ERROR] Task Server -> server -> uncaughtException -> err.stack = ' + err.stack)