Handling of Process Date re implemented

This commit is contained in:
Luis Fernando Molina committed 2020-08-20 14:56:23 +02:00
1 parent 09f189541d
commit 7d519868b7
4 files changed
+148 -156

No files matched your search

+3 -4
View File
@@ -27,7 +27,7 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
}
async function start(chart, timeFrame, timeFrameLabel, currentDay) {
async function start(chart, timeFrame, timeFrameLabel, tradingProcessDate) {
try {
if (timeFrame > global.dailyFilePeriods[0][0]) {
@@ -41,7 +41,6 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
let tradingSimulation = TRADING_SIMULATION.newTradingSimulation(bot, logger, UTILITIES)
let outputDatasets = bot.processNode.referenceParent.processOutput.outputDatasets
let market = bot.market
let outputDatasetsMap = new Map()
if (bot.FIRST_EXECUTION === true && bot.RESUME === false) {
@@ -127,7 +126,7 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
if (dataset.config.type === 'Daily Files') {
let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2);
let dateForPath = tradingProcessDate.getUTCFullYear() + '/' + utilities.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(tradingProcessDate.getUTCDate(), 2);
let fileName = 'Data.json'
let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel + "/" + dateForPath
@@ -184,7 +183,7 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
if (dataset.config.type === 'Daily Files') {
let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2);
let dateForPath = tradingProcessDate.getUTCFullYear() + '/' + utilities.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(tradingProcessDate.getUTCDate(), 2);
let fileName = 'Data.json'
let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel + "/" + dateForPath
+119 -146
View File
@@ -66,19 +66,31 @@
try {
let currentTimeFrame
let currentTimeFrameLabel
let market = bot.market;
/* Context Variables */
let contextVariables = {
lastFile: undefined, // Datetime of the last file files sucessfully produced by this process.
dateBeginOfMarket: undefined, // Datetime of the first trade file in the whole market history.
dateEndOfMarket: undefined // Datetime of the last file available to be used as an input of this process.
};
let previousDay; // Holds the date of the previous day relative to the processing date.
getContextVariables()
/* Initializing the Trading Process Date */
if (bot.FIRST_EXECUTION === true && bot.RESUME === false) {
/*
This funcion is going to be called many times by the Trading Bot Loop.
Only during the first execution and when the User is not resuming the execution
of a stopped session / task; we are going to initialize the Process Date Time.
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()
}
/* 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)
await processSingleFiles()
await processMarketFiles()
@@ -102,19 +114,20 @@
await generateOutput(chart)
await writeProcessFiles()
checkIfSessionMustStop()
} else {
/* We are processing Daily Files */
/*
Go back one day to start well when we advance time at the begining of the loop.
*/
bot.tradingProcessDate = new Date(contextVariables.lastFile.valueOf() - global.ONE_DAY_IN_MILISECONDS);
do {
if (advanceTime() === false) {break}
if (checkStopHeadOfTheMarket() === false) {break}
if (checkStopTaskGracefully() === false) {break}
if (checkStopProcessing() === false) {break}
/*
We update the Trading Process Date with the date calculated at the simulation.
We will use this date to load indicator and output files. After that we will
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)
await processDailyFiles()
@@ -126,19 +139,23 @@
while (true)
}
checkIfSessionMustStop()
/*
Everything worked as expected. We return an OK code and wait for
the Bot Loop to call us again later.
*/
callBackFunction(global.DEFAULT_OK_RESPONSE)
function getContextVariables() {
try {
let thisReport;
let reportKey;
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)
/*
Here we get the status report from the bot who knows which is the end of the market.
Here we get the status report from the bot who knows which is the end of the market.
*/
statusReport = statusDependencies.reportsByMainUtility.get("Market Ending Point")
@@ -170,17 +187,6 @@
contextVariables.dateEndOfMarket = new Date(thisReport.lastFile.valueOf());
/* Validation that the data is not up-to-date. */
if (bot.tradingProcessDate.valueOf() - global.ONE_DAY_IN_MILISECONDS > contextVariables.dateEndOfMarket.valueOf() && bot.SESSION.type !== "Backtesting Session") {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> " + "Head of the market is @ " + contextVariables.dateEndOfMarket); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> You need to UPDATE your datasets in order to run a " + bot.SESSION.type) }
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
}
/* Finally we get our own Status Report. */
statusReport = statusDependencies.reportsByMainUtility.get("Self Reference")
@@ -256,29 +262,13 @@
/* We cut the async calls via callBacks at this point, so as to have a clearer code upstream */
let response = await asyncGetDatasetFile(datasetModule, filePath, fileName)
onFileReceived(response.err, response.text)
function onFileReceived(err, text) {
try {
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
if (err.message === 'File does not exist.') {
logger.write(MODULE_NAME, "[ERROR] The file " + filePath + '/' + fileName + ' does not exist and it is required to continue. This process will retry to read it in a while. In the meantime make yourself sure that the process that generates it has ran properly.');
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
} else {
logger.write(MODULE_NAME, "[ERROR] start -> processSingleFiles -> onFileReceived -> err = " + err.message);
callBackFunction(err);
}
return
}
let dataFile = JSON.parse(text);
dataFiles.set(dependency.id, dataFile);
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processSingleFiles -> onFileReceived -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
if (response.err.result !== global.DEFAULT_OK_RESPONSE.result) {
throw(response.err)
}
let dataFile = JSON.parse(response.text);
dataFiles.set(dependency.id, dataFile);
}
let mapKey = "Single Files"
@@ -321,30 +311,14 @@
/* We cut the async calls via callBacks at this point, so as to have a clearer code upstream */
let response = await asyncGetDatasetFile(datasetModule, filePath, fileName)
onFileReceived(response.err, response.text)
function onFileReceived(err, text) {
try {
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
if (err.message === 'File does not exist.') {
logger.write(MODULE_NAME, "[ERROR] The file " + filePath + '/' + fileName + ' does not exist and it is required to continue. This process will retry to read it in a while. In the meantime make yourself sure that the process that generates it has ran properly.');
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
} else {
logger.write(MODULE_NAME, "[ERROR] start -> processMarketFiles -> onFileReceived -> err = " + err.message);
callBackFunction(err);
}
return
}
let dataFile = JSON.parse(text);
let trimmedDataFile = trimDataFile(dataFile, datasetModule.node.parentNode.record)
dataFiles.set(dependency.id, trimmedDataFile);
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processMarketFiles -> onFileReceived -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
if (response.err.result !== global.DEFAULT_OK_RESPONSE.result) {
throw(response.err)
}
let dataFile = JSON.parse(response.text);
let trimmedDataFile = trimDataFile(dataFile, datasetModule.node.parentNode.record)
dataFiles.set(dependency.id, trimmedDataFile);
function trimDataFile(dataFile, recordDefinition) {
/*
@@ -381,8 +355,8 @@
async function processDailyFiles() {
/* Telling the world we are alive and doing well and which date we are processing right now. */
let processingDate = bot.tradingProcessDate.getUTCFullYear() + '-' + utilities.pad(bot.tradingProcessDate.getUTCMonth() + 1, 2) + '-' + utilities.pad(bot.tradingProcessDate.getUTCDate(), 2);
bot.processHeartBeat(processingDate)
let processingDateString = tradingProcessDate.getUTCFullYear() + '-' + utilities.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '-' + utilities.pad(tradingProcessDate.getUTCDate(), 2);
bot.processHeartBeat(processingDateString)
/*
We will iterate through all posible timeFrames.
@@ -416,7 +390,6 @@
for (let dependencyIndex = 0; dependencyIndex < dataDependenciesModule.nodeArray.length; dependencyIndex++) {
let dependency = dataDependenciesModule.nodeArray[dependencyIndex];
let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex];
let file
if (dependency.referenceParent.config.codeName !== "Multi-Period-Daily") {
continue
@@ -428,7 +401,7 @@
}
}
let dateForPath = bot.tradingProcessDate.getUTCFullYear() + '/' + utilities.pad(bot.tradingProcessDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(bot.tradingProcessDate.getUTCDate(), 2);
let dateForPath = tradingProcessDate.getUTCFullYear() + '/' + utilities.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(tradingProcessDate.getUTCDate(), 2);
let filePath
if (dependency.referenceParent.config.codeName === "Multi-Period-Daily") {
filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel + "/" + dateForPath;
@@ -439,30 +412,13 @@
/* We cut the async calls via callBacks at this point, so as to have a clearer code upstream */
let response = await asyncGetDatasetFile(datasetModule, filePath, fileName)
onFileReceived(response.err, response.text)
function onFileReceived(err, text) {
try {
if ((err.result === "Fail Because" && err.message === "File does not exist.") || err.code === 'The specified key does not exist.') {
logger.write(MODULE_NAME, "[ERROR] The file " + filePath + '/' + fileName + ' does not exist and it is required to continue. This process will retry to read it in a while. In the meantime make yourself sure that the process that generates it has ran properly.');
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
return
}
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] start -> processDailyFiles -> onFileReceived -> Not Ok -> err = " + err.code);
callBackFunction(err);
return
}
file = JSON.parse(text);
dataFiles.set(dependency.id, file);
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processDailyFiles -> onFileReceived -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
if (response.err.result !== global.DEFAULT_OK_RESPONSE.result) {
throw(response.err)
}
let dataFile = JSON.parse(response.text);
dataFiles.set(dependency.id, dataFile);
}
let mapKey = global.dailyFilePeriods[n][1];
@@ -470,26 +426,14 @@
}
}
function advanceTime() {
bot.tradingProcessDate = new Date(bot.tradingProcessDate.valueOf() + global.ONE_DAY_IN_MILISECONDS);
previousDay = new Date(bot.tradingProcessDate.valueOf() - global.ONE_DAY_IN_MILISECONDS);
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> advanceTime -> bot.tradingProcessDate = " + bot.tradingProcessDate); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> advanceTime -> previousDay = " + previousDay); }
/* Validation that we are not going past the user defined end date. */
if (bot.tradingProcessDate.valueOf() >= bot.SESSION.parameters.timeRange.config.finalDatetime) {
const logText = "User Defined End Datetime reached @ " + previousDay.getUTCFullYear() + "/" + (previousDay.getUTCMonth() + 1) + "/" + previousDay.getUTCDate() + ".";
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> advanceTime -> " + logText); }
bot.SESSION.stop(logText)
return false
}
/* Validation that we are not going past the head of the market. */
if (bot.tradingProcessDate.valueOf() > contextVariables.dateEndOfMarket.valueOf() + global.ONE_DAY_IN_MILISECONDS - 1) {
const logText = "Head of the market found @ " + previousDay.getUTCFullYear() + "/" + (previousDay.getUTCMonth() + 1) + "/" + previousDay.getUTCDate() + ".";
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> advanceTime -> " + logText); }
function checkStopHeadOfTheMarket() {
/*
We need to check if we have reached the head of the market in order to know
when to break the Daily Files Process loop and give time for a new candles /
indicators to be built and continue the processing once this process is called
again.
*/
if (bot.simulationState.tradingEngine.current.episode.headOfTheMarket.value === true) {
return false
}
}
@@ -565,7 +509,7 @@
chart,
currentTimeFrame,
currentTimeFrameLabel,
bot.tradingProcessDate
tradingProcessDate
)
bot.FIRST_EXECUTION = false // From here on, all other loops executions wont be the first execution.
@@ -574,24 +518,28 @@
async function writeProcessFiles() {
await writeTimeFramesFiles(currentTimeFrame, currentTimeFrameLabel)
await writeDataRanges(currentTimeFrameLabel)
await writeDataRanges()
if (currentTimeFrame > global.dailyFilePeriods[0][0]) {
await writeMarketStatusReport(currentTimeFrameLabel)
} else {
await writeDailyStatusReport(bot.tradingProcessDate, currentTimeFrameLabel)
await writeDailyStatusReport(currentTimeFrameLabel)
}
async function writeDataRanges(currentTimeFrameLabel) {
for (let outputDatasetIndex = 0; outputDatasetIndex < bot.processNode.referenceParent.processOutput.outputDatasets.length; outputDatasetIndex++) {
async function writeDataRanges() {
for (
let outputDatasetIndex = 0;
outputDatasetIndex < bot.processNode.referenceParent.processOutput.outputDatasets.length;
outputDatasetIndex++
) {
let productCodeName = bot.processNode.referenceParent.processOutput.outputDatasets[outputDatasetIndex].referenceParent.parentNode.config.codeName;
await writeDataRange(contextVariables.dateBeginOfMarket, bot.tradingProcessDate, productCodeName, currentTimeFrameLabel);
await writeDataRange(productCodeName);
}
async function writeDataRange(pBegin, pEnd, productCodeName, currentTimeFrameLabel) {
async function writeDataRange(productCodeName) {
let dataRange = {
begin: pBegin.valueOf(),
end: pEnd.valueOf() + global.ONE_DAY_IN_MILISECONDS
begin: contextVariables.dateBeginOfMarket.valueOf(),
end: tradingProcessDate + global.ONE_DAY_IN_MILISECONDS
}
let fileContent = JSON.stringify(dataRange);
@@ -618,12 +566,16 @@
async function writeTimeFramesFiles(currentTimeFrame, currentTimeFrameLabel) {
for (let outputDatasetIndex = 0; outputDatasetIndex < bot.processNode.referenceParent.processOutput.outputDatasets.length; outputDatasetIndex++) {
for (
let outputDatasetIndex = 0;
outputDatasetIndex < bot.processNode.referenceParent.processOutput.outputDatasets.length;
outputDatasetIndex++
) {
let productCodeName = bot.processNode.referenceParent.processOutput.outputDatasets[outputDatasetIndex].referenceParent.parentNode.config.codeName;
await writeTimeFramesFile(currentTimeFrame, currentTimeFrameLabel, productCodeName, 'Multi-Period-Daily')
await writeTimeFramesFile(currentTimeFrame, currentTimeFrameLabel, productCodeName, 'Multi-Period-Market')
await writeTimeFramesFile( currentTimeFrameLabel, productCodeName, 'Multi-Period-Daily')
await writeTimeFramesFile( currentTimeFrameLabel, productCodeName, 'Multi-Period-Market')
async function writeTimeFramesFile(currentTimeFrame, currentTimeFrameLabel, productCodeName, processType) {
async function writeTimeFramesFile(currentTimeFrameLabel, productCodeName, processType) {
let timeFramesArray = []
timeFramesArray.push(currentTimeFrameLabel)
@@ -641,12 +593,12 @@
}
}
async function writeDailyStatusReport(lastFileDate, currentTimeFrameLabel) {
async function writeDailyStatusReport( currentTimeFrameLabel) {
let reportKey = bot.dataMine + "-" + bot.codeName + "-" + bot.processNode.referenceParent.config.codeName
let thisReport = statusDependencies.statusReports.get(reportKey)
thisReport.file.lastExecution = bot.currentDaytime
thisReport.file.lastFile = lastFileDate
thisReport.file.lastFile = tradingProcessDate
thisReport.file.simulationState = bot.simulationState
thisReport.file.timeFrames = currentTimeFrameLabel
await thisReport.asyncSave()
@@ -660,33 +612,54 @@
thisReport.file.simulationState = bot.simulationState
thisReport.file.timeFrames = currentTimeFrameLabel
logger.newInternalLoop(bot.codeName, bot.process, bot.tradingProcessDate)
logger.newInternalLoop(bot.codeName, bot.process, tradingProcessDate)
await thisReport.asyncSave()
}
}
function checkIfSessionMustStop() {
/*
The natural way for the session to stop is when we reached the
user defined end datetime.
*/
const now = new Date()
if (now.valueOf() >= bot.SESSION.parameters.timeRange.config.finalDatetime) {
const logText = "User Defined End Datetime reached @ " + now.getUTCFullYear() + "/" + (now.getUTCMonth() + 1) + "/" + now.getUTCDate() + ".";
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeProcessFiles -> onMarketStatusReport -> " + logText); }
bot.SESSION.stop('because it just finished.')
return
}
if (bot.SESSION.type === 'Backtesting Session') {
bot.SESSION.stop('Backtesting Session over Market Files Finished.')
return
/*
Backtests needs only one execution of this process to complete.
*/
bot.SESSION.stop('Backtesting Session Finished.')
} else {
/*
The natural way for the session to stop is when we reached the
user defined end datetime.
*/
const now = new Date()
if (now.valueOf() >= bot.SESSION.parameters.timeRange.config.finalDatetime) {
const logText = "User Defined End Datetime reached @ " + now.getUTCFullYear() + "/" + (now.getUTCMonth() + 1) + "/" + now.getUTCDate() + ".";
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeProcessFiles -> onMarketStatusReport -> " + logText); }
bot.SESSION.stop('Final Datetime Reached.')
}
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
/* An unhandled exception occured. in this case we return Fail and log the stack. */
if (err.stack) {
logger.write(MODULE_NAME, "[ERROR] start -> Unhandled Exception. Will Abort this process. err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
}
/* Some expected file was not found. We will return a RETRY code and move on. */
if ((err.result === "Fail Because" && err.message === "File does not exist.") || err.code === 'The specified key does not exist.') {
logger.write(MODULE_NAME, "[ERROR] File not Found. Will Retry the Process Loop.")
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
return
}
/* Some other handled exception occured. We return Fail and move on. */
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] start -> Handled Exception. Will Abort this process. err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
}
}
}
+25
View File
@@ -368,8 +368,33 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
For the special case of 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) {
/*
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 we are at the last candle of
the day, we will advance current process day. By doing so, during the next execution, the
simulation will receive the candles and indicators files of the next day.
*/
if (bot.processingDailyFiles) {
let candlesPerDay = global.ONE_DAY_IN_MILISECONDS / sessionParameters.timeFrame.config.value
if (tradingEngine.current.episode.candle.index.value + 1 === candlesPerDay - 1) {
/*
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
the next day. At the same time we will reset the index to be ready to real next time
the first candle of the new set we receive.
*/
tradingEngine.current.episode.candle.index.value = 0
tradingEngine.current.episode.processDate.value =
tradingEngine.current.episode.processDate.value + global.ONE_DAY_IN_MILISECONDS
}
}
/* We reached the head of the market */
tradingEngine.current.episode.headOfTheMarket.value = true
return false
} else {
/* Wd did not reach the head of the market */
tradingEngine.current.episode.headOfTheMarket.value = false
return true
}
}
+1 -6
View File
@@ -67,6 +67,7 @@
setUpAppSchema()
setUpSessionFolderName()
/* We validate all parameters received and complete some that might be missing if needed. */
if (checkParemeters() === false) { return }
socialBotsModule.initialize()
@@ -310,7 +311,6 @@
}
function startBackTesting(message) {
bot.tradingProcessDate = new Date(bot.SESSION.parameters.timeRange.config.initialDatetime.valueOf()) // Here we initialize the date of the process.
return true
}
@@ -319,8 +319,6 @@
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[ERROR] initialize -> startLiveTrading -> Key 'codeName' or 'secret' not provided. Plese check that and try again."); }
return false
}
bot.tradingProcessDate = new Date(bot.SESSION.parameters.timeRange.config.initialDatetime.valueOf())
pProcessConfig.liveWaitTime = bot.SESSION.parameters.timeFrame.config.value
return true
}
@@ -332,8 +330,6 @@
return false
}
bot.tradingProcessDate = new Date(bot.SESSION.parameters.timeRange.config.initialDatetime.valueOf())
/* Reduce the balance */
let balancePercentage = 1 // This is the default value
@@ -356,7 +352,6 @@
}
function startPaperTrading(message) {
bot.tradingProcessDate = new Date(bot.SESSION.parameters.timeRange.config.initialDatetime.valueOf())
pProcessConfig.normalWaitTime = bot.SESSION.parameters.timeFrame.config.value
return true
}