Merge pull request #528 from Luis-Fernando-Molina/develop
Contribution: Moving Towards Enabling a Learning Bot
This commit is contained in:
39 files changed
+5170
-1074
No files matched your search
@@ -442,6 +442,24 @@
|
||||
"propertyName": "singleMarketFunctions",
|
||||
"functionName": "newSuperalgosFunctionLibrariesSingleMarketFunctions",
|
||||
"fileName": "SingleMarketFunctions.js"
|
||||
},
|
||||
{
|
||||
"name": "Data Dependencies Functions",
|
||||
"propertyName": "dataDependenciesFunctions",
|
||||
"functionName": "newSuperalgosFunctionLibrariesDataDependenciesFunctions",
|
||||
"fileName": "DataDependenciesFunctions.js"
|
||||
},
|
||||
{
|
||||
"name": "Process Files Functions",
|
||||
"propertyName": "processFilesFunctions",
|
||||
"functionName": "newSuperalgosFunctionLibrariesProcessFilesFunctions",
|
||||
"fileName": "ProcessFilesFunctions.js"
|
||||
},
|
||||
{
|
||||
"name": "Output Management Functions",
|
||||
"propertyName": "outputManagementFunctions",
|
||||
"functionName": "newSuperalgosFunctionLibrariesOutputManagementFunctions",
|
||||
"fileName": "OutputManagementFunctions.js"
|
||||
}
|
||||
],
|
||||
"utilities": [
|
||||
@@ -762,6 +780,55 @@
|
||||
"functionName": "newSuperalgosBotModulesExchangeAPI",
|
||||
"fileName": "ExchangeAPI.js",
|
||||
"folderName": "Trading-Bot/Low-Frequency-Trading/APIs"
|
||||
},
|
||||
{
|
||||
"name": "Learning Process",
|
||||
"propertyName": "learningProcess",
|
||||
"functionName": "newSuperalgosBotModulesLearningProcess",
|
||||
"fileName": "LearningProcess.js",
|
||||
"folderName": "Learning-Bot/Low-Frequency-Learning"
|
||||
},
|
||||
{
|
||||
"name": "Learning Engine",
|
||||
"propertyName": "learningEngine",
|
||||
"functionName": "newSuperalgosBotModulesLearningEngine",
|
||||
"fileName": "LearningEngine.js",
|
||||
"folderName": "Learning-Bot/Low-Frequency-Learning"
|
||||
},
|
||||
{
|
||||
"name": "Learning Output",
|
||||
"propertyName": "learningOutput",
|
||||
"functionName": "newSuperalgosBotModulesLearningOutput",
|
||||
"fileName": "LearningOutput.js",
|
||||
"folderName": "Learning-Bot/Low-Frequency-Learning"
|
||||
},
|
||||
{
|
||||
"name": "Learning Simulation",
|
||||
"propertyName": "learningSimulation",
|
||||
"functionName": "newSuperalgosBotModulesLearningSimulation",
|
||||
"fileName": "LearningSimulation.js",
|
||||
"folderName": "Learning-Bot/Low-Frequency-Learning"
|
||||
},
|
||||
{
|
||||
"name": "Learning Episode",
|
||||
"propertyName": "learningEpisode",
|
||||
"functionName": "newSuperalgosBotModulesLearningEpisode",
|
||||
"fileName": "LearningEpisode.js",
|
||||
"folderName": "Learning-Bot/Low-Frequency-Learning"
|
||||
},
|
||||
{
|
||||
"name": "Learning Records",
|
||||
"propertyName": "learningRecords",
|
||||
"functionName": "newSuperalgosBotModulesLearningRecords",
|
||||
"fileName": "LearningRecords.js",
|
||||
"folderName": "Learning-Bot/Low-Frequency-Learning"
|
||||
},
|
||||
{
|
||||
"name": "Learning System",
|
||||
"propertyName": "learningSystem",
|
||||
"functionName": "newSuperalgosBotModulesLearningSystem",
|
||||
"fileName": "LearningSystem.js",
|
||||
"folderName": "Learning-Bot/Low-Frequency-Learning"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -2740,8 +2740,16 @@
|
||||
"action": "Add UI Object",
|
||||
"disableIfPropertyIsDefined": true,
|
||||
"propertyToCheckFor": "session",
|
||||
"label": "Add Learning Session",
|
||||
"relatedUiObject": "Learning Session",
|
||||
"label": "Add Back Learning Session",
|
||||
"relatedUiObject": "Back Learning Session",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"disableIfPropertyIsDefined": true,
|
||||
"propertyToCheckFor": "session",
|
||||
"label": "Add Live Learning Session",
|
||||
"relatedUiObject": "Live Learning Session",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
@@ -2779,7 +2787,12 @@
|
||||
{
|
||||
"name": "session",
|
||||
"type": "node",
|
||||
"childType": "Learning Session"
|
||||
"childType": "Back Learning Session"
|
||||
},
|
||||
{
|
||||
"name": "session",
|
||||
"type": "node",
|
||||
"childType": "Live Learning Session"
|
||||
},
|
||||
{
|
||||
"name": "executionStartedEvent",
|
||||
@@ -2937,6 +2950,31 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Learning Engine",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Add Missing Children",
|
||||
"label": "Add Missing Children",
|
||||
"relatedUiObject": "Learning Engine",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete-entity",
|
||||
"iconPathOff": "delete-entity",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"isHierarchyHead": true,
|
||||
"addLeftIcons": true,
|
||||
"level": 0,
|
||||
"childrenNodesProperties": [],
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Dynamic Indicators",
|
||||
"menuItems": [
|
||||
@@ -9539,7 +9577,7 @@
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"attachingRules": {
|
||||
"compatibleTypes": "->Learning Session->"
|
||||
"compatibleTypes": "->Back Learning Session->Live Learning Session->"
|
||||
},
|
||||
"childrenNodesProperties": [
|
||||
{
|
||||
@@ -9615,6 +9653,60 @@
|
||||
},
|
||||
"propertyNameAtParent": "tradingEngineReference"
|
||||
},
|
||||
{
|
||||
"type": "Learning System Reference",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete-entity",
|
||||
"iconPathOff": "delete-entity",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"title": [
|
||||
"Use Reference Parent"
|
||||
],
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"attachingRules": {
|
||||
"compatibleTypes": "->Back Learning Session->Live Learning Session->"
|
||||
},
|
||||
"referencingRules": {
|
||||
"compatibleTypes": "->Learning System->"
|
||||
},
|
||||
"propertyNameAtParent": "learningSystemReference",
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Learning Engine Reference",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete-entity",
|
||||
"iconPathOff": "delete-entity",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"title": [
|
||||
"Use Reference Parent"
|
||||
],
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"attachingRules": {
|
||||
"compatibleTypes": "->Back Learning Session->Live Learning Session->"
|
||||
},
|
||||
"referencingRules": {
|
||||
"compatibleTypes": "->Learning Engine->"
|
||||
},
|
||||
"propertyNameAtParent": "learningEngineReference",
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Session Base Asset",
|
||||
"menuItems": [
|
||||
@@ -10398,7 +10490,7 @@
|
||||
"propertyNameAtParent": "session"
|
||||
},
|
||||
{
|
||||
"type": "Learning Session",
|
||||
"type": "Back Learning Session",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Run Learning Session",
|
||||
@@ -10496,7 +10588,110 @@
|
||||
"childType": "Social Bots"
|
||||
}
|
||||
],
|
||||
"propertyNameAtParent": "session"
|
||||
"propertyNameAtParent": "session",
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Live Learning Session",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Run Learning Session",
|
||||
"label": "Run",
|
||||
"workingLabel": "Run Request Sent",
|
||||
"workDoneLabel": "Session Running",
|
||||
"workFailedLabel": "Session Cannot be Run",
|
||||
"secondaryAction": "Stop Learning Session",
|
||||
"secondaryLabel": "Stop",
|
||||
"secondaryWorkingLabel": "Stopping...",
|
||||
"secondaryWorkDoneLabel": "Session Stopped",
|
||||
"secondaryWorkFailedLabel": "Session Cannot be Stopped",
|
||||
"secondaryIcon": "stop",
|
||||
"iconPathOn": "run",
|
||||
"iconPathOff": "run",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Resume Learning Session",
|
||||
"label": "Resume",
|
||||
"workingLabel": "Resume Request Sent",
|
||||
"workDoneLabel": "Session Running",
|
||||
"workFailedLabel": "Session Cannot be Resumed",
|
||||
"secondaryAction": "Stop Learning Session",
|
||||
"secondaryLabel": "Stop",
|
||||
"secondaryWorkingLabel": "Stopping...",
|
||||
"secondaryWorkDoneLabel": "Session Stopped",
|
||||
"secondaryWorkFailedLabel": "Session Cannot be Stopped",
|
||||
"secondaryIcon": "stop",
|
||||
"iconPathOn": "resume",
|
||||
"iconPathOff": "resume",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Configure",
|
||||
"label": "Configure",
|
||||
"iconPathOn": "configuration",
|
||||
"iconPathOff": "configuration",
|
||||
"dontShowAtFullscreen": true,
|
||||
"actionFunction": "uiObject.configEditor.activate"
|
||||
},
|
||||
{
|
||||
"action": "Add Missing Children",
|
||||
"label": "Add Missing Children",
|
||||
"relatedUiObject": "Trading Parameters",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete-entity",
|
||||
"iconPathOff": "delete-entity",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"isTitleAllwaysVisible": true,
|
||||
"addLeftIcons": true,
|
||||
"editors": {
|
||||
"config": true
|
||||
},
|
||||
"initialValues": {
|
||||
"config": "{ \n\"folderName\": \"Your-Session-Folder-Name\"\n}"
|
||||
},
|
||||
"level": 2,
|
||||
"referencingRules": {
|
||||
"compatibleTypes": "->Trading System->"
|
||||
},
|
||||
"attachingRules": {
|
||||
"compatibleTypes": "->Learning Process Instance->"
|
||||
},
|
||||
"childrenNodesProperties": [
|
||||
{
|
||||
"name": "learningParameters",
|
||||
"type": "node",
|
||||
"childType": "Learning Parameters",
|
||||
"autoAdd": true
|
||||
},
|
||||
{
|
||||
"name": "tradingSystemReference",
|
||||
"type": "node",
|
||||
"childType": "Trading System Reference",
|
||||
"autoAdd": true
|
||||
},
|
||||
{
|
||||
"name": "tradingEngineReference",
|
||||
"type": "node",
|
||||
"childType": "Trading Engine Reference",
|
||||
"autoAdd": true
|
||||
},
|
||||
{
|
||||
"name": "socialBots",
|
||||
"type": "node",
|
||||
"childType": "Social Bots"
|
||||
}
|
||||
],
|
||||
"propertyNameAtParent": "session",
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Sensor Bot Instance",
|
||||
@@ -12065,6 +12260,25 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Learning System",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete-entity",
|
||||
"iconPathOff": "delete-entity",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"isHierarchyHead": true,
|
||||
"addLeftIcons": true,
|
||||
"level": 0,
|
||||
"childrenNodesProperties": [],
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Trading Strategy",
|
||||
"menuItems": [
|
||||
@@ -13684,7 +13898,7 @@
|
||||
"addLeftIcons": true,
|
||||
"level": 4,
|
||||
"attachingRules": {
|
||||
"compatibleTypes": "->Backtesting Session->Live Trading Session->Paper Trading Session->Forward Testing Session->Learning Session->"
|
||||
"compatibleTypes": "->Backtesting Session->Live Trading Session->Paper Trading Session->Forward Testing Session->Back Learning Session->Live Learning Session->"
|
||||
},
|
||||
"childrenNodesProperties": [
|
||||
{
|
||||
@@ -17289,7 +17503,7 @@
|
||||
"level": 3,
|
||||
"alternativeIcons": "Use Reference Parent",
|
||||
"referencingRules": {
|
||||
"compatibleTypes": "->Learning Session->"
|
||||
"compatibleTypes": "->Back Learning Session->Live Learning Session->"
|
||||
},
|
||||
"attachingRules": {
|
||||
"compatibleTypes": "->Market Learning Products->"
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "Back Learning Session"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"type": "Learning Session"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "Live Learning Session"
|
||||
}
|
||||
+1
-1
@@ -258,7 +258,7 @@
|
||||
let n;
|
||||
processDate = new Date(contextVariables.lastBandFile.valueOf() - TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS); // Go back one day to start well when we advance time at the begining of the loop.
|
||||
let fromDate = new Date(processDate.valueOf())
|
||||
let lastDate = new Date()
|
||||
let lastDate = TS.projects.superalgos.utilities.dateTimeFunctions.removeTime(new Date())
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildBands -> processDate = " + processDate)
|
||||
|
||||
+1
-1
@@ -409,7 +409,7 @@
|
||||
/* Telling the world we are alive and doing well */
|
||||
let currentDateString = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME.getUTCFullYear() + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME.getUTCMonth() + 1, 2) + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME.getUTCDate(), 2);
|
||||
let currentDate = new Date(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME)
|
||||
let lastDate = new Date()
|
||||
let lastDate = TS.projects.superalgos.utilities.dateTimeFunctions.removeTime(new Date())
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, currentDateString, TS.projects.superalgos.utilities.dateTimeFunctions.getPercentage(currentDate, currentDate, lastDate))
|
||||
}
|
||||
catch (err) {
|
||||
|
||||
+1
-1
@@ -228,7 +228,7 @@
|
||||
function buildCandles() {
|
||||
try {
|
||||
let fromDate = new Date(contextVariables.lastCandleFile.valueOf())
|
||||
let lastDate = new Date()
|
||||
let lastDate = TS.projects.superalgos.utilities.dateTimeFunctions.removeTime(new Date())
|
||||
let outputCandles
|
||||
let outputVolumes
|
||||
|
||||
|
||||
+1
-1
@@ -389,7 +389,7 @@
|
||||
|
||||
try {
|
||||
let fromDate = new Date(contextVariables.lastCandleFile.valueOf())
|
||||
let lastDate = new Date()
|
||||
let lastDate = TS.projects.superalgos.utilities.dateTimeFunctions.removeTime(new Date())
|
||||
/*
|
||||
Firstly we prepere the arrays that will accumulate all the information for each output file.
|
||||
*/
|
||||
|
||||
@@ -234,7 +234,7 @@
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME =
|
||||
new Date(contextVariables.lastFile.valueOf() - TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS) // Go back one day to start well when we advance time at the begining of the loop.
|
||||
let fromDate = new Date(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME.valueOf())
|
||||
let lastDate = new Date()
|
||||
let lastDate = TS.projects.superalgos.utilities.dateTimeFunctions.removeTime(new Date())
|
||||
|
||||
advanceTime()
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
return thisObject;
|
||||
|
||||
function initialize(pStatusDependencies, pDataDependencies, callBackFunction) {
|
||||
|
||||
|
||||
statusDependencies = pStatusDependencies;
|
||||
dataDependenciesModule = pDataDependencies;
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> processTimeFrames -> timeFramesLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = " + err.stack)
|
||||
callBackFunction(err)
|
||||
return;
|
||||
@@ -136,8 +136,8 @@
|
||||
}
|
||||
|
||||
function writeTimeFramesFiles(callBack) {
|
||||
let outputDatasets =
|
||||
TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset')
|
||||
let outputDatasets =
|
||||
TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset')
|
||||
let outputDatasetIndex = -1;
|
||||
controlLoop()
|
||||
|
||||
@@ -178,14 +178,14 @@
|
||||
|
||||
let fileContent = JSON.stringify(timeFramesArray)
|
||||
let fileName = '/Time.Frames.json';
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Output/" + productCodeName + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName + fileName;
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Output/" + productCodeName + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName + fileName;
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated)
|
||||
|
||||
function onFileCreated(err) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeTimeFramesFile -> onFileCreated -> err = " + err.stack)
|
||||
callBack(err)
|
||||
return
|
||||
@@ -195,8 +195,8 @@
|
||||
}
|
||||
|
||||
function writeStatusReport(callBack) {
|
||||
let reportKey = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + "Multi-Period-Market"
|
||||
let reportKey = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + "Multi-Period-Market"
|
||||
let thisReport = statusDependencies.statusReports.get(reportKey)
|
||||
|
||||
thisReport.file.lastExecution = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME;
|
||||
@@ -214,13 +214,16 @@
|
||||
/* Telling the world we are alive and doing well */
|
||||
let currentDateString = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME.getUTCFullYear() + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME.getUTCMonth() + 1, 2) + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME.getUTCDate(), 2)
|
||||
let currentDate = new Date(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME)
|
||||
let lastDate = new Date()
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, currentDateString, TS.projects.superalgos.utilities.dateTimeFunctions.getPercentage(currentDate, currentDate, lastDate))
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(
|
||||
processIndex,
|
||||
currentDateString,
|
||||
TS.projects.superalgos.utilities.dateTimeFunctions.getPercentage(currentDate, currentDate, currentDate)
|
||||
)
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> err = " + err.stack)
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,606 @@
|
||||
exports.newSuperalgosBotModulesLearningSession = function (processIndex) {
|
||||
|
||||
const MODULE_NAME = "Learning Session"
|
||||
|
||||
let thisObject = {
|
||||
initialize: initialize
|
||||
}
|
||||
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SOCIAL_BOTS_MODULE =
|
||||
TS.projects.superalgos.botModules.socialBots.newSuperalgosBotModulesSocialBots(processIndex)
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(callBackFunction) {
|
||||
try {
|
||||
/* Check if there is a session */
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session === undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> Cannot run without a Session.");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
We will store here the session key, which we will need everytine
|
||||
we need to emit an event related to the session itself.
|
||||
*/
|
||||
let VARIABLES_BY_PROCESS_INDEX = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex)
|
||||
VARIABLES_BY_PROCESS_INDEX.SESSION_KEY =
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.name +
|
||||
'-' +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.type +
|
||||
'-' +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.id
|
||||
|
||||
/*
|
||||
We will also store the session folder name, to be used for debug logging and session output.
|
||||
*/
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.config.folderName === undefined) {
|
||||
VARIABLES_BY_PROCESS_INDEX.SESSION_FOLDER_NAME = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.type.replace(' ', '-').replace(' ', '-') + '-' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.id
|
||||
} else {
|
||||
VARIABLES_BY_PROCESS_INDEX.SESSION_FOLDER_NAME = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.type.replace(' ', '-').replace(' ', '-') + '-' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.config.folderName
|
||||
}
|
||||
/*
|
||||
We will store all session keys on a map so as to be able to send an event to all
|
||||
of them when the task stops.
|
||||
*/
|
||||
TS.projects.superalgos.globals.taskVariables.SESSION_MAP.set(
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY,
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY)
|
||||
|
||||
/* Listen to event to start or stop the session. */
|
||||
TS.projects.superalgos.globals.taskConstants.EVENT_SERVER_CLIENT_MODULE_OBJECT.listenToEvent(
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY,
|
||||
'Learning Session Status',
|
||||
undefined,
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY,
|
||||
undefined,
|
||||
onSessionStatus)
|
||||
TS.projects.superalgos.globals.taskConstants.EVENT_SERVER_CLIENT_MODULE_OBJECT.listenToEvent(
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY,
|
||||
'Run Learning Session',
|
||||
undefined,
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY,
|
||||
undefined,
|
||||
onSessionRun)
|
||||
TS.projects.superalgos.globals.taskConstants.EVENT_SERVER_CLIENT_MODULE_OBJECT.listenToEvent(
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY,
|
||||
'Stop Learning Session',
|
||||
undefined,
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY,
|
||||
undefined,
|
||||
onSessionStop)
|
||||
TS.projects.superalgos.globals.taskConstants.EVENT_SERVER_CLIENT_MODULE_OBJECT.listenToEvent(
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY,
|
||||
'Resume Learning Session',
|
||||
undefined,
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY,
|
||||
undefined,
|
||||
onSessionResume)
|
||||
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE)
|
||||
return
|
||||
|
||||
function onSessionStatus() {
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_STATUS === 'Running') {
|
||||
let event = {
|
||||
status: 'Learning Session Runnning'
|
||||
}
|
||||
TS.projects.superalgos.globals.taskConstants.EVENT_SERVER_CLIENT_MODULE_OBJECT.raiseEvent(
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY, 'Status Response', event)
|
||||
} else {
|
||||
let event = {
|
||||
status: 'Learning Session Not Runnning'
|
||||
}
|
||||
TS.projects.superalgos.globals.taskConstants.EVENT_SERVER_CLIENT_MODULE_OBJECT.raiseEvent(
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY, 'Status Response', event)
|
||||
}
|
||||
}
|
||||
|
||||
function onSessionRun(message) {
|
||||
try {
|
||||
/* This happens when the UI is reloaded, the session was running and tries to run it again. */
|
||||
if (
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_STATUS === 'Idle' ||
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_STATUS === 'Running'
|
||||
) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] onSessionRun -> Event received to run the Session while it was already running. ")
|
||||
return
|
||||
}
|
||||
|
||||
/* We are going to initialize here these constants whose values are comming at the event. */
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_SYSTEM_NODE = JSON.parse(message.event.learningSystem)
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_NODE = JSON.parse(message.event.learningEngine)
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE = JSON.parse(message.event.session)
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).DEPENDENCY_FILTER = JSON.parse(message.event.dependencyFilter)
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_RESUMING = false
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_FIRST_LOOP = true
|
||||
|
||||
setUpSessionFolderName()
|
||||
|
||||
/* We validate all parameters received and complete some that might be missing if needed. */
|
||||
if (checkParemeters() === false) { return }
|
||||
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SOCIAL_BOTS_MODULE.initialize()
|
||||
|
||||
let allGood
|
||||
switch (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.type) {
|
||||
case 'Back Learning Session': {
|
||||
allGood = startBackLearning(message)
|
||||
break
|
||||
}
|
||||
case 'Live Learning Session': {
|
||||
allGood = startLiveLearning(message)
|
||||
break
|
||||
}
|
||||
}
|
||||
if (allGood === true) {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_STATUS = 'Idle'
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_STOPPING = false
|
||||
} else {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_STOPPING = true
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[IMPORTANT] onSessionRun -> Stopping the Session now. ')
|
||||
}
|
||||
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SOCIAL_BOTS_MODULE.sendMessage(
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.type + " '" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.name + "' is starting.")
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> onSessionRun -> err = " + err.stack);
|
||||
}
|
||||
}
|
||||
|
||||
function onSessionStop() {
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.stopSession(processIndex, 'Session Stopped From the User Interface.')
|
||||
}
|
||||
|
||||
function onSessionResume(message) {
|
||||
try {
|
||||
if (TS.projects.superalgos.functionLibraries.sessionFunctions.stopSession === undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] onSessionResume -> Event received to resume the Session that have never be ran before. ")
|
||||
return
|
||||
}
|
||||
|
||||
/* This happens when the UI is reloaded, the session was running and tries to run it again. */
|
||||
if (
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_STATUS === 'Idle' ||
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_STATUS === 'Running') {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] onSessionResume -> Event received to resume the Session while it was already running. ")
|
||||
return
|
||||
}
|
||||
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_RESUMING = true
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_STOPPING = false
|
||||
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SOCIAL_BOTS_MODULE.sendMessage(
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.type + " '" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.name + "' is resuming.")
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> onSessionResume -> err = " + err.stack);
|
||||
}
|
||||
}
|
||||
|
||||
function setUpSessionFolderName() {
|
||||
/*
|
||||
The session object is overwritten when the session is run. For that reason we
|
||||
need to setup again the folder name at the Session level.
|
||||
Set the folderName for logging, reports, context and data output
|
||||
*/
|
||||
let config
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.config !== undefined) {
|
||||
config = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.config
|
||||
if (config.folderName === undefined) {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME =
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.type.replace(' ', '-').replace(' ', '-') + '-' +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.id
|
||||
} else {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME =
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.type.replace(' ', '-').replace(' ', '-') + '-' +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.config.folderName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkParemeters() {
|
||||
/*
|
||||
Here we check all the Session Parameters received. If something critical is missing we abort returning false. If something
|
||||
non critical is missing, we complete it with a default value.
|
||||
*/
|
||||
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters === undefined) {
|
||||
let errorMessage = "Parameters Node Missing"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS Learning Session Error - ' + errorMessage,
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(
|
||||
processIndex,
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE,
|
||||
errorMessage,
|
||||
docs
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
/* Time Range */
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange === undefined) { // if the Time Range is missing we create a default one.
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange = {
|
||||
name: 'Missing Time Range',
|
||||
type: 'Time Range',
|
||||
config: {
|
||||
initialDatetime: (new Date()).valueOf(),
|
||||
finalDatetime: (new Date()).valueOf() + TS.projects.superalgos.globals.timeConstants.ONE_YEAR_IN_MILISECONDS
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Check that we received valid dates */
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.type === 'Backtesting Session') {
|
||||
if (isNaN(new Date(TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.initialDatetime)).valueOf()) {
|
||||
let errorMessage = "Invalid Initial Datetime Property Value"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS Learning Session Error - ' + errorMessage,
|
||||
placeholder: {
|
||||
currentValue: {
|
||||
style: "Json",
|
||||
text: TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.initialDatetime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange, errorMessage, docs)
|
||||
return false
|
||||
}
|
||||
}
|
||||
if (isNaN(new Date(TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.finalDatetime)).valueOf()) {
|
||||
let errorMessage = "Invalid Initial Datetime Property Value"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS Learning Session Error - ' + errorMessage,
|
||||
placeholder: {
|
||||
currentValue: {
|
||||
style: "Json",
|
||||
text: TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.finalDatetime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange, errorMessage, docs)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/* Session Type Forced Values */
|
||||
let today = (new Date()).valueOf()
|
||||
let aYearAgo = today - TS.projects.superalgos.globals.timeConstants.ONE_YEAR_IN_MILISECONDS
|
||||
let aYearFromNow = today + TS.projects.superalgos.globals.timeConstants.ONE_YEAR_IN_MILISECONDS
|
||||
switch (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.type) {
|
||||
case 'Backtesting Session': {
|
||||
useDefaultDatetimes(aYearAgo, today)
|
||||
break
|
||||
}
|
||||
case 'Live Learning Session': {
|
||||
useDefaultDatetimes(today, aYearFromNow)
|
||||
break
|
||||
}
|
||||
case 'Fordward Testing Session': {
|
||||
useDefaultDatetimes(today, aYearFromNow)
|
||||
break
|
||||
}
|
||||
case 'Paper Learning Session': {
|
||||
useDefaultDatetimes(today, aYearFromNow)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
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 (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.type === 'Backtesting Session') {
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.initialDatetime === undefined) {
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.initialDatetime = initialDefault
|
||||
} else {
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.initialDatetime = (new Date(TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.initialDatetime)).valueOf()
|
||||
}
|
||||
} else {
|
||||
/* Non backtest session can start from the past only if explicitly configured that way */
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.initialDatetime === undefined || TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.allowStartingFromThePast !== true) {
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.initialDatetime = initialDefault
|
||||
} else {
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.initialDatetime = (new Date(TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.initialDatetime)).valueOf()
|
||||
}
|
||||
}
|
||||
|
||||
/* Final Datetime */
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.finalDatetime === undefined) {
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.finalDatetime = finalDefault
|
||||
} else {
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.finalDatetime = (new Date(TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.finalDatetime)).valueOf()
|
||||
}
|
||||
}
|
||||
|
||||
/* Time Frame */
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeFrame === undefined) {
|
||||
let errorMessage = "Time Frame Node Missing"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS Learning Session Error - ' + errorMessage,
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters, errorMessage, docs)
|
||||
return false
|
||||
}
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeFrame.config.label === undefined) {
|
||||
let errorMessage = "Label Property Missing"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS Learning Session Error - ' + errorMessage,
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeFrame, errorMessage, docs)
|
||||
return false
|
||||
}
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeFrame.config.value = getTimeFrameFromLabel(TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeFrame.config.label)
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeFrame.config.value === undefined) {
|
||||
let errorMessage = "Invalid Label Property Value"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS Learning Session Error - ' + errorMessage,
|
||||
placeholder: {
|
||||
currentValue: {
|
||||
style: "Json",
|
||||
text: TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeFrame.config.label
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeFrame, errorMessage, docs)
|
||||
return false
|
||||
}
|
||||
|
||||
/* Session Base Asset */
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.sessionBaseAsset === undefined) {
|
||||
let errorMessage = "Session Base Asset Node Missing"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS Learning Session Error - ' + errorMessage,
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters, errorMessage, docs)
|
||||
return false
|
||||
}
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.sessionBaseAsset.config.initialBalance === undefined) {
|
||||
let errorMessage = "Initial Balance Property Missing"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS Learning Session Error - ' + errorMessage,
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.sessionBaseAsset, errorMessage, docs)
|
||||
return false
|
||||
}
|
||||
|
||||
/* Session Quoted Asset */
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.sessionQuotedAsset === undefined) {
|
||||
let errorMessage = "Session Quoted Asset Node Missing"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS Learning Session Error - ' + errorMessage,
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters, errorMessage, docs)
|
||||
return false
|
||||
}
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.sessionQuotedAsset.config.initialBalance === undefined) {
|
||||
let errorMessage = "Initial Balance Property Missing"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS Learning Session Error - ' + errorMessage,
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.sessionQuotedAsset, errorMessage, docs)
|
||||
return false
|
||||
}
|
||||
|
||||
/* Slippage */
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.slippage === undefined) { // if the Slippage is missing we create a default one.
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.slippage = {
|
||||
name: 'Missing Slippage',
|
||||
type: 'Slippage',
|
||||
config: {
|
||||
marketOrderRate: 0,
|
||||
stopLoss: 0,
|
||||
takeProfit: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.slippage.config.marketOrderRate === undefined) { // if the marketOrderRate is missing we create a default one.
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.slippage.config.marketOrderRate = 0
|
||||
}
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.slippage.config.stopLoss === undefined) { // if the stopLoss is missing we create a default one.
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.slippage.config.stopLoss = 0
|
||||
}
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.slippage.config.takeProfit === undefined) { // if the takeProfit is missing we create a default one.
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.slippage.config.takeProfit = 0
|
||||
}
|
||||
|
||||
/* Fee Structure */
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.feeStructure === undefined) { // if the Fee Structure is missing we create a default one.
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.feeStructure = {
|
||||
name: 'Missing Fee Structure',
|
||||
type: 'Fee Structure',
|
||||
config: {
|
||||
maker: 0,
|
||||
taker: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.feeStructure.config.maker === undefined) { // if the maker is missing we create a default one.
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.feeStructure.config.maker = 0
|
||||
}
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.feeStructure.config.taker === undefined) { // if the taker is missing we create a default one.
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.feeStructure.config.taker = 0
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
function startBackLearning(message) {
|
||||
return true
|
||||
}
|
||||
|
||||
function checkKey() {
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference === undefined) {
|
||||
let errorMessage = "Key Reference Node Missing"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> checkKey -> " + errorMessage)
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS Learning Session Error - ' + errorMessage,
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, TS.projects.superalgos.globals.taskConstants.TASK_NODE, errorMessage, docs)
|
||||
return false
|
||||
}
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference.referenceParent === undefined) {
|
||||
let errorMessage = "Exchange Account Key Node Missing"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> checkKey -> " + errorMessage)
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS Learning Session Error - ' + errorMessage,
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference, errorMessage, docs)
|
||||
return false
|
||||
}
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference.referenceParent.config.codeName === undefined) {
|
||||
let errorMessage = "Codename Property Missing"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> checkKey -> " + errorMessage)
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS Learning Session Error - ' + errorMessage,
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference.referenceParent, errorMessage, docs)
|
||||
return false
|
||||
}
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference.referenceParent.config.secret === undefined) {
|
||||
let errorMessage = "Secret Property Missing"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> checkKey -> " + errorMessage)
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS Learning Session Error - ' + errorMessage,
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference.referenceParent, errorMessage, docs)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function startLiveLearning() {
|
||||
return checkKey()
|
||||
}
|
||||
|
||||
function getTimeFrameFromLabel(timeFrameLabel) {
|
||||
|
||||
for (let i = 0; i < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length; i++) {
|
||||
let value = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[i][0]
|
||||
let label = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[i][1]
|
||||
|
||||
if (timeFrameLabel === label) {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length; i++) {
|
||||
let value = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[i][0]
|
||||
let label = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[i][1]
|
||||
|
||||
if (timeFrameLabel === label) {
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
};
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
exports.newSuperalgosBotModulesLearningEngine = function (processIndex) {
|
||||
/*
|
||||
We call the Learning Engine to the data structure that is needed in order to exevute the
|
||||
learning protocol with the specific rules defined at the Learning System.
|
||||
*/
|
||||
const MODULE_NAME = 'Learning Engine'
|
||||
let thisObject = {
|
||||
mantain: mantain,
|
||||
reset: reset,
|
||||
getNodeById: getNodeById,
|
||||
cloneValues: cloneValues,
|
||||
setCurrentCandle: setCurrentCandle,
|
||||
setCurrentCycle: setCurrentCycle,
|
||||
initializeNode: initializeNode,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
}
|
||||
|
||||
let learningEngine
|
||||
let sessionParameters
|
||||
let nodesMap = new Map()
|
||||
|
||||
return thisObject
|
||||
|
||||
function initialize() {
|
||||
|
||||
learningEngine = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.learningEngine
|
||||
sessionParameters = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters
|
||||
|
||||
initializeNodeMap(learningEngine)
|
||||
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_FIRST_LOOP === true) {
|
||||
/*
|
||||
Here we will go through all the nodes in the Learning Engine hiriarchy and
|
||||
apply the initial value to the value property when needed
|
||||
*/
|
||||
initializeNode(learningEngine)
|
||||
}
|
||||
}
|
||||
|
||||
function finalize() {
|
||||
learningEngine = undefined
|
||||
sessionParameters = undefined
|
||||
nodesMap = undefined
|
||||
}
|
||||
|
||||
function mantain() {
|
||||
}
|
||||
|
||||
function reset() {
|
||||
|
||||
}
|
||||
|
||||
function getNodeById(NodeId) {
|
||||
return nodesMap.get(NodeId)
|
||||
}
|
||||
|
||||
function setCurrentCandle(candle) {
|
||||
learningEngine.current.episode.candle.begin.value = candle.begin
|
||||
learningEngine.current.episode.candle.end.value = candle.end
|
||||
learningEngine.current.episode.candle.open.value = candle.open
|
||||
learningEngine.current.episode.candle.close.value = candle.close
|
||||
learningEngine.current.episode.candle.min.value = candle.min
|
||||
learningEngine.current.episode.candle.max.value = candle.max
|
||||
}
|
||||
|
||||
function setCurrentCycle(cycle) {
|
||||
learningEngine.current.episode.cycle.value = cycle
|
||||
learningEngine.current.episode.cycle.lastBegin.value = learningEngine.current.episode.cycle.begin.value
|
||||
learningEngine.current.episode.cycle.lastEnd.value = learningEngine.current.episode.cycle.end.value
|
||||
switch (cycle) {
|
||||
case 'First': {
|
||||
learningEngine.current.episode.cycle.begin.value =
|
||||
learningEngine.current.episode.candle.begin.value +
|
||||
sessionParameters.timeFrame.config.value
|
||||
learningEngine.current.episode.cycle.end.value =
|
||||
learningEngine.current.episode.candle.begin.value +
|
||||
sessionParameters.timeFrame.config.value +
|
||||
sessionParameters.timeFrame.config.value / 2 - 1
|
||||
break
|
||||
}
|
||||
case 'Second': {
|
||||
learningEngine.current.episode.cycle.begin.value =
|
||||
learningEngine.current.episode.candle.begin.value +
|
||||
sessionParameters.timeFrame.config.value +
|
||||
sessionParameters.timeFrame.config.value / 2
|
||||
learningEngine.current.episode.cycle.end.value =
|
||||
learningEngine.current.episode.candle.begin.value +
|
||||
sessionParameters.timeFrame.config.value +
|
||||
sessionParameters.timeFrame.config.value * 4 / 4 - 1
|
||||
break
|
||||
}
|
||||
}
|
||||
/*
|
||||
We can not have the last begin or last end to be zero, because that would prevent
|
||||
objects starting with lastBegin in zero to being saved on file. For that reason
|
||||
we will do this:
|
||||
*/
|
||||
if (learningEngine.current.episode.cycle.lastBegin.value === 0) {
|
||||
learningEngine.current.episode.cycle.lastBegin.value = learningEngine.current.episode.cycle.begin.value
|
||||
}
|
||||
if (learningEngine.current.episode.cycle.lastEnd.value === 0) {
|
||||
learningEngine.current.episode.cycle.lastEnd.value = learningEngine.current.episode.cycle.end.value
|
||||
}
|
||||
}
|
||||
|
||||
function cloneValues(originNode, destinationNode) {
|
||||
if (originNode === undefined) { return }
|
||||
if (destinationNode === undefined) { return }
|
||||
|
||||
/* Here copy the node value */
|
||||
destinationNode.value = originNode.value
|
||||
|
||||
/* Now we go down through all the children of the origin node, assuming the destination node has the same children structure*/
|
||||
let schemaDocument = TS.projects.superalgos.globals.taskConstants.APP_SCHEMA_MAP.get(originNode.project + '-' + originNode.type)
|
||||
if (schemaDocument === undefined) { return }
|
||||
|
||||
if (schemaDocument.childrenNodesProperties !== undefined) {
|
||||
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
|
||||
for (let i = 0; i < schemaDocument.childrenNodesProperties.length; i++) {
|
||||
let property = schemaDocument.childrenNodesProperties[i]
|
||||
|
||||
switch (property.type) {
|
||||
case 'node': {
|
||||
if (property.name !== previousPropertyName) {
|
||||
if (originNode[property.name] !== undefined && destinationNode[property.name] !== undefined) {
|
||||
cloneValues(originNode[property.name], destinationNode[property.name])
|
||||
}
|
||||
previousPropertyName = property.name
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'array': {
|
||||
if (originNode[property.name] !== undefined && destinationNode[property.name] !== undefined) {
|
||||
let originNodePropertyArray = originNode[property.name]
|
||||
let destinationNodePropertyArray = destinationNode[property.name]
|
||||
for (let m = 0; m < originNodePropertyArray.length; m++) {
|
||||
cloneValues(originNodePropertyArray[m], destinationNodePropertyArray[m])
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initializeNodeMap(node) {
|
||||
if (node === undefined) { return }
|
||||
/* Add to Node Map */
|
||||
nodesMap.set(node.id, node)
|
||||
|
||||
/* Now we go down through all this node children */
|
||||
let schemaDocument = TS.projects.superalgos.globals.taskConstants.APP_SCHEMA_MAP.get(node.project + '-' + node.type)
|
||||
if (schemaDocument === undefined) { return }
|
||||
|
||||
if (schemaDocument.childrenNodesProperties !== undefined) {
|
||||
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
|
||||
for (let i = 0; i < schemaDocument.childrenNodesProperties.length; i++) {
|
||||
let property = schemaDocument.childrenNodesProperties[i]
|
||||
|
||||
switch (property.type) {
|
||||
case 'node': {
|
||||
if (property.name !== previousPropertyName) {
|
||||
if (node[property.name] !== undefined) {
|
||||
initializeNodeMap(node[property.name])
|
||||
}
|
||||
previousPropertyName = property.name
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'array': {
|
||||
if (node[property.name] !== undefined) {
|
||||
let nodePropertyArray = node[property.name]
|
||||
for (let m = 0; m < nodePropertyArray.length; m++) {
|
||||
initializeNodeMap(nodePropertyArray[m])
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initializeNode(node) {
|
||||
if (node === undefined) { return }
|
||||
|
||||
/* Here we initialize the node value */
|
||||
if (node.config !== undefined) {
|
||||
if (node.config.initialValue !== undefined) {
|
||||
node.value = node.config.initialValue
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we go down through all this node children */
|
||||
let schemaDocument = TS.projects.superalgos.globals.taskConstants.APP_SCHEMA_MAP.get(node.project + '-' + node.type)
|
||||
if (schemaDocument === undefined) { return }
|
||||
|
||||
if (schemaDocument.childrenNodesProperties !== undefined) {
|
||||
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
|
||||
for (let i = 0; i < schemaDocument.childrenNodesProperties.length; i++) {
|
||||
let property = schemaDocument.childrenNodesProperties[i]
|
||||
|
||||
switch (property.type) {
|
||||
case 'node': {
|
||||
if (property.name !== previousPropertyName) {
|
||||
if (node[property.name] !== undefined) {
|
||||
initializeNode(node[property.name])
|
||||
}
|
||||
previousPropertyName = property.name
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'array': {
|
||||
if (node[property.name] !== undefined) {
|
||||
let nodePropertyArray = node[property.name]
|
||||
for (let m = 0; m < nodePropertyArray.length; m++) {
|
||||
initializeNode(nodePropertyArray[m])
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+320
@@ -0,0 +1,320 @@
|
||||
exports.newSuperalgosBotModulesLearningEpisode = function (processIndex) {
|
||||
/*
|
||||
This module packages all functions related to Episodes.
|
||||
*/
|
||||
const MODULE_NAME = 'Learning Episode'
|
||||
let thisObject = {
|
||||
mantain: mantain,
|
||||
reset: reset,
|
||||
openEpisode: openEpisode,
|
||||
updateExitType: updateExitType,
|
||||
closeEpisode: closeEpisode,
|
||||
cycleBasedStatistics: cycleBasedStatistics,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
}
|
||||
|
||||
let learningEngine
|
||||
let learningSystem
|
||||
let sessionParameters
|
||||
|
||||
return thisObject
|
||||
|
||||
function initialize() {
|
||||
learningSystem = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.learningSystem
|
||||
learningEngine = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.learningEngine
|
||||
sessionParameters = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters
|
||||
}
|
||||
|
||||
function finalize() {
|
||||
learningEngine = undefined
|
||||
learningSystem = undefined
|
||||
sessionParameters = undefined
|
||||
}
|
||||
|
||||
function mantain() {
|
||||
updateCounters()
|
||||
updateStatistics()
|
||||
updateEnds()
|
||||
updateDistanceToEventsCounters()
|
||||
}
|
||||
|
||||
function reset() {
|
||||
resetLearningEngineDataStructure()
|
||||
}
|
||||
|
||||
function openEpisode() {
|
||||
/*
|
||||
This function is called each time the simulation starts. That does not mean the Episode
|
||||
must be opened there, since it might happen that it is looping at the end of the market
|
||||
or the task / session was restarted. We will only execute if the episode was never opened before.
|
||||
*/
|
||||
if (learningEngine.current.episode.begin.value !== learningEngine.current.episode.begin.config.initialValue) { return }
|
||||
|
||||
/* Starting begin and end */
|
||||
learningEngine.current.episode.begin.value = learningEngine.current.episode.candle.begin.value
|
||||
learningEngine.current.episode.end.value = learningEngine.current.episode.candle.end.value
|
||||
|
||||
/* Getting the begin Balance from the session configuration */
|
||||
learningEngine.current.episode.episodeBaseAsset.beginBalance.value = sessionParameters.sessionBaseAsset.config.initialBalance
|
||||
learningEngine.current.episode.episodeQuotedAsset.beginBalance.value = sessionParameters.sessionQuotedAsset.config.initialBalance
|
||||
|
||||
/* The current balance is also the begin balance, that is how this starts. */
|
||||
learningEngine.current.episode.episodeBaseAsset.balance.value = sessionParameters.sessionBaseAsset.config.initialBalance
|
||||
learningEngine.current.episode.episodeQuotedAsset.balance.value = sessionParameters.sessionQuotedAsset.config.initialBalance
|
||||
|
||||
/* Recording the opening at the Learning Engine Data Structure */
|
||||
learningEngine.current.episode.status.value = 'Open'
|
||||
learningEngine.current.episode.serialNumber.value = 1
|
||||
learningEngine.current.episode.identifier.value = TS.projects.superalgos.utilities.miscellaneousFunctions.genereteUniqueId()
|
||||
learningEngine.current.episode.beginRate.value = learningEngine.current.episode.candle.close.value
|
||||
}
|
||||
|
||||
function updateExitType(exitType) {
|
||||
learningEngine.current.episode.exitType.value = exitType
|
||||
}
|
||||
|
||||
function closeEpisode() {
|
||||
learningEngine.current.episode.status.value = 'Closed'
|
||||
learningEngine.current.episode.end.value = learningEngine.current.episode.candle.end.value
|
||||
learningEngine.current.episode.endRate.value = learningEngine.current.episode.candle.close.value
|
||||
learningEngine.current.episode.episodeBaseAsset.endBalance.value = learningEngine.current.episode.episodeBaseAsset.balance.value
|
||||
learningEngine.current.episode.episodeQuotedAsset.endBalance.value = learningEngine.current.episode.episodeQuotedAsset.balance.value
|
||||
}
|
||||
|
||||
function resetEpisode() {
|
||||
TS.projects.superalgos.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT.initializeNode(learningEngine.current.episode)
|
||||
}
|
||||
|
||||
function updateEnds() {
|
||||
if (learningEngine.current.episode.status.value === 'Open') {
|
||||
learningEngine.current.episode.end.value = learningEngine.current.episode.end.value + sessionParameters.timeFrame.config.value
|
||||
learningEngine.current.episode.endRate.value = learningEngine.current.episode.candle.close.value
|
||||
learningEngine.current.episode.episodeBaseAsset.endBalance.value = learningEngine.current.episode.episodeBaseAsset.balance.value
|
||||
learningEngine.current.episode.episodeQuotedAsset.endBalance.value = learningEngine.current.episode.episodeQuotedAsset.balance.value
|
||||
}
|
||||
}
|
||||
|
||||
function resetLearningEngineDataStructure() {
|
||||
if (learningEngine.current.episode.status.value === 'Closed') {
|
||||
resetEpisode()
|
||||
}
|
||||
}
|
||||
|
||||
function updateCounters() {
|
||||
if (learningEngine.current.episode.status.value === 'Open') {
|
||||
learningEngine.current.episode.episodeCounters.periods.value++
|
||||
}
|
||||
}
|
||||
|
||||
function updateStatistics() {
|
||||
|
||||
/* Daus Calculation */
|
||||
learningEngine.current.episode.episodeStatistics.days.value =
|
||||
learningEngine.current.episode.episodeCounters.periods.value *
|
||||
sessionParameters.timeFrame.config.value /
|
||||
TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS
|
||||
}
|
||||
|
||||
function cycleBasedStatistics() {
|
||||
|
||||
calculateAssetsStatistics()
|
||||
calculateEpisodeStatistics()
|
||||
|
||||
function calculateAssetsStatistics() {
|
||||
/* Updating Profit Loss */
|
||||
learningEngine.current.episode.episodeBaseAsset.profitLoss.value =
|
||||
learningEngine.current.episode.episodeBaseAsset.balance.value -
|
||||
sessionParameters.sessionBaseAsset.config.initialBalance
|
||||
|
||||
learningEngine.current.episode.episodeQuotedAsset.profitLoss.value =
|
||||
learningEngine.current.episode.episodeQuotedAsset.balance.value -
|
||||
sessionParameters.sessionQuotedAsset.config.initialBalance
|
||||
|
||||
learningEngine.current.episode.episodeBaseAsset.profitLoss.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(learningEngine.current.episode.episodeBaseAsset.profitLoss.value, 10)
|
||||
learningEngine.current.episode.episodeQuotedAsset.profitLoss.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(learningEngine.current.episode.episodeQuotedAsset.profitLoss.value, 10)
|
||||
|
||||
/*
|
||||
Updating ROI
|
||||
|
||||
https://www.investopedia.com/articles/basics/10/guide-to-calculating-roi.asp
|
||||
*/
|
||||
learningEngine.current.episode.episodeBaseAsset.ROI.value =
|
||||
learningEngine.current.episode.episodeBaseAsset.profitLoss.value /
|
||||
learningEngine.current.episode.episodeBaseAsset.beginBalance.value * 100
|
||||
|
||||
learningEngine.current.episode.episodeQuotedAsset.ROI.value =
|
||||
learningEngine.current.episode.episodeQuotedAsset.profitLoss.value /
|
||||
learningEngine.current.episode.episodeQuotedAsset.beginBalance.value * 100
|
||||
|
||||
learningEngine.current.episode.episodeBaseAsset.ROI.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(learningEngine.current.episode.episodeBaseAsset.ROI.value, 10)
|
||||
learningEngine.current.episode.episodeQuotedAsset.ROI.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(learningEngine.current.episode.episodeQuotedAsset.ROI.value, 10)
|
||||
|
||||
/* Updating Hit Ratio */
|
||||
if (learningEngine.current.episode.episodeCounters.positions.value > 0) {
|
||||
learningEngine.current.episode.episodeBaseAsset.hitRatio.value =
|
||||
learningEngine.current.episode.episodeBaseAsset.hits.value /
|
||||
learningEngine.current.episode.episodeCounters.positions.value
|
||||
|
||||
learningEngine.current.episode.episodeQuotedAsset.hitRatio.value =
|
||||
learningEngine.current.episode.episodeQuotedAsset.hits.value /
|
||||
learningEngine.current.episode.episodeCounters.positions.value
|
||||
|
||||
learningEngine.current.episode.episodeBaseAsset.hitRatio.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(learningEngine.current.episode.episodeBaseAsset.hitRatio.value, 10)
|
||||
learningEngine.current.episode.episodeQuotedAsset.hitRatio.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(learningEngine.current.episode.episodeQuotedAsset.hitRatio.value, 10)
|
||||
}
|
||||
|
||||
/*
|
||||
Updating Annualized Rate Of Return
|
||||
|
||||
https://www.investopedia.com/terms/a/annualized-rate.asp
|
||||
*/
|
||||
learningEngine.current.episode.episodeBaseAsset.annualizedRateOfReturn.value =
|
||||
Math.pow(
|
||||
(
|
||||
learningEngine.current.episode.episodeBaseAsset.beginBalance.value +
|
||||
learningEngine.current.episode.episodeBaseAsset.profitLoss.value
|
||||
) / learningEngine.current.episode.episodeBaseAsset.beginBalance.value
|
||||
,
|
||||
(365 / learningEngine.current.episode.episodeStatistics.days.value)
|
||||
) - 1
|
||||
|
||||
learningEngine.current.episode.episodeQuotedAsset.annualizedRateOfReturn.value =
|
||||
Math.pow(
|
||||
(
|
||||
learningEngine.current.episode.episodeQuotedAsset.beginBalance.value +
|
||||
learningEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
) / learningEngine.current.episode.episodeQuotedAsset.beginBalance.value
|
||||
,
|
||||
(365 / learningEngine.current.episode.episodeStatistics.days.value)
|
||||
) - 1
|
||||
|
||||
learningEngine.current.episode.episodeBaseAsset.annualizedRateOfReturn.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(learningEngine.current.episode.episodeBaseAsset.annualizedRateOfReturn.value, 10)
|
||||
learningEngine.current.episode.episodeQuotedAsset.annualizedRateOfReturn.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(learningEngine.current.episode.episodeQuotedAsset.annualizedRateOfReturn.value, 10)
|
||||
|
||||
/* Updating Hit or Fail */
|
||||
if (learningEngine.current.episode.episodeBaseAsset.profitLoss.value > 0) {
|
||||
learningEngine.current.episode.episodeBaseAsset.hitFail.value = 'Hit'
|
||||
} else {
|
||||
learningEngine.current.episode.episodeBaseAsset.hitFail.value = 'Fail'
|
||||
}
|
||||
if (learningEngine.current.episode.episodeQuotedAsset.profitLoss.value > 0) {
|
||||
learningEngine.current.episode.episodeQuotedAsset.hitFail.value = 'Hit'
|
||||
} else {
|
||||
learningEngine.current.episode.episodeQuotedAsset.hitFail.value = 'Fail'
|
||||
}
|
||||
}
|
||||
|
||||
function calculateEpisodeStatistics() {
|
||||
/* Updating Profit Loss */
|
||||
learningEngine.current.episode.episodeStatistics.profitLoss.value =
|
||||
learningEngine.current.episode.episodeBaseAsset.profitLoss.value * learningEngine.current.episode.candle.close.value +
|
||||
learningEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
|
||||
learningEngine.current.episode.episodeStatistics.profitLoss.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(learningEngine.current.episode.episodeStatistics.profitLoss.value, 10)
|
||||
|
||||
/*
|
||||
Updating ROI
|
||||
|
||||
https://www.investopedia.com/articles/basics/10/guide-to-calculating-roi.asp
|
||||
*/
|
||||
learningEngine.current.episode.episodeStatistics.ROI.value =
|
||||
(
|
||||
learningEngine.current.episode.episodeBaseAsset.profitLoss.value * learningEngine.current.episode.endRate.value +
|
||||
learningEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
) / (
|
||||
learningEngine.current.episode.episodeBaseAsset.beginBalance.value * learningEngine.current.episode.beginRate.value +
|
||||
learningEngine.current.episode.episodeQuotedAsset.beginBalance.value
|
||||
) * 100
|
||||
|
||||
learningEngine.current.episode.episodeStatistics.ROI.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(learningEngine.current.episode.episodeStatistics.ROI.value, 10)
|
||||
|
||||
/*
|
||||
Updating Annualized Rate Of Return
|
||||
|
||||
https://www.investopedia.com/terms/a/annualized-rate.asp
|
||||
*/
|
||||
learningEngine.current.episode.episodeStatistics.annualizedRateOfReturn.value =
|
||||
Math.pow(
|
||||
(
|
||||
learningEngine.current.episode.episodeBaseAsset.beginBalance.value * learningEngine.current.episode.beginRate.value +
|
||||
learningEngine.current.episode.episodeQuotedAsset.beginBalance.value +
|
||||
learningEngine.current.episode.episodeBaseAsset.profitLoss.value +
|
||||
learningEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
) /
|
||||
(
|
||||
learningEngine.current.episode.episodeBaseAsset.beginBalance.value * learningEngine.current.episode.beginRate.value +
|
||||
learningEngine.current.episode.episodeQuotedAsset.beginBalance.value
|
||||
)
|
||||
,
|
||||
(365 / learningEngine.current.episode.episodeStatistics.days.value)
|
||||
) - 1
|
||||
|
||||
learningEngine.current.episode.episodeStatistics.annualizedRateOfReturn.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(learningEngine.current.episode.episodeStatistics.annualizedRateOfReturn.value, 10)
|
||||
|
||||
/* Updating Hit or Fail */
|
||||
if (learningEngine.current.episode.episodeStatistics.profitLoss.value > 0) {
|
||||
learningEngine.current.episode.episodeStatistics.hitFail.value = 'Hit'
|
||||
} else {
|
||||
learningEngine.current.episode.episodeStatistics.hitFail.value = 'Fail'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateDistanceToEventsCounters() {
|
||||
/* Keeping Distance Counters Up-to-date while avoinding counting before the first event happens. */
|
||||
if (
|
||||
learningEngine.current.episode.distanceToEvent.triggerOn.value > 0
|
||||
) {
|
||||
learningEngine.current.episode.distanceToEvent.triggerOn.value++
|
||||
}
|
||||
|
||||
if (
|
||||
learningEngine.current.episode.distanceToEvent.triggerOff.value > 0
|
||||
) {
|
||||
learningEngine.current.episode.distanceToEvent.triggerOff.value++
|
||||
}
|
||||
|
||||
if (
|
||||
learningEngine.current.episode.distanceToEvent.takePosition.value > 0
|
||||
) {
|
||||
learningEngine.current.episode.distanceToEvent.takePosition.value++
|
||||
}
|
||||
|
||||
if (
|
||||
learningEngine.current.episode.distanceToEvent.closePosition.value > 0
|
||||
) {
|
||||
learningEngine.current.episode.distanceToEvent.closePosition.value++
|
||||
}
|
||||
|
||||
if (
|
||||
learningEngine.current.episode.distanceToEvent.nextPhase.value > 0
|
||||
) {
|
||||
learningEngine.current.episode.distanceToEvent.nextPhase.value++
|
||||
}
|
||||
|
||||
if (
|
||||
learningEngine.current.episode.distanceToEvent.moveToPhase.value > 0
|
||||
) {
|
||||
learningEngine.current.episode.distanceToEvent.moveToPhase.value++
|
||||
}
|
||||
|
||||
if (
|
||||
learningEngine.current.episode.distanceToEvent.createOrder.value > 0
|
||||
) {
|
||||
learningEngine.current.episode.distanceToEvent.createOrder.value++
|
||||
}
|
||||
|
||||
if (
|
||||
learningEngine.current.episode.distanceToEvent.cancelOrder.value > 0
|
||||
) {
|
||||
learningEngine.current.episode.distanceToEvent.cancelOrder.value++
|
||||
}
|
||||
|
||||
if (
|
||||
learningEngine.current.episode.distanceToEvent.closeOrder.value > 0
|
||||
) {
|
||||
learningEngine.current.episode.distanceToEvent.closeOrder.value++
|
||||
}
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
exports.newSuperalgosBotModulesLearningOutput = function (processIndex) {
|
||||
/*
|
||||
This module will load if necesary all the data outputs so that they can be appended with new
|
||||
records if needed. After running the simulation, it will save all the data outputs.
|
||||
*/
|
||||
const MODULE_NAME = 'Learning Output'
|
||||
|
||||
let thisObject = {
|
||||
start: start
|
||||
}
|
||||
|
||||
return thisObject
|
||||
|
||||
async function start(
|
||||
chart,
|
||||
market,
|
||||
exchange,
|
||||
timeFrame,
|
||||
timeFrameLabel,
|
||||
learningProcessDate
|
||||
) {
|
||||
try {
|
||||
let fileStorage = TS.projects.superalgos.taskModules.fileStorage.newFileStorage(processIndex)
|
||||
|
||||
if (timeFrame > TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[0][0]) {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES = false
|
||||
} else {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES = true
|
||||
}
|
||||
|
||||
/* Preparing everything for the Simulation */
|
||||
let learningSimulationModuleObject = TS.projects.superalgos.botModules.learningSimulation.newSuperalgosBotModulesLearningSimulation(processIndex)
|
||||
|
||||
let outputDatasets = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset')
|
||||
let outputDatasetsMap = new Map()
|
||||
|
||||
await TS.projects.superalgos.functionLibraries.outputManagementFunctions.readFiles(
|
||||
processIndex,
|
||||
outputDatasets,
|
||||
outputDatasetsMap,
|
||||
timeFrameLabel,
|
||||
learningProcessDate,
|
||||
fileStorage
|
||||
)
|
||||
|
||||
await learningSimulationModuleObject.runSimulation(
|
||||
chart,
|
||||
market,
|
||||
exchange,
|
||||
outputDatasetsMap,
|
||||
writeOutputFiles
|
||||
)
|
||||
|
||||
learningSimulationModuleObject.finalize()
|
||||
return
|
||||
|
||||
function writeOutputFiles() {
|
||||
TS.projects.superalgos.functionLibraries.outputManagementFunctions.writeFiles(
|
||||
processIndex,
|
||||
outputDatasets,
|
||||
outputDatasetsMap,
|
||||
timeFrameLabel,
|
||||
learningProcessDate,
|
||||
fileStorage
|
||||
)
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[ERROR] start -> err = ' + err.stack)
|
||||
throw (TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+320
@@ -0,0 +1,320 @@
|
||||
exports.newSuperalgosBotModulesLearningProcess = function (processIndex) {
|
||||
/*
|
||||
This Module will load all the process data dependencies from files and send them downstream.
|
||||
After execution, will save the time range and status report of the process.
|
||||
*/
|
||||
const MODULE_NAME = "Learning Process"
|
||||
|
||||
thisObject = {
|
||||
start: start
|
||||
}
|
||||
|
||||
return thisObject
|
||||
|
||||
async function start(statusDependencies, dataDependenciesModule, callBackFunction) {
|
||||
try {
|
||||
|
||||
let dataFiles = new Map()
|
||||
let multiTimeFrameDataFiles = new Map()
|
||||
TS.projects.superalgos.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT = TS.projects.superalgos.botModules.learningEngine.newSuperalgosBotModulesLearningEngine(processIndex)
|
||||
let learningOutputModuleObject = TS.projects.superalgos.botModules.learningOutput.newSuperalgosBotModulesLearningOutput(processIndex)
|
||||
|
||||
let currentTimeFrame = {}
|
||||
|
||||
/* Context Variables */
|
||||
let contextVariables = {
|
||||
lastFile: undefined, // Datetime of the last file files successfully 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.
|
||||
}
|
||||
|
||||
if (
|
||||
TS.projects.superalgos.functionLibraries.processFilesFunctions.getContextVariables(
|
||||
processIndex,
|
||||
contextVariables,
|
||||
statusDependencies,
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.initialDatetime,
|
||||
callBackFunction
|
||||
) !== true) { return }
|
||||
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_FIRST_LOOP === true && TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_RESUMING === false) {
|
||||
/*
|
||||
Here is where the Learning Engine and Learning Systems received are moved to the simulation state.
|
||||
*/
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.learningEngine = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_NODE
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.learningSystem = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_SYSTEM_NODE
|
||||
}
|
||||
|
||||
/* We set up the Learning Engine Module. */
|
||||
TS.projects.superalgos.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT.initialize()
|
||||
|
||||
/* Initializing the Learning Process Date */
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_FIRST_LOOP === true && TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_RESUMING === false) {
|
||||
/*
|
||||
This funcion is going to be called many times by the Learning 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.
|
||||
*/
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.learningEngine.current.episode.processDate.value =
|
||||
TS.projects.superalgos.utilities.dateTimeFunctions.removeTime(TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.initialDatetime).valueOf()
|
||||
}
|
||||
|
||||
/*
|
||||
This is the Date that is going to be used across the execution of this Learning Process.
|
||||
We need this because it has a different life cycle than the processData stored at the
|
||||
Learning Engine data structure. This date has to remain the same during the whole execution
|
||||
of the Learning Process until the end, inclusind the writting of Data Ranges and Status Reports.
|
||||
The processDate of the Learning 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 learningProcessDate = TS.projects.superalgos.utilities.dateTimeFunctions.removeTime(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.learningEngine.current.episode.processDate.value)
|
||||
|
||||
if (
|
||||
await TS.projects.superalgos.functionLibraries.dataDependenciesFunctions.processSingleFiles(
|
||||
processIndex,
|
||||
dataFiles,
|
||||
multiTimeFrameDataFiles,
|
||||
dataDependenciesModule
|
||||
) === false) {
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Waiting for Data Mining to be run')
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
if (await TS.projects.superalgos.functionLibraries.dataDependenciesFunctions.processMarketFiles(
|
||||
processIndex,
|
||||
dataFiles,
|
||||
multiTimeFrameDataFiles,
|
||||
dataDependenciesModule,
|
||||
currentTimeFrame,
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeFrame.config.label,
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.initialDatetime,
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeRange.config.finalDatetime
|
||||
) === false) {
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Waiting for Data Mining to be run')
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
/*
|
||||
These are the Data Structures used by end users at Conditions Code or Formulas.
|
||||
*/
|
||||
let chart = {}
|
||||
let market = {}
|
||||
let exchange = {}
|
||||
/*
|
||||
Here we check if we need to get Daily Files or not. As an optimization, when
|
||||
we are running on a Time Frame of 1hs or above, we are not going to load
|
||||
dependencies on Daily Files. The way we recognize that is by checking if
|
||||
we alreaady set a value to currentTimeFrame.value. We are also not going to loop
|
||||
through days if we are processing market files.
|
||||
*/
|
||||
if (currentTimeFrame.value) {
|
||||
/* We are processing Market Files */
|
||||
/*
|
||||
With all the indicators data files loaded, we will build the chart object
|
||||
data structure that will be used in user-defied conditions and formulas.
|
||||
*/
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Waking up')
|
||||
TS.projects.superalgos.functionLibraries.dataDependenciesFunctions.buildDataStructures(
|
||||
processIndex,
|
||||
dataDependenciesModule,
|
||||
multiTimeFrameDataFiles,
|
||||
currentTimeFrame,
|
||||
chart,
|
||||
market,
|
||||
exchange,
|
||||
callBackFunction
|
||||
)
|
||||
|
||||
if (checkThereAreCandles() === true) {
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Running')
|
||||
await outputManagement()
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Saving')
|
||||
await TS.projects.superalgos.functionLibraries.processFilesFunctions.writeProcessFiles(processIndex, contextVariables, currentTimeFrame, learningProcessDate, statusDependencies)
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Sleeping')
|
||||
} else {
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Waiting for Data Mining to be up to date. No candles found at.')
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
/* We are processing Daily Files */
|
||||
do {
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.emitSessionStatus(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_STATUS, TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY)
|
||||
/*
|
||||
We update the Learning 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 Learning Process Level.
|
||||
*/
|
||||
learningProcessDate = TS.projects.superalgos.utilities.dateTimeFunctions.removeTime(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.learningEngine.current.episode.processDate.value)
|
||||
|
||||
if (checkStopTaskGracefully() === false) { break }
|
||||
if (checkStopProcessing() === false) { break }
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Waking up')
|
||||
if (
|
||||
await TS.projects.superalgos.functionLibraries.dataDependenciesFunctions.processDailyFiles(
|
||||
processIndex,
|
||||
dataFiles,
|
||||
multiTimeFrameDataFiles,
|
||||
dataDependenciesModule,
|
||||
currentTimeFrame,
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeFrame.config.label,
|
||||
learningProcessDate
|
||||
) === false) {
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Waiting for Data Mining to be run')
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
/*
|
||||
With all the indicators data files loaded, we will build the chart object
|
||||
data structure that will be used in user-defied conditions and formulas.
|
||||
*/
|
||||
TS.projects.superalgos.functionLibraries.dataDependenciesFunctions.buildDataStructures(
|
||||
processIndex,
|
||||
dataDependenciesModule,
|
||||
multiTimeFrameDataFiles,
|
||||
currentTimeFrame,
|
||||
chart,
|
||||
market,
|
||||
exchange,
|
||||
callBackFunction
|
||||
)
|
||||
/*
|
||||
The process of generating the output includes the learning simulation.
|
||||
*/
|
||||
if (checkThereAreCandles() === true) {
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Running')
|
||||
await outputManagement()
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Saving')
|
||||
await TS.projects.superalgos.functionLibraries.processFilesFunctions.writeProcessFiles(processIndex, contextVariables, currentTimeFrame, learningProcessDate, statusDependencies)
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Sleeping')
|
||||
} else {
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Waiting for Data Mining to be up to date')
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
/*
|
||||
If for any reason the session was stopped, we will break this loop and exit the process.
|
||||
*/
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_STOPPING === true) { break }
|
||||
/*
|
||||
When we get to the end of the market, we need to break this process loop in order
|
||||
to let time pass, new information be collected from the exchange, new data built
|
||||
into indicators, and eventually a new execution of this process.
|
||||
*/
|
||||
if (checkStopHeadOfTheMarket() === false) { break }
|
||||
|
||||
}
|
||||
while (true)
|
||||
}
|
||||
|
||||
checkIfSessionMustStop()
|
||||
/*
|
||||
Everything worked as expected. We return an OK code and wait for
|
||||
the Bot Loop to call us again later.
|
||||
*/
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE)
|
||||
|
||||
function checkThereAreCandles() {
|
||||
let sessionParameters = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters
|
||||
let propertyName = 'at' + sessionParameters.timeFrame.config.label.replace('-', '')
|
||||
let candles = chart[propertyName].candles
|
||||
|
||||
if (candles.length === 0) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
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 (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.learningEngine.current.episode.headOfTheMarket.value === true) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function checkStopTaskGracefully() {
|
||||
/* Validation that we dont need to stop. */
|
||||
if (TS.projects.superalgos.globals.taskVariables.IS_TASK_STOPPING === true) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function checkStopProcessing() {
|
||||
/* Validation that we dont need to stop. */
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_STOPPING === true) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function outputManagement() {
|
||||
await learningOutputModuleObject.start(
|
||||
chart,
|
||||
market,
|
||||
exchange,
|
||||
currentTimeFrame.value,
|
||||
currentTimeFrame.label,
|
||||
learningProcessDate
|
||||
)
|
||||
|
||||
/*
|
||||
From here on, all other loops executions wont be the first execution and also
|
||||
we will consider that it is not resuming a previous execution as well.
|
||||
*/
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_FIRST_LOOP = false
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_RESUMING = false
|
||||
}
|
||||
|
||||
function checkIfSessionMustStop() {
|
||||
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.type === 'Backtesting Session') {
|
||||
/*
|
||||
Backtests needs only one execution of this process to complete.
|
||||
*/
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[IMPORTANT] checkIfSessionMustStop -> Backtesting Session Finished. Stopping the Session now. ')
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.stopSession(processIndex, 'Backtesting Session Finished.')
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
/* An unhandled exception occured. in this case we return Fail and log the stack. */
|
||||
if (err.stack) {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> Unhandled Exception. Will Abort this process. err = " + err.stack)
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.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.') {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] File not Found. Will Retry the Process Loop.")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
/* Some other handled exception occured. We return Fail and move on. */
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> Handled Exception. Will Abort this process. err = " + err.message)
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+419
@@ -0,0 +1,419 @@
|
||||
exports.newSuperalgosBotModulesLearningRecords = function (processIndex) {
|
||||
/*
|
||||
This module facilitates the appending of records to the output of the process.
|
||||
*/
|
||||
const MODULE_NAME = 'Learning Records'
|
||||
|
||||
let thisObject = {
|
||||
appendRecords: appendRecords,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
}
|
||||
|
||||
let learningEngine
|
||||
let learningSystem
|
||||
let sessionParameters
|
||||
let outputDatasetsMap
|
||||
|
||||
return thisObject
|
||||
|
||||
function initialize(pOutputDatasetsMap) {
|
||||
learningEngine = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.learningEngine
|
||||
learningSystem = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.learningSystem
|
||||
sessionParameters = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters
|
||||
outputDatasetsMap = pOutputDatasetsMap // These are the files turned into arrays, stored in a Map by Product codeName.
|
||||
}
|
||||
|
||||
function finalize() {
|
||||
learningEngine = undefined
|
||||
learningSystem = undefined
|
||||
sessionParameters = undefined
|
||||
outputDatasetsMap = undefined
|
||||
}
|
||||
|
||||
function appendRecords() {
|
||||
/*
|
||||
Here we add records to the output files. At the product config property nodePath
|
||||
we have a pointer to the node that have the information we need to extract.
|
||||
Later, based on the product record definition we will extract each individual value.
|
||||
*/
|
||||
let outputDatasets = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset')
|
||||
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
let product = dataset.parentNode
|
||||
let outputDatasetArray = outputDatasetsMap.get(product.config.codeName)
|
||||
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES === true && dataset.config.type === 'Daily Files') {
|
||||
persistRecords()
|
||||
}
|
||||
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES === false && dataset.config.type === 'Market Files') {
|
||||
persistRecords()
|
||||
}
|
||||
|
||||
function persistRecords() {
|
||||
/*
|
||||
There are a few products configured to be saved only at an specific cycle.
|
||||
*/
|
||||
if (product.config.saveAtCycle !== undefined) {
|
||||
if (learningEngine.current.episode.cycle.value !== product.config.saveAtCycle) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean the file from information of previous executions */
|
||||
//pruneOutputFile(product, outputDatasetArray, learningEngine.current.episode.candle.end.value)
|
||||
|
||||
/* Clean Open Records */
|
||||
if (product.config.saveAsObjects === true) {
|
||||
for (let j = 0; j < product.record.properties.length; j++) {
|
||||
let recordProperty = product.record.properties[j]
|
||||
if (recordProperty.config.codeName === product.config.propertyNameThatDefinesObject) {
|
||||
/* Remove Open Records */
|
||||
spliceOpenRecords(j, product, outputDatasetArray)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
The product root can be a node or a node property of type array.
|
||||
*/
|
||||
let productRoot
|
||||
try {
|
||||
productRoot = eval(product.config.nodePath)
|
||||
} catch (err) {
|
||||
badDefinitionUnhandledException(err, 'Cannot get productRoot -> nodePath = ' + product.config.nodePath, product, undefined)
|
||||
}
|
||||
|
||||
if (product.config.nodePathType === 'array') {
|
||||
/*
|
||||
This means that the configured nodePath is not pointing to a node, but to a node property that is an array.
|
||||
For that reason we will assume that each element of the array is a record to be outputed
|
||||
*/
|
||||
for (let index = 0; index < productRoot.length; index++) {
|
||||
/*
|
||||
The Product Root Node is the root of the node hiriarchy from where we are going to extract the record values.
|
||||
*/
|
||||
let productRootNode = productRoot[index]
|
||||
let record = scanRecordDefinition(product, productRootNode, index)
|
||||
if (record !== undefined) {
|
||||
/*
|
||||
We will add the index value to the record itself, so that the plotter can know to which
|
||||
brach of the learning engine data structure it belongs.
|
||||
*/
|
||||
record.push(index)
|
||||
persistIndividualRecord(record, product, outputDatasetArray)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
This means that the configured nodePath points to a single node, which is the one whose children constitutes
|
||||
the record to be saved at the output file.
|
||||
*/
|
||||
/*
|
||||
The Product Root Node is the root of the node hiriarchy from where we are going to extract the record values.
|
||||
*/
|
||||
let productRootNode = productRoot
|
||||
let record = scanRecordDefinition(product, productRootNode)
|
||||
if (record !== undefined) {
|
||||
persistIndividualRecord(record, product, outputDatasetArray)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function scanRecordDefinition(product, productRootNode, index) {
|
||||
|
||||
let record = []
|
||||
for (let j = 0; j < product.record.properties.length; j++) {
|
||||
let recordProperty = product.record.properties[j]
|
||||
/*
|
||||
The Property Root Node is the Root of the Hiriarchy branch we must find in order
|
||||
to get the node where we are going to extract the value. Initially
|
||||
we point it to the Product Root Node, because that is the default in case
|
||||
a property does not have at its configuration a different nodePath configured
|
||||
pointing to an specific Root for the property.
|
||||
*/
|
||||
let propertyRootNode = productRootNode
|
||||
/*
|
||||
If we find at the configuration a nodePath, then we take this path to find
|
||||
the Root Node specifically for this property only.
|
||||
*/
|
||||
if (recordProperty.config.nodePath !== undefined) {
|
||||
if (recordProperty.config.nodePath === "learningEngine.exchangeOrders.marketBuyOrders.marketOrders[index].orderBaseAsset") {
|
||||
let a = learningEngine
|
||||
}
|
||||
try {
|
||||
propertyRootNode = eval(recordProperty.config.nodePath)
|
||||
} catch (err) {
|
||||
badDefinitionUnhandledException(err, 'Error Evaluating Record Property nodePath -> nodePath = ' + recordProperty.config.nodePath, product, recordProperty)
|
||||
}
|
||||
}
|
||||
/*
|
||||
The Target Node is the node from where we are going to exctract the value.
|
||||
We will use the codeName of the Record Property to match it with
|
||||
any of the properties of the Root Node to get the Target Node.
|
||||
*/
|
||||
let targetNode
|
||||
try {
|
||||
targetNode = propertyRootNode[recordProperty.config.codeName]
|
||||
} catch (err) {
|
||||
badDefinitionUnhandledException(err, 'Error setting Target Node.', product, recordProperty)
|
||||
}
|
||||
/*
|
||||
If the codeName of the Record Property can not match the name of the property at
|
||||
the target node, the user can explicitly specify the property name at the configuration,
|
||||
and in those cases we need to use that. This happens when there are many Record Properties
|
||||
pointing to the same property at the Target Node.
|
||||
*/
|
||||
if (recordProperty.config.childProperty !== undefined) {
|
||||
targetNode = propertyRootNode[recordProperty.config.childProperty]
|
||||
}
|
||||
/*
|
||||
It can happen that intead of having a Node in targetNode what we have is an
|
||||
array of nodes. We need to pick one of the elements of the array and for that
|
||||
we use the Index value we find at the configuration of the Record Property.
|
||||
*/
|
||||
if (recordProperty.config.index !== undefined) {
|
||||
try {
|
||||
targetNode = targetNode[recordProperty.config.index]
|
||||
} catch (err) {
|
||||
badDefinitionUnhandledException(err, 'Error setting Target Node.', product, recordProperty)
|
||||
}
|
||||
}
|
||||
/*
|
||||
By Default the value is extracted from the value property of the Target Node.
|
||||
But it might happen the the Target Node does not exist for example when there is an Array
|
||||
of Nodes defined in the Record Properties but not all of them exist at the Root Node.
|
||||
We filter out those cases by not extracting the value from the value property.
|
||||
*/
|
||||
let value = 0 // This is a default value, since we do not want null in files because it breakes JSON format.
|
||||
if (targetNode !== undefined) {
|
||||
if (targetNode.type !== undefined) {
|
||||
/*
|
||||
In this case the Target Node is really a node (since it has a type), so we extract the value
|
||||
from its value property.
|
||||
*/
|
||||
value = targetNode.value
|
||||
|
||||
if (recordProperty.config.decimals !== undefined) {
|
||||
try {
|
||||
value = Number(value.toFixed(recordProperty.config.decimals))
|
||||
} catch (err) {
|
||||
badDefinitionUnhandledException(err, 'Error applying configured decimals.', product, recordProperty)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
In this case the Target Node is not really node, but the value itself. Se we return this as the
|
||||
value of the Record Property.
|
||||
*/
|
||||
value = targetNode
|
||||
}
|
||||
}
|
||||
|
||||
/* We are not going to add records where the begin or end are missing */
|
||||
if (
|
||||
recordProperty.config.codeName === 'begin' && value === 0 ||
|
||||
recordProperty.config.codeName === 'end' && value === 0
|
||||
) { return }
|
||||
|
||||
if (recordProperty.config.isString !== true && Array.isArray(value) !== true) {
|
||||
value = safeNumericValue(value)
|
||||
}
|
||||
if (recordProperty.config.isString === true && Array.isArray(value) !== true) {
|
||||
value = safeStringValue(value)
|
||||
}
|
||||
record.push(value)
|
||||
}
|
||||
return record
|
||||
}
|
||||
|
||||
function persistIndividualRecord(record, product, outputDatasetArray) {
|
||||
|
||||
if (product.config.saveAsObjects === true) {
|
||||
/* For saving objects we need to take care of a different set of rules. */
|
||||
for (let j = 0; j < product.record.properties.length; j++) {
|
||||
let recordProperty = product.record.properties[j]
|
||||
if (recordProperty.config.codeName === product.config.propertyNameThatDefinesObject) {
|
||||
let propertyValue = record[j]
|
||||
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES) {
|
||||
if (product.config.doNotCutObjectInDays !== true) {
|
||||
/*
|
||||
By default we will cut objects in days.
|
||||
*/
|
||||
if (propertyValue !== product.config.propertyValueThatPreventsSavingObject) {
|
||||
outputDatasetArray.push(record)
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
When dealing with Daily Files, we need to avoid to write an open object at the last 'candle' of the day,
|
||||
since the object will be duplicated on the next day. How do we know we are positioned at the last candle
|
||||
of the day? Easy: the end of the candle must be 1 millisecod before the next day. That happens at any
|
||||
time frame.
|
||||
*/
|
||||
let currentDay = new Date(learningEngine.current.episode.candle.end.value)
|
||||
let nextDay = new Date(learningEngine.current.episode.candle.end.value + 1)
|
||||
if (currentDay.getUTCDate() !== nextDay.getUTCDate()) {
|
||||
/*
|
||||
We will save the object only if it is closed, becasuse we are at the last candle of the day.
|
||||
*/
|
||||
if (propertyValue === product.config.propertyValueThatClosesObject) {
|
||||
outputDatasetArray.push(record)
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
When we are not at the end of the day, we will save the object normally, like in market files.
|
||||
*/
|
||||
if (propertyValue !== product.config.propertyValueThatPreventsSavingObject) {
|
||||
outputDatasetArray.push(record)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*
|
||||
For Market Files we will add a record everytime that proeprty value does not match this
|
||||
*/
|
||||
if (propertyValue !== product.config.propertyValueThatPreventsSavingObject) {
|
||||
outputDatasetArray.push(record)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
When we are not dealing with objects, we add every record to the existing file except
|
||||
for the ones that are filtered out at the Product Definition.
|
||||
*/
|
||||
if (product.config.codeName === "Learning-System-Errors") {
|
||||
let a = 1
|
||||
}
|
||||
if (product.config.propertyNameThatDefinesStatus !== undefined && product.config.propertyValueThatPreventsSavingObject !== undefined) {
|
||||
for (let j = 0; j < product.record.properties.length; j++) {
|
||||
let recordProperty = product.record.properties[j]
|
||||
if (recordProperty.config.codeName === product.config.propertyNameThatDefinesStatus) {
|
||||
let propertyValue = record[j]
|
||||
|
||||
if (product.config.propertyValueThatPreventsSavingObject === "->Empty Array->" && propertyValue.length === 0) {
|
||||
break
|
||||
}
|
||||
if (propertyValue !== product.config.propertyValueThatPreventsSavingObject) {
|
||||
outputDatasetArray.push(record)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
outputDatasetArray.push(record)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function safeNumericValue(value) {
|
||||
/*
|
||||
The purpose of this function is to check that value variable does not have a value that
|
||||
will later break the JSON format of files where this is going to be stored at.
|
||||
*/
|
||||
if (value === Infinity) {
|
||||
value = Number.MAX_SAFE_INTEGER
|
||||
}
|
||||
if (value === undefined) {
|
||||
value = 0
|
||||
}
|
||||
if (value === null) {
|
||||
value = 0
|
||||
}
|
||||
if (isNaN(value)) {
|
||||
value = 0
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
function safeStringValue(value) {
|
||||
/*
|
||||
The purpose of this function is to check that value variable does not have a value that
|
||||
will later break the JSON format of files where this is going to be stored at.
|
||||
*/
|
||||
if (value === undefined) {
|
||||
value = ''
|
||||
}
|
||||
if (value === null) {
|
||||
value = ''
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
function pruneOutputFile(product, outputFile, currentEnd) {
|
||||
if (outputFile.isPrunned === true) { return }
|
||||
/*
|
||||
When a session is resumed, we will be potentially reading output files belonging to a previous session execution.
|
||||
For that reason we need to prune all the records that are beyond the current candle. We do not delete everything
|
||||
because we might be resuming a stopped session, which is fine.
|
||||
*/
|
||||
for (let i = 0; i < outputFile.length; i++) {
|
||||
let record = outputFile[i]
|
||||
|
||||
for (let j = 0; j < product.record.properties.length; j++) {
|
||||
let recordProperty = product.record.properties[j]
|
||||
if (recordProperty.config.codeName === 'end') {
|
||||
let end = record[j]
|
||||
if (end >= currentEnd) {
|
||||
outputFile.splice(i, 1)
|
||||
/*
|
||||
This will execute the next prune call in the next iteration of the NodeJs event loop
|
||||
allowing for other callbacks to be executed. It also prevents the error
|
||||
'Maximum call stack size exceeded', since the call is not placed at the call stack.
|
||||
*/
|
||||
setImmediate(pruneOutputFile, product, outputFile, currentEnd)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
outputFile.isPrunned = true
|
||||
}
|
||||
|
||||
function spliceOpenRecords(j, product, outputDatasetArray) {
|
||||
/*
|
||||
Before adding records to the output file, we need to remove all open records,
|
||||
because we will be adding the same records later with potentially
|
||||
new or updated information.
|
||||
*/
|
||||
|
||||
for (let i = 0; i < outputDatasetArray.length; i++) {
|
||||
let dataRecord = outputDatasetArray[i]
|
||||
if (dataRecord !== undefined) {
|
||||
let dataRecordValue = dataRecord[j]
|
||||
if (dataRecordValue !== product.config.propertyValueThatClosesObject) {
|
||||
outputDatasetArray.splice(i, 1)
|
||||
spliceOpenRecords(j, product, outputDatasetArray)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function badDefinitionUnhandledException(err, message, product, recordProperty) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] appendRecords -> " + message);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] appendRecords -> product.name = " + product.name);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] appendRecords -> product.config = " + JSON.stringify(product.config));
|
||||
|
||||
if (recordProperty) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] appendRecords -> recordProperty.name = " + recordProperty.name);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] appendRecords -> recordProperty.config.codeName = " + recordProperty.config.codeName);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] appendRecords -> recordProperty.config = " + JSON.stringify(recordProperty.config));
|
||||
}
|
||||
|
||||
if (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] appendRecords -> err.stack = " + err.stack);
|
||||
}
|
||||
throw 'Can not continue with a Definition Error like this.'
|
||||
}
|
||||
}
|
||||
+678
@@ -0,0 +1,678 @@
|
||||
exports.newSuperalgosBotModulesLearningSimulation = function (processIndex) {
|
||||
/*
|
||||
This Module represents the learning simulacion. Escentially a loop through a set of candles and
|
||||
the execution at each loop cycle of the Learning System Protocol.
|
||||
*/
|
||||
const MODULE_NAME = 'Learning Simulation -> ' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.name
|
||||
|
||||
let thisObject = {
|
||||
finalize: finalize,
|
||||
runSimulation: runSimulation
|
||||
}
|
||||
return thisObject
|
||||
|
||||
function finalize() {
|
||||
thisObject = undefined
|
||||
}
|
||||
|
||||
async function runSimulation(
|
||||
chart,
|
||||
market,
|
||||
exchange,
|
||||
outputDatasetsMap,
|
||||
writeFiles,
|
||||
) {
|
||||
try {
|
||||
|
||||
let learningSystem = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.learningSystem
|
||||
let learningEngine = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.learningEngine
|
||||
let sessionParameters = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[INFO] runSimulation -> initialDatetime = ' + sessionParameters.timeRange.config.initialDatetime)
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[INFO] runSimulation -> finalDatetime = ' + sessionParameters.timeRange.config.finalDatetime)
|
||||
|
||||
/* These are the Modules we will need to run the Simulation */
|
||||
let learningRecordsModuleObject = TS.projects.superalgos.botModules.learningRecords.newSuperalgosBotModulesLearningRecords(processIndex)
|
||||
learningRecordsModuleObject.initialize(outputDatasetsMap)
|
||||
|
||||
let learningSystemModuleObject = TS.projects.superalgos.botModules.learningSystem.newSuperalgosBotModulesLearningSystem(processIndex)
|
||||
learningSystemModuleObject.initialize()
|
||||
|
||||
let learningEpisodeModuleObject = TS.projects.superalgos.botModules.learningEpisode.newSuperalgosBotModulesLearningEpisode(processIndex)
|
||||
learningEpisodeModuleObject.initialize()
|
||||
|
||||
/* Setting up the candles array: The whole simulation is based on the array of candles at the time-frame defined at the session parameters. */
|
||||
let propertyName = 'at' + sessionParameters.timeFrame.config.label.replace('-', '')
|
||||
let candles = chart[propertyName].candles
|
||||
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES) {
|
||||
/*
|
||||
We need to purge from the candles array all the candles from the previous day
|
||||
that comes when processing daily files.
|
||||
*/
|
||||
let dailyCandles = []
|
||||
for (let i = 0; i < candles.length; i++) {
|
||||
let candle = candles[i]
|
||||
if (candle.begin >= TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.learningEngine.current.episode.processDate.value) {
|
||||
dailyCandles.push(candle)
|
||||
}
|
||||
}
|
||||
candles = dailyCandles
|
||||
} else {
|
||||
candles = chart[propertyName].candles
|
||||
}
|
||||
|
||||
/* Variables needed for heartbeat functionality */
|
||||
let heartBeatDate
|
||||
let previousHeartBeatDate
|
||||
/*
|
||||
Estimation of the Initial Candle to Process in this Run.
|
||||
*/
|
||||
let initialCandle
|
||||
if (
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_FIRST_LOOP === true &&
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_RESUMING === false) {
|
||||
|
||||
/* Estimate Initial Candle based on the timeRange configured for the session. */
|
||||
let firstEnd = candles[0].end
|
||||
let targetEnd = sessionParameters.timeRange.config.initialDatetime
|
||||
let diff = targetEnd - firstEnd
|
||||
let amount = diff / sessionParameters.timeFrame.config.value
|
||||
|
||||
initialCandle = Math.trunc(amount)
|
||||
if (initialCandle < 0) { initialCandle = 0 }
|
||||
if (initialCandle > candles.length - 1) {
|
||||
/*
|
||||
This will happen when the sessionParameters.timeRange.config.initialDatetime is beyond the last candle available,
|
||||
meaning that the dataSet needs to be updated with more up-to-date data.
|
||||
*/
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.stopSession(processIndex, 'Data is not up-to-date enough. Please start the Masters Data Mining Operation.')
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[IMPORTANT] runSimulation -> Data is not up-to-date enough. Stopping the Session now. ')
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
/*
|
||||
In this case we already have at the last candle index the next candle to be
|
||||
processed. We will just continue with this candle.
|
||||
*/
|
||||
initialCandle = learningEngine.current.episode.candle.index.value
|
||||
}
|
||||
/*
|
||||
Main Simulation Loop
|
||||
*/
|
||||
/* We are going to use this to exit the loop if needed. */
|
||||
let breakLoop = false
|
||||
|
||||
/*
|
||||
We will assume that we are at the head of the market here. We do this
|
||||
because the loop could be empty and no validation is going to run. If the
|
||||
loop is not empty, then the lascCandle() check will override this value
|
||||
depending on if we really are at the head of the market or not.
|
||||
*/
|
||||
learningEngine.current.episode.headOfTheMarket.value = true
|
||||
/*
|
||||
This is the main simulation loop. It will go through the initial candle
|
||||
until one less than the last candle available. We will never process the last
|
||||
candle available since it is not considered a closed candle, but a candle
|
||||
that still can change. So effectively will be processing all closed candles.
|
||||
*/
|
||||
for (let i = initialCandle; i < candles.length - 1; i++) {
|
||||
learningEngine.current.episode.candle.index.value = i
|
||||
|
||||
/* This is the current candle the Simulation is working at. */
|
||||
let candle = candles[learningEngine.current.episode.candle.index.value]
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[INFO] runSimulation -> loop -> Candle Begin @ ' + (new Date(candle.begin)).toUTCString())
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[INFO] runSimulation -> loop -> Candle End @ ' + (new Date(candle.end)).toUTCString())
|
||||
|
||||
TS.projects.superalgos.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT.setCurrentCandle(candle) // We move the current candle we are standing at, to the learning engine data structure to make it available to anyone, including conditions and formulas.
|
||||
|
||||
/* We emit a heart beat so that the UI can now where we are at the overal process.*/
|
||||
heartBeat()
|
||||
|
||||
/* Opening the Episode, if needed. */
|
||||
learningEpisodeModuleObject.openEpisode()
|
||||
|
||||
if (checkInitialDatetime() === false) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[INFO] runSimulation -> loop -> Candle Before the Initia Date Time @ ' + (new Date(candle.begin)).toUTCString())
|
||||
continue
|
||||
}
|
||||
|
||||
positionDataStructuresAtCurrentCandle()
|
||||
|
||||
/* The chart was recalculated based on the current candle. */
|
||||
learningSystemModuleObject.updateChart(
|
||||
chart,
|
||||
exchange,
|
||||
market
|
||||
)
|
||||
|
||||
/*
|
||||
Do the stuff needed previous to the run like
|
||||
Episode Counters and Statistics update. Mantaince is done
|
||||
once per simulation candle.
|
||||
*/
|
||||
learningSystemModuleObject.mantain()
|
||||
learningEpisodeModuleObject.mantain()
|
||||
TS.projects.superalgos.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT.mantain()
|
||||
|
||||
/*
|
||||
Run the first cycle of the Learning System. In this first cycle we
|
||||
give some room so that orders can be canceled or filled and we can
|
||||
write those records into the output memory. During this cycle new
|
||||
orders can not be created, since otherwise the could be cancelled at
|
||||
the second cycle without spending real time at the order book.
|
||||
*/
|
||||
TS.projects.superalgos.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT.setCurrentCycle('First')
|
||||
await runCycle()
|
||||
|
||||
/*
|
||||
We check if we need to stop before appending the records so that the stop
|
||||
reason is also propery recorded. Note also that we check this after the first
|
||||
cycle, where orders have not been submitted to the exchange yet, but we
|
||||
had the chance to check for the status of placed orders or even cancel
|
||||
the ones that needed cancellation.
|
||||
*/
|
||||
checkIfWeNeedToStopBetweenCycles()
|
||||
|
||||
/* Add new records to the process output */
|
||||
learningRecordsModuleObject.appendRecords()
|
||||
|
||||
if (breakLoop === true) { break }
|
||||
/*
|
||||
Run the second cycle of the Learning System. During this second run
|
||||
some new orders might be created at slots freed up during the first
|
||||
run. This allows for example for a Limit Order to be cancelled during the
|
||||
first run, and the same Limit Order definition to spawn a new order
|
||||
without the need to wait until the next candle. Orders can not be cancelled
|
||||
during the second cycle.
|
||||
*/
|
||||
TS.projects.superalgos.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT.setCurrentCycle('Second')
|
||||
await runCycle()
|
||||
|
||||
checkIfWeNeedToStopAfterBothCycles()
|
||||
|
||||
/* Add new records to the process output */
|
||||
learningRecordsModuleObject.appendRecords()
|
||||
|
||||
if (breakLoop === true) { break }
|
||||
|
||||
async function runCycle() {
|
||||
/* Reset Data Structures */
|
||||
learningSystemModuleObject.reset()
|
||||
learningEpisodeModuleObject.reset()
|
||||
TS.projects.superalgos.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT.reset()
|
||||
|
||||
let infoMessage = 'Processing candle # ' + learningEngine.current.episode.candle.index.value + ' @ the ' + learningEngine.current.episode.cycle.value + ' cycle.'
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[INFO] runSimulation -> loop -> ' + infoMessage)
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS LF Learning Bot Info - Candle And Cycle',
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
contextInfo = {
|
||||
candleIndex: learningEngine.current.episode.candle.index.value,
|
||||
cycle: learningEngine.current.episode.cycle.value
|
||||
}
|
||||
TS.projects.superalgos.utilities.docsFunctions.buildPlaceholder(docs, undefined, undefined, undefined, undefined, undefined, contextInfo)
|
||||
|
||||
learningSystem.addInfo([learningSystem.id, infoMessage, docs])
|
||||
|
||||
await learningSystemModuleObject.run()
|
||||
}
|
||||
|
||||
function checkIfWeNeedToStopBetweenCycles() {
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_STOPPING === true) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing this session.')
|
||||
updateEpisode('Session Stopped')
|
||||
breakLoop = true
|
||||
return
|
||||
}
|
||||
|
||||
if (TS.projects.superalgos.globals.taskVariables.IS_TASK_STOPPING === true) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing this task.')
|
||||
updateEpisode('Task Stopped')
|
||||
breakLoop = true
|
||||
return
|
||||
}
|
||||
|
||||
if (checkFinalDatetime() === false) {
|
||||
closeEpisode('Final Datetime Reached')
|
||||
breakLoop = true
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.stopSession(processIndex, 'Final Datetime Reached')
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[IMPORTANT] runSimulation -> Final Datetime Reached. Stopping the Session now. ')
|
||||
return
|
||||
}
|
||||
|
||||
if (checkMinimunAndMaximunBalance() === false) {
|
||||
closeEpisode('Min or Max Balance Reached')
|
||||
breakLoop = true
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.stopSession(processIndex, 'Min or Max Balance Reached')
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[IMPORTANT] runSimulation -> Min or Max Balance Reached. Stopping the Session now. ')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function checkIfWeNeedToStopAfterBothCycles() {
|
||||
if (checkNextCandle() === false) {
|
||||
updateEpisode('All Candles Processed')
|
||||
breakLoop = true
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
learningSystemModuleObject.finalize()
|
||||
learningRecordsModuleObject.finalize()
|
||||
learningEpisodeModuleObject.finalize()
|
||||
|
||||
learningSystemModuleObject = undefined
|
||||
learningRecordsModuleObject = undefined
|
||||
learningEpisodeModuleObject = undefined
|
||||
|
||||
await writeFiles()
|
||||
|
||||
function closeEpisode(exitType) {
|
||||
learningEpisodeModuleObject.updateExitType(exitType)
|
||||
learningEpisodeModuleObject.closeEpisode()
|
||||
}
|
||||
|
||||
function updateEpisode(exitType) {
|
||||
learningEpisodeModuleObject.updateExitType(exitType)
|
||||
}
|
||||
|
||||
function heartBeat() {
|
||||
let hartbeatText = ''
|
||||
if (sessionParameters.heartbeats !== undefined) {
|
||||
if (sessionParameters.heartbeats.config.date === true || sessionParameters.heartbeats.config.candleIndex === true) {
|
||||
/* We will produce a simulation level heartbeat in order to inform the user this is running. */
|
||||
|
||||
heartBeatDate = new Date(Math.trunc(learningEngine.current.episode.candle.begin.value / TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS) * TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS)
|
||||
|
||||
let fromDate = new Date(sessionParameters.timeRange.config.initialDatetime)
|
||||
let lastDate = new Date(sessionParameters.timeRange.config.finalDatetime)
|
||||
|
||||
let currentDateString = heartBeatDate.getUTCFullYear() + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(heartBeatDate.getUTCMonth() + 1, 2) + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(heartBeatDate.getUTCDate(), 2)
|
||||
let currentDate = new Date(heartBeatDate)
|
||||
let percentage = TS.projects.superalgos.utilities.dateTimeFunctions.getPercentage(fromDate, currentDate, lastDate)
|
||||
/*
|
||||
Theere are a few tasks that we need to do only when the date changes,
|
||||
otherwise it would be suboptimal.
|
||||
*/
|
||||
if (heartBeatDate.valueOf() !== previousHeartBeatDate) {
|
||||
previousHeartBeatDate = heartBeatDate.valueOf()
|
||||
|
||||
let processingDate = heartBeatDate.getUTCFullYear() + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(heartBeatDate.getUTCMonth() + 1, 2) + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(heartBeatDate.getUTCDate(), 2)
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[INFO] runSimulation -> loop -> Simulation ' + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY + ' Loop # ' + learningEngine.current.episode.candle.index.value + ' @ ' + processingDate)
|
||||
|
||||
/* Logging to console and disk */
|
||||
if (TS.projects.superalgos.utilities.dateTimeFunctions.areTheseDatesEqual(currentDate, new Date()) === false) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.newInternalLoop(currentDate, percentage)
|
||||
}
|
||||
|
||||
/* Date only hearbeat */
|
||||
if (sessionParameters.heartbeats.config.date === true && sessionParameters.heartbeats.config.candleIndex === false) {
|
||||
hartbeatText = hartbeatText + currentDateString
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, hartbeatText, percentage)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
When the Candle Index nees to be shown, then we can not send the hearbet
|
||||
only when the dates changes, we have to send it for every candle.
|
||||
It might also contain the date information.
|
||||
*/
|
||||
if (sessionParameters.heartbeats.config.candleIndex === true) {
|
||||
if (sessionParameters.heartbeats.config.date === true) {
|
||||
hartbeatText = hartbeatText + currentDateString
|
||||
}
|
||||
hartbeatText = hartbeatText + ' Candle # ' + learningEngine.current.episode.candle.index.value
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, hartbeatText, percentage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function positionDataStructuresAtCurrentCandle() {
|
||||
/*
|
||||
In conditions and Formulas, we want users to have an easy sintax to refer to indicators. In order to achieve that, we need the user to have
|
||||
easy access to the current candle for instance, or the current bollinger band, meaning the one the Simulation is currently standing at.
|
||||
For that reason we do the following processing, to have at the chart data structure the current objects of each indicator / time frame.
|
||||
*/
|
||||
|
||||
for (const exchangeCodeName in exchange) {
|
||||
let currentExchange = exchange[exchangeCodeName]
|
||||
for (const baseAssetCodeName in currentExchange.market) {
|
||||
let currentBaseAsset = currentExchange.market[baseAssetCodeName]
|
||||
for (const quotedAssetCodeName in currentBaseAsset) {
|
||||
let currentQuotedAsset = currentBaseAsset[quotedAssetCodeName]
|
||||
let currentChart = currentQuotedAsset.chart
|
||||
positionChart(currentChart)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function positionChart(chart) {
|
||||
let dataDependencies = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processDependencies, 'Data Dependency')
|
||||
dataDependencies = TS.projects.superalgos.utilities.nodeFunctions.filterOutNodeWihtoutReferenceParentFromNodeArray(dataDependencies)
|
||||
|
||||
/* Finding the Current Element on Market Files */
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES) {
|
||||
for (let j = 0; j < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length; j++) {
|
||||
let mapKey = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[j][1]
|
||||
let propertyName = 'at' + mapKey.replace('-', '')
|
||||
let thisChart = chart[propertyName]
|
||||
|
||||
if (thisChart === undefined) { continue }
|
||||
|
||||
for (let k = 0; k < dataDependencies.length; k++) {
|
||||
let dataDependencyNode = dataDependencies[k]
|
||||
if (dataDependencyNode.referenceParent.config.codeName !== 'Multi-Period-Daily') { continue }
|
||||
let singularVariableName = dataDependencyNode.referenceParent.parentNode.config.singularVariableName
|
||||
let pluralVariableName = dataDependencyNode.referenceParent.parentNode.config.pluralVariableName
|
||||
if (thisChart[pluralVariableName] !== undefined) {
|
||||
let currentElement = getElement(thisChart[pluralVariableName], 'Daily' + '-' + mapKey + '-' + pluralVariableName)
|
||||
if (currentElement !== undefined) {
|
||||
thisChart[singularVariableName] = currentElement
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Finding the Current Element on Market Files */
|
||||
for (let j = 0; j < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length; j++) {
|
||||
let mapKey = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[j][1]
|
||||
let propertyName = 'at' + mapKey.replace('-', '')
|
||||
let thisChart = chart[propertyName]
|
||||
|
||||
if (thisChart === undefined) { continue }
|
||||
|
||||
for (let k = 0; k < dataDependencies.length; k++) {
|
||||
let dataDependencyNode = dataDependencies[k]
|
||||
if (dataDependencyNode.referenceParent.config.codeName !== 'Multi-Period-Market') { continue }
|
||||
let singularVariableName = dataDependencyNode.referenceParent.parentNode.config.singularVariableName
|
||||
let pluralVariableName = dataDependencyNode.referenceParent.parentNode.config.pluralVariableName
|
||||
if (thisChart[pluralVariableName] !== undefined) {
|
||||
let currentElement = getElement(thisChart[pluralVariableName], 'Market' + '-' + mapKey + '-' + pluralVariableName)
|
||||
if (currentElement !== undefined) {
|
||||
thisChart[singularVariableName] = currentElement
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Finding the Current Element At Single Files*/
|
||||
let propertyName = 'atAnyTimeFrame'
|
||||
let thisChart = chart[propertyName]
|
||||
|
||||
if (thisChart === undefined) { return }
|
||||
|
||||
for (let k = 0; k < dataDependencies.length; k++) {
|
||||
let dataDependencyNode = dataDependencies[k]
|
||||
if (dataDependencyNode.referenceParent.config.codeName !== 'Single-File') { continue }
|
||||
let singularVariableName = dataDependencyNode.referenceParent.parentNode.config.singularVariableName
|
||||
let pluralVariableName = dataDependencyNode.referenceParent.parentNode.config.pluralVariableName
|
||||
let elementArray = thisChart[pluralVariableName]
|
||||
let currentElement
|
||||
if (elementArray !== undefined) {
|
||||
currentElement = elementArray[elementArray.length - 1]
|
||||
}
|
||||
thisChart[singularVariableName] = currentElement
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getElement(pArray, datasetName) {
|
||||
if (pArray === undefined) { return }
|
||||
try {
|
||||
let element
|
||||
for (let i = 0; i < pArray.length; i++) {
|
||||
element = pArray[i]
|
||||
|
||||
if (learningEngine.current.episode.candle.end.value === element.end) { // when there is an exact match at the end we take that element
|
||||
return element
|
||||
} else {
|
||||
if (
|
||||
i > 0 &&
|
||||
element.end > learningEngine.current.episode.candle.end.value
|
||||
) {
|
||||
let previousElement = pArray[i - 1]
|
||||
if (previousElement.end < learningEngine.current.episode.candle.end.value) {
|
||||
return previousElement // If one elements goes into the future of currentCandle, then we stop and take the previous element.
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[ERROR] runSimulation -> getElement -> datasetName = ' + datasetName)
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[ERROR] runSimulation -> getElement -> err = ' + err.stack)
|
||||
throw (TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
|
||||
function checkNextCandle() {
|
||||
/*
|
||||
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.
|
||||
|
||||
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.)
|
||||
*/
|
||||
if (learningEngine.current.episode.candle.index.value + 1 + 1 === candles.length) {
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
let candlesPerDay = TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS / sessionParameters.timeFrame.config.value
|
||||
if (
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES &&
|
||||
learningEngine.current.episode.candle.index.value + 1 + 1 === candlesPerDay
|
||||
) {
|
||||
/*
|
||||
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 dataset we shall receive. The first candle of the next day starts
|
||||
at index 0, so we will position the index now at zero.
|
||||
*/
|
||||
learningEngine.current.episode.candle.index.value = 0
|
||||
learningEngine.current.episode.processDate.value =
|
||||
learningEngine.current.episode.processDate.value + TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS
|
||||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
We reached the head of the market but we are not at the last candle of a day during
|
||||
Daily Files processing. We will advance to the next candle index anyways because in the
|
||||
next execution it will likely have more candles at the dataset. And if it does not,
|
||||
it will just wait there until it does.
|
||||
*/
|
||||
learningEngine.current.episode.headOfTheMarket.value = true
|
||||
learningEngine.current.episode.candle.index.value++
|
||||
return false
|
||||
} else {
|
||||
|
||||
/* Wd did not reach the head of the market */
|
||||
learningEngine.current.episode.headOfTheMarket.value = false
|
||||
learningEngine.current.episode.candle.index.value++
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
function checkInitialDatetime() {
|
||||
/* Here we check that the current candle is not before the initial datetime defined at the session parameters.*/
|
||||
if (learningEngine.current.episode.candle.end.value < sessionParameters.timeRange.config.initialDatetime) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[INFO] runSimulation -> checkInitialAndFinalDatetime -> Skipping Candle before the sessionParameters.timeRange.config.initialDatetime.')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function checkFinalDatetime() {
|
||||
/* Here we check that the next candle is not after of the user-defined final datetime at the session parameters.*/
|
||||
if (learningEngine.current.episode.candle.begin.value + sessionParameters.timeFrame.config.value > sessionParameters.timeRange.config.finalDatetime) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[INFO] runSimulation -> checkInitialAndFinalDatetime -> Skipping Candle after the sessionParameters.timeRange.config.finalDatetime.')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function checkMinimunAndMaximunBalance() {
|
||||
/* Checks for Minimun and Maximun Balance. We do the check while not inside any strategy only. */
|
||||
if (
|
||||
learningEngine.current.strategy.index.value === learningEngine.current.strategy.index.config.initialValue
|
||||
) {
|
||||
/*
|
||||
We will perform this check only when we are not inside a position,
|
||||
because there the balances have shifted from their resting position.
|
||||
*/
|
||||
|
||||
let stopRunningDate = (new Date(learningEngine.current.episode.candle.begin.value)).toUTCString()
|
||||
|
||||
if (sessionParameters.sessionBaseAsset.config.minimumBalance !== undefined) {
|
||||
if (learningEngine.current.episode.episodeBaseAsset.balance.value <= sessionParameters.sessionBaseAsset.config.minimumBalance) {
|
||||
const errorMessage = 'Min Balance reached @ ' + stopRunningDate
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS LF Learning Bot Error - Minimum Balance Reached',
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
let contextInfo = {
|
||||
timestamp: stopRunningDate,
|
||||
episodeBaseAssetBalance: learningEngine.current.episode.episodeBaseAsset.balance.value,
|
||||
sessionBaseAssetMinimumBalance: sessionParameters.sessionBaseAsset.config.minimumBalance
|
||||
}
|
||||
|
||||
TS.projects.superalgos.utilities.docsFunctions.buildPlaceholder(docs, undefined, undefined, undefined, undefined, undefined, contextInfo)
|
||||
|
||||
learningSystem.addError([learningSystem.id, errorMessage, docs])
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[WARN] runSimulation -> checkMinimunAndMaximunBalance -> ' + errorMessage)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if (sessionParameters.sessionBaseAsset.config.maximumBalance !== undefined) {
|
||||
if (learningEngine.current.episode.episodeBaseAsset.balance.value >= sessionParameters.sessionBaseAsset.config.maximumBalance) {
|
||||
const errorMessage = 'Max Balance reached @ ' + stopRunningDate
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS LF Learning Bot Error - Maximum Balance Reached',
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
let contextInfo = {
|
||||
timestamp: stopRunningDate,
|
||||
episodeBaseAssetBalance: learningEngine.current.episode.episodeBaseAsset.balance.value,
|
||||
sessionBaseAssetMaximumBalance: sessionParameters.sessionBaseAsset.config.maximumBalance
|
||||
}
|
||||
|
||||
TS.projects.superalgos.utilities.docsFunctions.buildPlaceholder(docs, undefined, undefined, undefined, undefined, undefined, contextInfo)
|
||||
|
||||
learningSystem.addError([learningSystem.id, errorMessage, docs])
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[WARN] runSimulation -> checkMinimunAndMaximunBalance -> ' + errorMessage)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if (sessionParameters.sessionQuotedAsset.config.minimumBalance !== undefined) {
|
||||
if (learningEngine.current.episode.episodeQuotedAsset.balance.value <= sessionParameters.sessionQuotedAsset.config.minimumBalance) {
|
||||
const errorMessage = 'Min Balance reached @ ' + stopRunningDate
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS LF Learning Bot Error - Minimum Balance Reached',
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
let contextInfo = {
|
||||
timestamp: stopRunningDate,
|
||||
episodeQuotedAssetBalance: learningEngine.current.episode.episodeQuotedAsset.balance.value,
|
||||
sessionQuotedAssetMinimumBalance: sessionParameters.sessionQuotedAsset.config.minimumBalance
|
||||
}
|
||||
|
||||
TS.projects.superalgos.utilities.docsFunctions.buildPlaceholder(docs, undefined, undefined, undefined, undefined, undefined, contextInfo)
|
||||
|
||||
learningSystem.addError([learningSystem.id, errorMessage, docs])
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[WARN] runSimulation -> checkMinimunAndMaximunBalance -> ' + errorMessage)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if (sessionParameters.sessionQuotedAsset.config.maximumBalance !== undefined) {
|
||||
if (learningEngine.current.episode.episodeQuotedAsset.balance.value >= sessionParameters.sessionQuotedAsset.config.maximumBalance) {
|
||||
const errorMessage = 'Max Balance reached @ ' + stopRunningDate
|
||||
|
||||
let docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS LF Learning Bot Error - Maximum Balance Reached',
|
||||
placeholder: {}
|
||||
}
|
||||
|
||||
let contextInfo = {
|
||||
timestamp: stopRunningDate,
|
||||
episodeQuotedAssetBalance: learningEngine.current.episode.episodeQuotedAsset.balance.value,
|
||||
sessionQuotedAssetMaximumBalance: sessionParameters.sessionQuotedAsset.config.maximumBalance
|
||||
}
|
||||
|
||||
TS.projects.superalgos.utilities.docsFunctions.buildPlaceholder(docs, undefined, undefined, undefined, undefined, undefined, contextInfo)
|
||||
|
||||
learningSystem.addError([learningSystem.id, errorMessage, docs])
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[WARN] runSimulation -> checkMinimunAndMaximunBalance -> ' + errorMessage)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return true
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[ERROR] runSimulation -> err = ' + err.stack)
|
||||
throw (TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+393
@@ -0,0 +1,393 @@
|
||||
exports.newSuperalgosBotModulesLearningSystem = function (processIndex) {
|
||||
/*
|
||||
The Learning System is the user defined set of rules compliant with the Learning Protocol that
|
||||
defines the learning logic to be applied during each cycle of the Simulation.
|
||||
*/
|
||||
const MODULE_NAME = 'Learning System'
|
||||
let thisObject = {
|
||||
mantain: mantain,
|
||||
reset: reset,
|
||||
run: run,
|
||||
updateChart: updateChart,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
}
|
||||
|
||||
/*
|
||||
These 3 are the main data structures available to users
|
||||
when writing conditions and formulas.
|
||||
*/
|
||||
let chart
|
||||
let exchange
|
||||
let market
|
||||
|
||||
let learningSystem
|
||||
let learningEngine
|
||||
let sessionParameters
|
||||
let dynamicIndicators
|
||||
|
||||
let learningStagesModuleObject = TS.projects.superalgos.botModules.learningStages.newSuperalgosBotModulesLearningStages(processIndex)
|
||||
|
||||
return thisObject
|
||||
|
||||
function initialize() {
|
||||
learningSystem = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.learningSystem
|
||||
learningEngine = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.learningEngine
|
||||
sessionParameters = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters
|
||||
|
||||
learningSystem.conditions = new Map()
|
||||
learningSystem.formulas = new Map()
|
||||
|
||||
learningStagesModuleObject.initialize()
|
||||
|
||||
/* Adding Functions used elsewhere to Learning System Definition */
|
||||
learningSystem.checkConditions = function (situation, passed) {
|
||||
/* Given a Situation, we check if all children conditions are true or not */
|
||||
for (let m = 0; m < situation.conditions.length; m++) {
|
||||
|
||||
let condition = situation.conditions[m]
|
||||
let value = false
|
||||
if (learningSystem.conditions.get(condition.id) !== undefined) {
|
||||
value = learningSystem.conditions.get(condition.id)
|
||||
}
|
||||
if (value === true) {
|
||||
learningSystem.highlights.push(condition.id)
|
||||
}
|
||||
else {
|
||||
passed = false
|
||||
}
|
||||
learningSystem.values.push([condition.id, value])
|
||||
}
|
||||
return passed
|
||||
}
|
||||
|
||||
learningSystem.evalConditions = function (startingNode, descendentOfNodeType) {
|
||||
evalNode(startingNode, 'Conditions', descendentOfNodeType)
|
||||
}
|
||||
|
||||
learningSystem.evalFormulas = function (startingNode, descendentOfNodeType) {
|
||||
evalNode(startingNode, 'Formulas', descendentOfNodeType)
|
||||
}
|
||||
|
||||
learningSystem.addError = function (errorDataArray) {
|
||||
/*
|
||||
This function adds to the array of error info a rate.
|
||||
This rate will later help plotting the error at the
|
||||
charts.
|
||||
*/
|
||||
let rate = learningEngine.current.episode.candle.close.value
|
||||
errorDataArray.push(rate)
|
||||
learningSystem.errors.push(errorDataArray)
|
||||
}
|
||||
|
||||
learningSystem.addWarning = function (warningDataArray) {
|
||||
/*
|
||||
This function adds to the array of warning info a rate.
|
||||
This rate will later help plotting the warning at the
|
||||
charts.
|
||||
*/
|
||||
let rate = learningEngine.current.episode.candle.close.value
|
||||
warningDataArray.push(rate)
|
||||
learningSystem.warnings.push(warningDataArray)
|
||||
}
|
||||
|
||||
learningSystem.addInfo = function (infoDataArray) {
|
||||
/*
|
||||
This function adds to the array of warning info a rate.
|
||||
This rate will later help plotting the warning at the
|
||||
charts.
|
||||
*/
|
||||
let rate = learningEngine.current.episode.candle.close.value
|
||||
infoDataArray.push(rate)
|
||||
learningSystem.infos.push(infoDataArray)
|
||||
}
|
||||
|
||||
function isItInside(elementWithTimestamp, elementWithBeginEnd) {
|
||||
/*
|
||||
The function is to allow in Conditions and Formulas to easily
|
||||
know when an element with timestamp (like the ones of
|
||||
single files) are inside the time range
|
||||
of an element with a time range, like a candle.
|
||||
*/
|
||||
if (elementWithTimestamp.timestamp >= elementWithBeginEnd.begin && elementWithTimestamp.timestamp <= elementWithBeginEnd.end) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function finalize() {
|
||||
learningStagesModuleObject.finalize()
|
||||
learningStagesModuleObject = undefined
|
||||
|
||||
chart = undefined
|
||||
exchange = undefined
|
||||
market = undefined
|
||||
|
||||
learningSystem.conditions = undefined
|
||||
learningSystem.formulas = undefined
|
||||
|
||||
learningSystem.highlights = undefined
|
||||
learningSystem.errors = undefined
|
||||
learningSystem.warnings = undefined
|
||||
learningSystem.infos = undefined
|
||||
learningSystem.values = undefined
|
||||
learningSystem.status = undefined
|
||||
learningSystem.progress = undefined
|
||||
learningSystem.running = undefined
|
||||
|
||||
learningSystem = undefined
|
||||
learningEngine = undefined
|
||||
sessionParameters = undefined
|
||||
}
|
||||
|
||||
function mantain() {
|
||||
learningStagesModuleObject.mantain()
|
||||
}
|
||||
|
||||
function reset() {
|
||||
learningStagesModuleObject.reset()
|
||||
|
||||
learningSystem.highlights = []
|
||||
learningSystem.errors = []
|
||||
learningSystem.warnings = []
|
||||
learningSystem.infos = []
|
||||
learningSystem.values = []
|
||||
learningSystem.status = []
|
||||
learningSystem.progress = []
|
||||
learningSystem.running = []
|
||||
learningSystem.announcements = []
|
||||
}
|
||||
|
||||
function updateChart(pChart, pExchange, pMarket) {
|
||||
/*
|
||||
We need these 3 data structures to be a local objects
|
||||
accessible while evaluating conditions and formulas.
|
||||
*/
|
||||
chart = pChart
|
||||
exchange = pExchange
|
||||
market = pMarket
|
||||
|
||||
learningStagesModuleObject.updateChart(pChart, pExchange, pMarket)
|
||||
}
|
||||
|
||||
function buildDynamicIndicators() {
|
||||
if (learningSystem.dynamicIndicators !== undefined) {
|
||||
dynamicIndicators = {}
|
||||
/* Eval Dynamic Indicators */
|
||||
learningSystem.evalFormulas(learningSystem.dynamicIndicators, 'Indicator Function')
|
||||
|
||||
for (let i = 0; i < learningSystem.dynamicIndicators.indicatorFunctions.length; i++) {
|
||||
let indicatorFunction = learningSystem.dynamicIndicators.indicatorFunctions[i]
|
||||
if (indicatorFunction.formula === undefined) { return }
|
||||
if (indicatorFunction.config.codeName === undefined) { return }
|
||||
dynamicIndicators[indicatorFunction.config.codeName] = learningSystem.formulas.get(indicatorFunction.formula.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
/* Dynamic Indicators */
|
||||
buildDynamicIndicators()
|
||||
|
||||
/* Run the Trigger Stage */
|
||||
learningStagesModuleObject.runTriggerStage()
|
||||
|
||||
/* Run the Open Stage */
|
||||
await learningStagesModuleObject.runOpenStage()
|
||||
|
||||
/* Run the Manage Stage */
|
||||
learningStagesModuleObject.runManageStage()
|
||||
|
||||
/* Run the Close Stage */
|
||||
await learningStagesModuleObject.runCloseStage()
|
||||
|
||||
/* Validation if we need to exit the position */
|
||||
learningStagesModuleObject.exitPositionValidation()
|
||||
|
||||
learningStagesModuleObject.cycleBasedStatistics()
|
||||
|
||||
} catch (err) {
|
||||
/*
|
||||
If an error ocurred during execution, it was alreeady logged and
|
||||
included at the errors array. That means we need to do nothing here,
|
||||
just prevent the execution to be halted for not handling exceptions.
|
||||
*/
|
||||
if (typeof err === 'string' || err instanceof String) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[ERROR] runExecution -> err = ' + err)
|
||||
}
|
||||
if (err.stack !== undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[ERROR] runExecution -> err = ' + err.stack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function evalNode(node, evaluating, descendentOfNodeType, isDescendent) {
|
||||
if (node === undefined) { return }
|
||||
|
||||
/* Verify if this node is decendent of the specified node type */
|
||||
if (isDescendent !== true) {
|
||||
if (node.type === descendentOfNodeType) {
|
||||
isDescendent = true
|
||||
}
|
||||
}
|
||||
|
||||
/* Here we check if there is a codition to be evaluated */
|
||||
if (node.type === 'Condition' && evaluating === 'Conditions') {
|
||||
/* We will eval this condition */
|
||||
if (isDescendent === true) {
|
||||
evalCondition(node)
|
||||
}
|
||||
}
|
||||
|
||||
/* Here we check if there is a formula to be evaluated */
|
||||
if ((node.type === 'Formula' || node.type === 'Announcement Formula') && evaluating === 'Formulas') {
|
||||
if (node.code !== undefined) {
|
||||
/* We will eval this formula */
|
||||
if (isDescendent === true) {
|
||||
evalFormula(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we go down through all this node children */
|
||||
let schemaDocument = TS.projects.superalgos.globals.taskConstants.APP_SCHEMA_MAP.get(node.project + '-' + node.type)
|
||||
if (schemaDocument === undefined) { return }
|
||||
|
||||
if (schemaDocument.childrenNodesProperties !== undefined) {
|
||||
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
|
||||
for (let i = 0; i < schemaDocument.childrenNodesProperties.length; i++) {
|
||||
let property = schemaDocument.childrenNodesProperties[i]
|
||||
|
||||
switch (property.type) {
|
||||
case 'node': {
|
||||
if (property.name !== previousPropertyName) {
|
||||
if (node[property.name] !== undefined) {
|
||||
evalNode(node[property.name], evaluating, descendentOfNodeType, isDescendent)
|
||||
}
|
||||
previousPropertyName = property.name
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'array': {
|
||||
if (node[property.name] !== undefined) {
|
||||
let nodePropertyArray = node[property.name]
|
||||
for (let m = 0; m < nodePropertyArray.length; m++) {
|
||||
evalNode(nodePropertyArray[m], evaluating, descendentOfNodeType, isDescendent)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function evalCondition(node) {
|
||||
let value
|
||||
let errorMessage
|
||||
let docs
|
||||
/*
|
||||
The code can be at the condition node if it was done with the Conditions Editor, or it can also be
|
||||
at a Javascript Code node. If there is a Javascript object we will give it preference and take the code
|
||||
from there. Otherwise we will take the code from the Condition node.
|
||||
*/
|
||||
let code = node.code
|
||||
let nodeName = node.name
|
||||
if (node.javascriptCode !== undefined) {
|
||||
if (node.javascriptCode.code !== undefined) {
|
||||
code = node.javascriptCode.code
|
||||
nodeName = node.javascriptCode.name
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[INFO] evalCondition -> ' + node.name + ' -> code = ' + code)
|
||||
value = eval(code)
|
||||
} catch (err) {
|
||||
/*
|
||||
One possible error is that the conditions references a .previous that is undefined. This
|
||||
will not be considered an error.
|
||||
*/
|
||||
value = false
|
||||
errorMessage = err.message
|
||||
docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS LF Learning Bot Error - Evaluating Condition Error',
|
||||
placeholder: {}
|
||||
}
|
||||
TS.projects.superalgos.utilities.docsFunctions.buildPlaceholder(docs, err, nodeName, code, undefined)
|
||||
}
|
||||
|
||||
learningSystem.conditions.set(node.id, value)
|
||||
|
||||
if (value === true) {
|
||||
learningSystem.highlights.push(node.id)
|
||||
}
|
||||
if (errorMessage !== undefined) {
|
||||
learningSystem.addError([node.id, errorMessage, docs])
|
||||
}
|
||||
if (value !== undefined) {
|
||||
learningSystem.values.push([node.id, value])
|
||||
}
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[INFO] evalCondition -> value = ' + value)
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[INFO] evalCondition -> errorMessage = ' + errorMessage)
|
||||
}
|
||||
|
||||
function evalFormula(node) {
|
||||
let value
|
||||
let errorMessage
|
||||
let docs
|
||||
|
||||
try {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[INFO] evalFormula -> ' + node.name + ' -> code = ' + node.code)
|
||||
value = eval(node.code)
|
||||
} catch (err) {
|
||||
/*
|
||||
One possible error is that the formula references a .previous that is undefined. This
|
||||
will not be considered an error.
|
||||
*/
|
||||
value = 0
|
||||
errorMessage = err.message
|
||||
docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS LF Learning Bot Error - Evaluating Formula Error',
|
||||
placeholder: {}
|
||||
}
|
||||
TS.projects.superalgos.utilities.docsFunctions.buildPlaceholder(docs, err, node.name, node.code, undefined)
|
||||
}
|
||||
|
||||
if (errorMessage !== undefined) {
|
||||
learningSystem.addError([node.id, errorMessage, docs])
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[INFO] evalFormula -> errorMessage = ' + errorMessage)
|
||||
return
|
||||
} else {
|
||||
if (value !== undefined) {
|
||||
if (node.type === 'Formula' && isNaN(value)) {
|
||||
|
||||
docs = {
|
||||
project: 'Superalgos',
|
||||
category: 'Topic',
|
||||
type: 'TS LF Learning Bot Error - Formula Value Not A Number',
|
||||
placeholder: {}
|
||||
}
|
||||
TS.projects.superalgos.utilities.docsFunctions.buildPlaceholder(docs, undefined, node.name, node.code, undefined, value)
|
||||
|
||||
learningSystem.addError([node.id, 'Formula needs to return a numeric value.', docs])
|
||||
return
|
||||
}
|
||||
|
||||
learningSystem.values.push([node.id, value])
|
||||
learningSystem.formulas.set(node.id, value)
|
||||
}
|
||||
}
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[INFO] evalFormula -> value = ' + value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,607 @@
|
||||
exports.newSuperalgosBotModulesSingleMarketLearningBot = function (processIndex) {
|
||||
|
||||
const MODULE_NAME = "Single Market Learning Bot";
|
||||
|
||||
let session = TS.projects.superalgos.botModules.learningSession.newSuperalgosBotModulesLearningSession(processIndex)
|
||||
let nextLoopTimeoutHandle;
|
||||
|
||||
let thisObject = {
|
||||
initialize: initialize,
|
||||
run: run
|
||||
};
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(callBackFunction) {
|
||||
try {
|
||||
/* We will check that we have received all the nodes needed to run this bot. */
|
||||
if (TS.projects.superalgos.functionLibraries.singleMarketFunctions.checkUpstreamOfTaskNode(processIndex) === false) {
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
/* Here we setup the path prefix that will be used when writting data or logs to disk. */
|
||||
TS.projects.superalgos.functionLibraries.singleMarketFunctions.initializeFilePathRoot(processIndex)
|
||||
|
||||
session.initialize(callBackFunction)
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function run(callBackFunction) {
|
||||
try {
|
||||
/* Some initial values*/
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_STOPPING = true;
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
'[IMPORTANT] run -> Stopping the Session now. ')
|
||||
|
||||
loop();
|
||||
|
||||
function loop() {
|
||||
try {
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, undefined, undefined, "Running...")
|
||||
function pad(str, max) {
|
||||
str = str.toString();
|
||||
return str.length < max ? pad(" " + str, max) : str;
|
||||
}
|
||||
|
||||
/* For each loop we want to create a new log file. */
|
||||
if (TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT !== undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.finalize()
|
||||
}
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT = TS.projects.superalgos.taskModules.debugLog.newSuperalgosTaskModulesDebugLog(processIndex)
|
||||
TS.projects.superalgos.globals.taskVariables.LOGGER_MAP.set(MODULE_NAME + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].id, TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT)
|
||||
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).MAIN_LOOP_COUNTER++;
|
||||
|
||||
let nextWaitTime;
|
||||
|
||||
/* We tell the UI that we are running. */
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, undefined, undefined, "Running...")
|
||||
|
||||
/* 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. */
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME = new Date(); // This will be considered the process date and time, so as to have it consistenly all over the execution.
|
||||
|
||||
/* Main Loop Console Logging */
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.newMainLoop()
|
||||
|
||||
/* Checking if we need to need to emit any event */
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_STATUS === 'Idle' && TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_STOPPING === false) {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_STATUS = 'Running'
|
||||
}
|
||||
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_STATUS === 'Running' && TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_STOPPING === true) {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_STATUS = 'Stopped'
|
||||
}
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.emitSessionStatus(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_STATUS, TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY)
|
||||
|
||||
/* Checking if we should process this loop or not.*/
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_STOPPING === true) {
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> Waiting for " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.type + " " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.name + " to be run.")
|
||||
|
||||
console.log(new Date().toISOString() + " " + pad(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName, 20) + " " + pad(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName, 30)
|
||||
+ " Waiting for " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.type + " " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.name + " to be run. ");
|
||||
|
||||
nextWaitTime = 'Waiting for Session';
|
||||
loopControl(nextWaitTime);
|
||||
return
|
||||
}
|
||||
|
||||
/* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */
|
||||
|
||||
let processExecutionEvents
|
||||
let userBot;
|
||||
let processFramework;
|
||||
let statusDependencies;
|
||||
let dataDependencies;
|
||||
|
||||
initializeProcessExecutionEvents();
|
||||
|
||||
function initializeProcessExecutionEvents() {
|
||||
try {
|
||||
processExecutionEvents = TS.projects.superalgos.processModules.processExecutionEvents.newSuperalgosProcessModulesProcessExecutionEvents(processIndex)
|
||||
processExecutionEvents.initialize(onInizialized);
|
||||
|
||||
function onInizialized(err) {
|
||||
try {
|
||||
switch (err.result) {
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Execution finished well.");
|
||||
startProcessExecutionEvents()
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Retry Later. Requesting Execution Retry.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Operation Failed. Aborting the process.");
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Unhandled err.result received. -> err = " + err.message);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeProcessExecutionEvents -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function startProcessExecutionEvents() {
|
||||
try {
|
||||
processExecutionEvents.start(onStarted);
|
||||
|
||||
function onStarted(err) {
|
||||
try {
|
||||
switch (err.result) {
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> startProcessExecutionEvents -> onStarted -> Execution finished well.");
|
||||
|
||||
if (TS.projects.superalgos.globals.taskVariables.IS_TASK_STOPPING === true) {
|
||||
loopControl()
|
||||
return
|
||||
}
|
||||
|
||||
initializeStatusDependencies();
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> startProcessExecutionEvents -> onStarted -> Retry Later. Requesting Execution Retry.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessExecutionEvents -> onStarted -> Operation Failed. Aborting the process.");
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessExecutionEvents -> onStarted -> Unhandled err.result received. -> err.result = " + err.result);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessExecutionEvents -> onStarted -> Unhandled err.result received. -> err = " + err.message);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessExecutionEvents -> onStarted -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessExecutionEvents -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function initializeStatusDependencies() {
|
||||
try {
|
||||
statusDependencies = TS.projects.superalgos.processModules.statusDependencies.newSuperalgosProcessModulesStatusDependencies(processIndex);
|
||||
statusDependencies.initialize(onInizialized);
|
||||
|
||||
function onInizialized(err) {
|
||||
try {
|
||||
switch (err.result) {
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> initializeStatusDependencies -> onInizialized -> Execution finished well.");
|
||||
initializeDataDependencies();
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> initializeStatusDependencies -> onInizialized -> Retry Later. Requesting Execution Retry.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeStatusDependencies -> onInizialized -> Operation Failed. Aborting the process.");
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeStatusDependencies -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeStatusDependencies -> onInizialized -> Unhandled err.result received. -> err = " + err.message);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeStatusDependencies -> onInizialized -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeStatusDependencies -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function initializeDataDependencies() {
|
||||
try {
|
||||
dataDependencies = TS.projects.superalgos.processModules.dataDependencies.newSuperalgosProcessModulesDataDependencies(processIndex);
|
||||
dataDependencies.initialize(onInizialized);
|
||||
|
||||
function onInizialized(err) {
|
||||
try {
|
||||
switch (err.result) {
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> initializeDataDependencies -> onInizialized -> Execution finished well.")
|
||||
switch (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.name) {
|
||||
case 'Low-Frequency-Learning-Process': {
|
||||
processFramework = TS.projects.superalgos.botModules.learningProcess.newSuperalgosBotModulesLearningProcess(processIndex);
|
||||
startProcessFramework();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Process Framework not Supported.");
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Process Framework Name = " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.name);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> initializeDataDependencies -> onInizialized -> Retry Later. Requesting Execution Retry.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Operation Failed. Aborting the process.");
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Unhandled err.result received. -> err = " + err.message);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeDataDependencies -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function startProcessFramework() {
|
||||
try {
|
||||
processFramework.start(statusDependencies, dataDependencies, onFinished);
|
||||
|
||||
function onFinished(err) {
|
||||
try {
|
||||
processFramework = undefined
|
||||
dataDependencies.finalize()
|
||||
dataDependencies = undefined
|
||||
statusDependencies.finalize()
|
||||
statusDependencies = undefined
|
||||
|
||||
switch (err.result) {
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> startProcessFramework -> onFinished -> Execution finished well.");
|
||||
nextWaitTime = 'Normal';
|
||||
finishProcessExecutionEvents()
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> startProcessFramework -> onFinished -> Retry Later. Requesting Execution Retry.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessFramework -> onFinished -> Operation Failed. Aborting the process.");
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result: {
|
||||
|
||||
switch (err.message) {
|
||||
case "Dependency does not exist.": {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> startProcessFramework -> onFinished -> Dependency does not exist. This Loop will go to sleep.");
|
||||
nextWaitTime = 'Sleep';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case "Dependency not ready.": {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> startProcessFramework -> onFinished -> Dependency not ready. This Loop will go to sleep.");
|
||||
nextWaitTime = 'Sleep';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled custom response received. -> err = " + err.message);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled err.result received. -> err.result = " + err.result);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled err.result received. -> err = " + err.message);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessFramework -> onFinished -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessFramework -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function finishProcessExecutionEvents() {
|
||||
try {
|
||||
processExecutionEvents.finish(onFinished);
|
||||
|
||||
function onFinished(err) {
|
||||
try {
|
||||
processExecutionEvents.finalize()
|
||||
processExecutionEvents = undefined
|
||||
|
||||
switch (err.result) {
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> finishProcessExecutionEvents -> onFinished -> Execution finished well.");
|
||||
nextWaitTime = 'Normal';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> finishProcessExecutionEvents -> onFinished -> Retry Later. Requesting Execution Retry.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> finishProcessExecutionEvents -> onFinished -> Operation Failed. Aborting the process.");
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> finishProcessExecutionEvents -> onFinished -> Unhandled err.result received. -> err.result = " + err.result);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> finishProcessExecutionEvents -> onFinished -> Unhandled err.result received. -> err = " + err.message);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> finishProcessExecutionEvents -> onFinished -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> finishProcessExecutionEvents -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function loopControl(nextWaitTime) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> loopControl -> nextWaitTime = " + nextWaitTime)
|
||||
|
||||
/* We show we reached the end of the loop. */
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, undefined, undefined, "Running...")
|
||||
|
||||
/* Here we check if we must stop the loop gracefully. */
|
||||
shallWeStop(onStop, onContinue);
|
||||
|
||||
function onStop() {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> loopControl -> onStop -> Stopping the Loop Gracefully. See you next time!")
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.persist();
|
||||
|
||||
TS.projects.superalgos.globals.taskConstants.EVENT_SERVER_CLIENT_MODULE_OBJECT.raiseEvent(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY, 'Stopped')
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return;
|
||||
}
|
||||
|
||||
function onContinue() {
|
||||
/* Indicator bots are going to be executed after a configured period of time after the last execution ended. This is to avoid overlapping executions. */
|
||||
switch (nextWaitTime) {
|
||||
case 'Waiting for Session': {
|
||||
let waitTime = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.sessionRunWaitTime
|
||||
nextLoopTimeoutHandle = setTimeout(loop, waitTime);
|
||||
let waitingTime = waitTime / 1000 / 60
|
||||
let label = 'minute/s'
|
||||
if (waitingTime < 1) {
|
||||
waitingTime = waitTime / 1000
|
||||
label = 'seconds'
|
||||
}
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, undefined, undefined, "Waiting " + waitingTime + " " + label + " for " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.type + " " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.name + " to be run. ")
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.persist();
|
||||
}
|
||||
break
|
||||
case 'Normal': {
|
||||
let waitTime
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).WAIT_FOR_EXECUTION_FINISHED_EVENT === true) {
|
||||
waitTime = 0
|
||||
} else {
|
||||
switch (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.type) {
|
||||
case 'Live Learning Session': {
|
||||
waitTime = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.learningParameters.timeFrame.config.value
|
||||
break
|
||||
}
|
||||
case 'Back Learning Session': {
|
||||
waitTime = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> loopControl -> Restarting Loop in " + (waitTime / 1000 / 60) + " minute/s.")
|
||||
nextLoopTimeoutHandle = setTimeout(loop, waitTime);
|
||||
let waitingTime = waitTime / 1000 / 60
|
||||
let label = 'minute/s'
|
||||
if (waitingTime < 1) {
|
||||
waitingTime = waitTime / 1000
|
||||
label = 'seconds'
|
||||
}
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, undefined, undefined, "Waiting " + waitingTime + " " + label + " for next execution.")
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.persist();
|
||||
}
|
||||
break;
|
||||
case 'Retry': {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> loopControl -> Restarting Loop in " + (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.retryWaitTime / 1000) + " seconds.")
|
||||
nextLoopTimeoutHandle = setTimeout(loop, TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.retryWaitTime);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, undefined, undefined, "Trying to recover from some problem. Waiting " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.retryWaitTime / 1000 + " seconds for next execution.")
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.persist();
|
||||
}
|
||||
break;
|
||||
case 'Sleep': {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> loopControl -> Restarting Loop in " + (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.sleepWaitTime / 60000) + " minutes.")
|
||||
nextLoopTimeoutHandle = setTimeout(loop, TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.sleepWaitTime);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, undefined, undefined, "Waiting " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.sleepWaitTime / 60000 + " minutes for next execution.")
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.persist();
|
||||
}
|
||||
break;
|
||||
case 'Coma': {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> loopControl -> Restarting Loop in " + (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.comaWaitTime / 3600000) + " hours.")
|
||||
nextLoopTimeoutHandle = setTimeout(loop, TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.comaWaitTime);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, undefined, undefined, "Waiting " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.comaWaitTime / 3600000 + " hours for next execution.")
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.persist();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function shallWeStop(stopCallBack, continueCallBack) {
|
||||
try {
|
||||
/* IMPORTANT: This function is exactly the same on the 3 modules. */
|
||||
if (!TS.projects.superalgos.globals.taskVariables.IS_TASK_STOPPING) {
|
||||
continueCallBack();
|
||||
} else {
|
||||
stopCallBack();
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> shallWeStop -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.taskVariables.UNEXPECTED_ERROR = err
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> err = " + err.stack);
|
||||
clearTimeout(nextLoopTimeoutHandle);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
};
|
||||
+19
-185
@@ -6,26 +6,11 @@ exports.newSuperalgosBotModulesTradingOutput = function (processIndex) {
|
||||
const MODULE_NAME = 'Trading Output'
|
||||
|
||||
let thisObject = {
|
||||
initialize: initialize,
|
||||
finalize: finalize,
|
||||
start: start
|
||||
}
|
||||
|
||||
let fileStorage = TS.projects.superalgos.taskModules.fileStorage.newFileStorage(processIndex)
|
||||
|
||||
return thisObject
|
||||
|
||||
function finalize() {
|
||||
thisObject = undefined
|
||||
utilities = undefined
|
||||
fileStorage = undefined
|
||||
commons = undefined
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
}
|
||||
|
||||
async function start(
|
||||
chart,
|
||||
market,
|
||||
@@ -35,6 +20,7 @@ exports.newSuperalgosBotModulesTradingOutput = function (processIndex) {
|
||||
tradingProcessDate
|
||||
) {
|
||||
try {
|
||||
let fileStorage = TS.projects.superalgos.taskModules.fileStorage.newFileStorage(processIndex)
|
||||
|
||||
if (timeFrame > TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[0][0]) {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES = false
|
||||
@@ -48,187 +34,35 @@ exports.newSuperalgosBotModulesTradingOutput = function (processIndex) {
|
||||
let outputDatasets = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset')
|
||||
let outputDatasetsMap = new Map()
|
||||
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES === true) {
|
||||
/*
|
||||
For Daily Files, we are going to initialize the outputs at the first execution
|
||||
if we are not resuming, but also at every following execution except when
|
||||
we are at the head of the market, because at the head of the market we need to
|
||||
append more data to the same output files that already exists.
|
||||
*/
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_FIRST_LOOP === true && TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_RESUMING === false) {
|
||||
await initializeOutputs()
|
||||
} else {
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.tradingEngine.current.episode.headOfTheMarket.value === true) {
|
||||
await readFiles()
|
||||
} else {
|
||||
await initializeOutputs()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
Form Market Files, we are only going to initialize the outputs at the first run
|
||||
and if we are not resuming execution. Subsequent runs means that we are at the
|
||||
head of the market. Remember that backtests finishes the session once the reach
|
||||
the final datetime.
|
||||
*/
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_FIRST_LOOP === true && TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_RESUMING === false) {
|
||||
await initializeOutputs()
|
||||
} else {
|
||||
await readFiles()
|
||||
}
|
||||
}
|
||||
await TS.projects.superalgos.functionLibraries.outputManagementFunctions.readFiles(
|
||||
processIndex,
|
||||
outputDatasets,
|
||||
outputDatasetsMap,
|
||||
timeFrameLabel,
|
||||
tradingProcessDate,
|
||||
fileStorage
|
||||
)
|
||||
|
||||
await tradingSimulationModuleObject.runSimulation(
|
||||
chart,
|
||||
market,
|
||||
exchange,
|
||||
outputDatasetsMap,
|
||||
writeFiles
|
||||
writeOutputFiles
|
||||
)
|
||||
|
||||
tradingSimulationModuleObject.finalize()
|
||||
return
|
||||
|
||||
async function initializeOutputs() {
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES) {
|
||||
await initializeDailyFiles()
|
||||
} else {
|
||||
await initializeMarketFiles()
|
||||
}
|
||||
}
|
||||
|
||||
async function initializeDailyFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
|
||||
if (dataset.config.type === 'Daily Files') {
|
||||
outputDatasetsMap.set(dataset.parentNode.config.codeName, [])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function initializeMarketFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
|
||||
if (dataset.config.type === 'Market Files') {
|
||||
outputDatasetsMap.set(dataset.parentNode.config.codeName, [])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function readFiles() {
|
||||
/*
|
||||
This bot have an output of files that it generates. At every call to the bot, it needs to read the previously generated
|
||||
files in order to later append more information after the execution is over. Here in this function we are going to
|
||||
read those output files and get them ready for appending content during the simulation.
|
||||
*/
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES) {
|
||||
await readDailyFiles()
|
||||
} else {
|
||||
await readMarketFiles()
|
||||
}
|
||||
}
|
||||
|
||||
async function readMarketFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
|
||||
if (dataset.config.type === 'Market Files') {
|
||||
|
||||
let fileName = 'Data.json'
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + '/Output/' + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel
|
||||
|
||||
await readOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function readDailyFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
|
||||
if (dataset.config.type === 'Daily Files') {
|
||||
|
||||
let dateForPath = tradingProcessDate.getUTCFullYear() + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(tradingProcessDate.getUTCDate(), 2);
|
||||
let fileName = 'Data.json'
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + '/Output/' + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel + "/" + dateForPath
|
||||
|
||||
await readOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function readOutputFile(fileName, filePath, productName) {
|
||||
filePath += '/' + fileName
|
||||
|
||||
let response = await fileStorage.asyncGetTextFile(filePath, true)
|
||||
|
||||
if (response.err.message === 'File does not exist.') {
|
||||
outputDatasetsMap.set(productName, [])
|
||||
return
|
||||
}
|
||||
if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
throw (response.err)
|
||||
}
|
||||
outputDatasetsMap.set(productName, JSON.parse(response.text))
|
||||
}
|
||||
|
||||
async function writeFiles() {
|
||||
/*
|
||||
The output of files which were appended with information during the simulation execution, now needs to be saved.
|
||||
*/
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES) {
|
||||
await writeDailyFiles()
|
||||
} else {
|
||||
await writeMarketFiles()
|
||||
}
|
||||
}
|
||||
|
||||
async function writeMarketFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
|
||||
if (dataset.config.type === 'Market Files') {
|
||||
|
||||
let fileName = 'Data.json'
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + '/Output/' + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel
|
||||
|
||||
await writeOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function writeDailyFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
|
||||
if (dataset.config.type === 'Daily Files') {
|
||||
|
||||
let dateForPath = tradingProcessDate.getUTCFullYear() + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(tradingProcessDate.getUTCDate(), 2);
|
||||
let fileName = 'Data.json'
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + '/Output/' + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel + "/" + dateForPath
|
||||
|
||||
await writeOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function writeOutputFile(fileName, filePath, productName) {
|
||||
filePath += '/' + fileName
|
||||
let fileContent = JSON.stringify(outputDatasetsMap.get(productName))
|
||||
|
||||
let response = await fileStorage.asyncCreateTextFile(filePath, fileContent)
|
||||
|
||||
if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
throw (response.err)
|
||||
}
|
||||
function writeOutputFiles() {
|
||||
TS.projects.superalgos.functionLibraries.outputManagementFunctions.writeFiles(
|
||||
processIndex,
|
||||
outputDatasets,
|
||||
outputDatasetsMap,
|
||||
timeFrameLabel,
|
||||
tradingProcessDate,
|
||||
fileStorage
|
||||
)
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
|
||||
+70
-740
@@ -6,58 +6,20 @@
|
||||
const MODULE_NAME = "Trading Process"
|
||||
|
||||
thisObject = {
|
||||
initialize: initialize,
|
||||
finalize: finalize,
|
||||
start: start
|
||||
}
|
||||
|
||||
let statusDependencies
|
||||
let dataDependenciesModule
|
||||
let dataFiles = new Map()
|
||||
let multiTimeFrameDataFiles = new Map()
|
||||
let fileStorage = TS.projects.superalgos.taskModules.fileStorage.newFileStorage(processIndex)
|
||||
TS.projects.superalgos.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT = TS.projects.superalgos.botModules.tradingEngine.newSuperalgosBotModulesTradingEngine(processIndex)
|
||||
let tradingOutputModuleObject = TS.projects.superalgos.botModules.tradingOutput.newSuperalgosBotModulesTradingOutput(processIndex)
|
||||
|
||||
return thisObject
|
||||
|
||||
function initialize(pStatusDependencies, pDataDependencies, callBackFunction) {
|
||||
async function start(statusDependencies, dataDependenciesModule, callBackFunction) {
|
||||
try {
|
||||
statusDependencies = pStatusDependencies
|
||||
dataDependenciesModule = pDataDependencies
|
||||
|
||||
tradingOutputModuleObject.initialize()
|
||||
let dataFiles = new Map()
|
||||
let multiTimeFrameDataFiles = new Map()
|
||||
TS.projects.superalgos.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT = TS.projects.superalgos.botModules.tradingEngine.newSuperalgosBotModulesTradingEngine(processIndex)
|
||||
let tradingOutputModuleObject = TS.projects.superalgos.botModules.tradingOutput.newSuperalgosBotModulesTradingOutput(processIndex)
|
||||
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE)
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> err = " + err.stack)
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
|
||||
function finalize() {
|
||||
|
||||
TS.projects.superalgos.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT.finalize()
|
||||
TS.projects.superalgos.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT = undefined
|
||||
|
||||
tradingOutputModuleObject.finalize()
|
||||
tradingOutputModuleObject = undefined
|
||||
|
||||
dataFiles = undefined
|
||||
multiTimeFrameDataFiles = undefined
|
||||
statusDependencies = undefined
|
||||
dataDependenciesModule = undefined
|
||||
fileStorage = undefined
|
||||
thisObject = undefined
|
||||
}
|
||||
|
||||
async function start(callBackFunction) {
|
||||
try {
|
||||
let currentTimeFrame
|
||||
let currentTimeFrameLabel
|
||||
let currentTimeFrame = {}
|
||||
|
||||
/* Context Variables */
|
||||
let contextVariables = {
|
||||
@@ -66,7 +28,14 @@
|
||||
dateEndOfMarket: undefined // Datetime of the last file available to be used as an input of this process.
|
||||
}
|
||||
|
||||
if (getContextVariables() !== true) { return }
|
||||
if (
|
||||
TS.projects.superalgos.functionLibraries.processFilesFunctions.getContextVariables(
|
||||
processIndex,
|
||||
contextVariables,
|
||||
statusDependencies,
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeRange.config.initialDatetime,
|
||||
callBackFunction
|
||||
) !== true) { return }
|
||||
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_FIRST_LOOP === true && TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_RESUMING === false) {
|
||||
/*
|
||||
@@ -103,13 +72,28 @@
|
||||
*/
|
||||
let tradingProcessDate = TS.projects.superalgos.utilities.dateTimeFunctions.removeTime(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.tradingEngine.current.episode.processDate.value)
|
||||
|
||||
if (await processSingleFiles() === false) {
|
||||
if (
|
||||
await TS.projects.superalgos.functionLibraries.dataDependenciesFunctions.processSingleFiles(
|
||||
processIndex,
|
||||
dataFiles,
|
||||
multiTimeFrameDataFiles,
|
||||
dataDependenciesModule
|
||||
) === false) {
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Waiting for Data Mining to be run')
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
if (await processMarketFiles() === false) {
|
||||
if (await TS.projects.superalgos.functionLibraries.dataDependenciesFunctions.processMarketFiles(
|
||||
processIndex,
|
||||
dataFiles,
|
||||
multiTimeFrameDataFiles,
|
||||
dataDependenciesModule,
|
||||
currentTimeFrame,
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeFrame.config.label,
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeRange.config.initialDatetime,
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeRange.config.finalDatetime
|
||||
) === false) {
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Waiting for Data Mining to be run')
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
@@ -124,23 +108,32 @@
|
||||
Here we check if we need to get Daily Files or not. As an optimization, when
|
||||
we are running on a Time Frame of 1hs or above, we are not going to load
|
||||
dependencies on Daily Files. The way we recognize that is by checking if
|
||||
we alreaady set a value to currentTimeFrame. We are also not going to loop
|
||||
we alreaady set a value to currentTimeFrame.value. We are also not going to loop
|
||||
through days if we are processing market files.
|
||||
*/
|
||||
if (currentTimeFrame) {
|
||||
if (currentTimeFrame.value) {
|
||||
/* We are processing Market Files */
|
||||
/*
|
||||
With all the indicators data files loaded, we will build the chart object
|
||||
data structure that will be used in user-defied conditions and formulas.
|
||||
*/
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Waking up')
|
||||
buildDataStructures()
|
||||
TS.projects.superalgos.functionLibraries.dataDependenciesFunctions.buildDataStructures(
|
||||
processIndex,
|
||||
dataDependenciesModule,
|
||||
multiTimeFrameDataFiles,
|
||||
currentTimeFrame,
|
||||
chart,
|
||||
market,
|
||||
exchange,
|
||||
callBackFunction
|
||||
)
|
||||
|
||||
if (checkThereAreCandles() === true) {
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Running')
|
||||
await generateOutput()
|
||||
await outputManagement()
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Saving')
|
||||
await writeProcessFiles()
|
||||
await TS.projects.superalgos.functionLibraries.processFilesFunctions.writeProcessFiles(processIndex, contextVariables, currentTimeFrame, tradingProcessDate, statusDependencies)
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Sleeping')
|
||||
} else {
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Waiting for Data Mining to be up to date. No candles found at.')
|
||||
@@ -164,7 +157,16 @@
|
||||
if (checkStopProcessing() === false) { break }
|
||||
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Waking up')
|
||||
if (await processDailyFiles() === false) {
|
||||
if (
|
||||
await TS.projects.superalgos.functionLibraries.dataDependenciesFunctions.processDailyFiles(
|
||||
processIndex,
|
||||
dataFiles,
|
||||
multiTimeFrameDataFiles,
|
||||
dataDependenciesModule,
|
||||
currentTimeFrame,
|
||||
TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeFrame.config.label,
|
||||
tradingProcessDate
|
||||
) === false) {
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Waiting for Data Mining to be run')
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
@@ -173,15 +175,24 @@
|
||||
With all the indicators data files loaded, we will build the chart object
|
||||
data structure that will be used in user-defied conditions and formulas.
|
||||
*/
|
||||
buildDataStructures()
|
||||
TS.projects.superalgos.functionLibraries.dataDependenciesFunctions.buildDataStructures(
|
||||
processIndex,
|
||||
dataDependenciesModule,
|
||||
multiTimeFrameDataFiles,
|
||||
currentTimeFrame,
|
||||
chart,
|
||||
market,
|
||||
exchange,
|
||||
callBackFunction
|
||||
)
|
||||
/*
|
||||
The process of generating the output includes the trading simulation.
|
||||
*/
|
||||
if (checkThereAreCandles() === true) {
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Running')
|
||||
await generateOutput()
|
||||
await outputManagement()
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Saving')
|
||||
await writeProcessFiles()
|
||||
await TS.projects.superalgos.functionLibraries.processFilesFunctions.writeProcessFiles(processIndex, contextVariables, currentTimeFrame, tradingProcessDate, statusDependencies)
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Sleeping')
|
||||
} else {
|
||||
TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Waiting for Data Mining to be up to date')
|
||||
@@ -222,429 +233,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function getContextVariables() {
|
||||
try {
|
||||
let thisReport
|
||||
let statusReport
|
||||
|
||||
/* We are going to use the start date as beging of market date. */
|
||||
contextVariables.dateBeginOfMarket = TS.projects.superalgos.utilities.dateTimeFunctions.removeTime(TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeRange.config.initialDatetime)
|
||||
/*
|
||||
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")
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return false
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return false
|
||||
}
|
||||
|
||||
thisReport = statusReport.file
|
||||
|
||||
if (thisReport.lastFile === undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Undefined Last File. -> thisReport = " + JSON.stringify(thisReport))
|
||||
|
||||
let customOK = {
|
||||
result: TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result,
|
||||
message: "Dependency not ready."
|
||||
}
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> customOK = " + customOK.message)
|
||||
callBackFunction(customOK)
|
||||
return false
|
||||
}
|
||||
|
||||
contextVariables.dateEndOfMarket = new Date(thisReport.lastFile.valueOf())
|
||||
|
||||
/* Finally we get our own Status Report. */
|
||||
statusReport = statusDependencies.reportsByMainUtility.get("Self Reference")
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return false
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process.")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
return false
|
||||
}
|
||||
|
||||
thisReport = statusReport.file
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE = thisReport.simulationState
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE === undefined) { TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE = {} } // This should happen only when there is no status report
|
||||
|
||||
if (thisReport.lastFile !== undefined) {
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_RESUMING !== true) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> Starting from the begining because bot has just started and resume execution was true.")
|
||||
startFromBegining()
|
||||
return true
|
||||
}
|
||||
contextVariables.lastFile = new Date(thisReport.lastFile)
|
||||
return true
|
||||
|
||||
} else {
|
||||
/*
|
||||
We are here becuse either:
|
||||
1. There is no status report
|
||||
2. There is no Last File (this happens on Market Files)
|
||||
*/
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> Starting from the begining of the market because own status report not found or lastFile was undefined.")
|
||||
startFromBegining()
|
||||
return true
|
||||
}
|
||||
|
||||
function startFromBegining() {
|
||||
contextVariables.lastFile = new Date(contextVariables.dateBeginOfMarket.getUTCFullYear() + "-" + (contextVariables.dateBeginOfMarket.getUTCMonth() + 1) + "-" + contextVariables.dateBeginOfMarket.getUTCDate() + " " + "00:00" + TS.projects.superalgos.globals.timeConstants.GMT_SECONDS)
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> startFromBegining -> contextVariables.lastFile = " + contextVariables.lastFile)
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> err = " + err.stack)
|
||||
if (err.message === "Cannot read property 'file' of undefined") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. ")
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys))
|
||||
}
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
|
||||
async function processSingleFiles() {
|
||||
|
||||
/*
|
||||
We will iterate through all the exchanges and markets involved.
|
||||
*/
|
||||
let exchangeList = Array.from(dataDependenciesModule.filters.exchange.list.keys())
|
||||
let marketList = Array.from(dataDependenciesModule.filters.market.list.keys())
|
||||
|
||||
for (let e = 0; e < exchangeList.length; e++) {
|
||||
let currentExchange = exchangeList[e]
|
||||
for (let m = 0; m < marketList.length; m++) {
|
||||
let currentMarket = marketList[m]
|
||||
|
||||
dataFiles = new Map()
|
||||
|
||||
for (let dependencyIndex = 0; dependencyIndex < dataDependenciesModule.curatedDependencyNodeArray.length; dependencyIndex++) {
|
||||
let dependency = dataDependenciesModule.curatedDependencyNodeArray[dependencyIndex]
|
||||
let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex]
|
||||
|
||||
if (datasetModule.node.config.codeName !== "Single-File") {
|
||||
continue
|
||||
}
|
||||
|
||||
if (datasetModule.exchange !== currentExchange) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (datasetModule.market !== currentMarket) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (dataDependenciesModule.filters.exchange.timeFrames.get(datasetModule.exchange + '-' + datasetModule.market + '-' + datasetModule.product + '-' + 'atAnyTimeFrame') !== true) {
|
||||
/*
|
||||
If we can not find the current data set is used at the current time
|
||||
frame we will skip this file.
|
||||
*/
|
||||
continue
|
||||
}
|
||||
|
||||
let fileName = "Data.json"
|
||||
let filePath = datasetModule.node.parentNode.config.codeName + '/' + datasetModule.node.config.codeName
|
||||
|
||||
/* 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)
|
||||
|
||||
if (response.err.message === 'File does not exist.') {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] File not Found. This process will wait until you run your Data Mining and this file is created. File = " + filePath + '/' + fileName)
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] Your strategy depends on the dataset " + dependency.name + '.')
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] The reason that it depends on this dataset is becuase in one of your condition's Javascript Code node, you have written an expression that references this dataset. If you don't want to depend on this dataset, just locate that code and remove the mention.")
|
||||
return false
|
||||
}
|
||||
|
||||
if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
throw (response.err)
|
||||
}
|
||||
|
||||
let dataFile = JSON.parse(response.text)
|
||||
dataFiles.set(dependency.id, dataFile)
|
||||
}
|
||||
|
||||
let mapKey = currentExchange + '-' + currentMarket + '-' + "Single Files"
|
||||
multiTimeFrameDataFiles.set(mapKey, dataFiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function processMarketFiles() {
|
||||
/*
|
||||
We do market files first since if the simulation is run on daily files, there will
|
||||
be a loop to get each of those files and we do not need that loop to reload market files.
|
||||
*/
|
||||
|
||||
/*
|
||||
We will iterate through all the exchanges and markets involved.
|
||||
*/
|
||||
let exchangeList = Array.from(dataDependenciesModule.filters.exchange.list.keys())
|
||||
let marketList = Array.from(dataDependenciesModule.filters.market.list.keys())
|
||||
|
||||
for (let e = 0; e < exchangeList.length; e++) {
|
||||
let currentExchange = exchangeList[e]
|
||||
for (let m = 0; m < marketList.length; m++) {
|
||||
let currentMarket = marketList[m]
|
||||
/*
|
||||
We will iterate through all posible timeFrames.
|
||||
*/
|
||||
for (let n = 0; n < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length; n++) {
|
||||
const timeFrame = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][0]
|
||||
const timeFrameLabel = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1]
|
||||
|
||||
dataFiles = new Map()
|
||||
|
||||
/* Current Time Frame detection */
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeFrame.config.label === timeFrameLabel) {
|
||||
currentTimeFrame = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][0]
|
||||
currentTimeFrameLabel = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1]
|
||||
}
|
||||
|
||||
/* Loop across the list of curated dependencies */
|
||||
for (let dependencyIndex = 0; dependencyIndex < dataDependenciesModule.curatedDependencyNodeArray.length; dependencyIndex++) {
|
||||
let dependency = dataDependenciesModule.curatedDependencyNodeArray[dependencyIndex]
|
||||
let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex]
|
||||
|
||||
if (dependency.referenceParent.config.codeName !== "Multi-Period-Market") {
|
||||
continue
|
||||
}
|
||||
|
||||
if (datasetModule.exchange !== currentExchange) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (datasetModule.market !== currentMarket) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (dataDependenciesModule.filters.exchange.timeFrames.get(datasetModule.exchange + '-' + datasetModule.market + '-' + datasetModule.product + '-' + timeFrameLabel) !== true) {
|
||||
/*
|
||||
If we can not find the current data set is used at the current time
|
||||
frame we will skip this file, unless we are in the only special
|
||||
case that we are retrieving candles.
|
||||
*/
|
||||
if (!(TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeFrame.config.label === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) {
|
||||
continue
|
||||
}
|
||||
if (currentExchange !== dataDependenciesModule.defaultExchange || currentMarket !== dataDependenciesModule.defaultMarket) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
let fileName = "Data.json"
|
||||
let filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel
|
||||
|
||||
/* 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)
|
||||
|
||||
if (response.err.message === 'File does not exist.') {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] File not Found. This process will wait until you run your Data Mining and this file is created. File = " + filePath + '/' + fileName)
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] Your strategy depends on the dataset " + dependency.name + '.')
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] The reason that it depends on this dataset is becuase in one of your condition's Javascript Code node, you have written an expression that references this dataset. If you don't want to depend on this dataset, just locate that code and remove the mention.")
|
||||
return false
|
||||
}
|
||||
|
||||
if (response.err.result !== TS.projects.superalgos.globals.standardResponses.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) {
|
||||
/*
|
||||
Here we will discard all the records in a file that are outside of the current time range.
|
||||
We will include the las element previous to the begining of the time range. This is needed
|
||||
because during the simulation, the current period is not the open one, but the previous to
|
||||
the open, and if we do not include the previous to the initial datetime there will be no
|
||||
current objects at the begining of the simulation for many time frames.
|
||||
*/
|
||||
let beginIndex
|
||||
let endIndex
|
||||
let result = []
|
||||
for (let i = 0; i < recordDefinition.properties.length; i++) {
|
||||
let property = recordDefinition.properties[i]
|
||||
if (property.config.codeName === 'begin') {
|
||||
beginIndex = i
|
||||
}
|
||||
if (property.config.codeName === 'end') {
|
||||
endIndex = i
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < dataFile.length; i++) {
|
||||
let dataRecord = dataFile[i]
|
||||
let begin = dataRecord[beginIndex]
|
||||
let end = dataRecord[endIndex]
|
||||
if (end + timeFrame < TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeRange.config.initialDatetime - 1) { continue } // /1 because we need the previous closed element
|
||||
if (begin > TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeRange.config.finalDatetime) { continue }
|
||||
result.push(dataRecord)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
let mapKey = currentExchange + '-' + currentMarket + '-' + TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1]
|
||||
multiTimeFrameDataFiles.set(mapKey, dataFiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
async function processDailyFiles() {
|
||||
/* Telling the world we are alive and doing well and which date we are processing right now. */
|
||||
let processingDateString = tradingProcessDate.getUTCFullYear() + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(tradingProcessDate.getUTCDate(), 2)
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, processingDateString, undefined, "Running...")
|
||||
|
||||
/*
|
||||
We will iterate through all the exchanges and markets involved.
|
||||
*/
|
||||
let exchangeList = Array.from(dataDependenciesModule.filters.exchange.list.keys())
|
||||
let marketList = Array.from(dataDependenciesModule.filters.market.list.keys())
|
||||
|
||||
for (let e = 0; e < exchangeList.length; e++) {
|
||||
let currentExchange = exchangeList[e]
|
||||
for (let m = 0; m < marketList.length; m++) {
|
||||
let currentMarket = marketList[m]
|
||||
/*
|
||||
We will iterate through all posible timeFrames.
|
||||
*/
|
||||
for (let n = 0; n < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length; n++) {
|
||||
const timeFrameLabel = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][1]
|
||||
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.validtimeFrames !== undefined) {
|
||||
let validPeriod = false
|
||||
for (let i = 0; i < TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.validtimeFrames.length; i++) {
|
||||
let period = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.validtimeFrames[i]
|
||||
if (period === timeFrameLabel) { validPeriod = true }
|
||||
}
|
||||
if (validPeriod === false) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeFrame.config.label === timeFrameLabel) {
|
||||
currentTimeFrame = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][0]
|
||||
currentTimeFrameLabel = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][1]
|
||||
}
|
||||
|
||||
dataFiles = new Map()
|
||||
|
||||
/*
|
||||
We will iterate through all dependencies, in order to load the
|
||||
files that later will end up at the chart data structure.
|
||||
*/
|
||||
for (let dependencyIndex = 0; dependencyIndex < dataDependenciesModule.curatedDependencyNodeArray.length; dependencyIndex++) {
|
||||
let dependency = dataDependenciesModule.curatedDependencyNodeArray[dependencyIndex]
|
||||
let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex]
|
||||
|
||||
if (dependency.referenceParent.config.codeName !== "Multi-Period-Daily") {
|
||||
continue
|
||||
}
|
||||
|
||||
if (datasetModule.exchange !== currentExchange) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (datasetModule.market !== currentMarket) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (dataDependenciesModule.filters.exchange.timeFrames.get(datasetModule.exchange + '-' + datasetModule.market + '-' + datasetModule.product + '-' + timeFrameLabel) !== true) {
|
||||
/*
|
||||
If we can not find the current data set is used at the current time
|
||||
frame we will skip this file, unless we are in the only special
|
||||
case that we are retrieving candles.
|
||||
*/
|
||||
if (!(TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeFrame.config.label === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) {
|
||||
continue
|
||||
}
|
||||
if (currentExchange !== dataDependenciesModule.defaultExchange || currentMarket !== dataDependenciesModule.defaultMarket) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
We will need to fetch the data of the current day and the previous day, in order for .previous properties in conditions and formulas to work well.
|
||||
*/
|
||||
let previousDate = new Date(tradingProcessDate.valueOf() - TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS)
|
||||
let currentDate = new Date(tradingProcessDate.valueOf())
|
||||
|
||||
let previousFile = await getDataFileFromDate(previousDate)
|
||||
if (previousFile === false) { return false }
|
||||
let currentFile = await getDataFileFromDate(currentDate)
|
||||
if (currentFile === false) { return false }
|
||||
let bothFiles = previousFile.concat(currentFile)
|
||||
dataFiles.set(dependency.id, bothFiles)
|
||||
|
||||
async function getDataFileFromDate(processDate) {
|
||||
|
||||
let dateForPath = processDate.getUTCFullYear() + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processDate.getUTCMonth() + 1, 2) + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processDate.getUTCDate(), 2)
|
||||
let filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel + "/" + dateForPath
|
||||
let fileName = "Data.json"
|
||||
|
||||
/* 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)
|
||||
|
||||
if (response.err.message === 'File does not exist.') {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] File not Found. This process will wait until you run your Data Mining and this file is created. File = " + filePath + '/' + fileName)
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] Your strategy depends on the dataset " + dependency.name + '.')
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] The reason that it depends on this dataset is becuase in one of your condition's Javascript Code node, you have written an expression that references this dataset. If you don't want to depend on this dataset, just locate that code and remove the mention.")
|
||||
return false
|
||||
}
|
||||
if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
throw (response.err)
|
||||
}
|
||||
|
||||
return JSON.parse(response.text)
|
||||
}
|
||||
}
|
||||
let mapKey = currentExchange + '-' + currentMarket + '-' + TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][1]
|
||||
multiTimeFrameDataFiles.set(mapKey, dataFiles)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function checkStopHeadOfTheMarket() {
|
||||
/*
|
||||
We need to check if we have reached the head of the market in order to know
|
||||
@@ -671,151 +259,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
function buildDataStructures() {
|
||||
/* Fisrt Phase: Validations */
|
||||
let mainDependency = {}
|
||||
/*
|
||||
THe first thing we do is to build an array of all the
|
||||
declared dependencies of the Trading Bot.
|
||||
*/
|
||||
let dataDependencies = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processDependencies, 'Data Dependency')
|
||||
/*
|
||||
Then we will filter out declared dependencies that are
|
||||
not referencing nodes currently present at the workspace.
|
||||
This will allow the user to have less Data Mines loaded at
|
||||
the workspace that the ones that a Trading Bot depends on.
|
||||
*/
|
||||
dataDependencies = TS.projects.superalgos.utilities.nodeFunctions.filterOutNodeWihtoutReferenceParentFromNodeArray(dataDependencies)
|
||||
/*
|
||||
We will run some validations to prevent starting the process
|
||||
if all needed config and nodes are not present.
|
||||
*/
|
||||
if (TS.projects.superalgos.functionLibraries.singleMarketFunctions.validateDataDependencies(processIndex, dataDependencies, callBackFunction) !== true) { return }
|
||||
/*
|
||||
Next we will build an array of output datasets of this process.
|
||||
We are not going to use it right now, but later down the line,
|
||||
we do it just to be able to validate that all nodes and config
|
||||
are ok before letting this provess run too far.
|
||||
*/
|
||||
let outputDatasets = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset')
|
||||
/*
|
||||
Here we check that all output datasets configs are ok.
|
||||
*/
|
||||
if (TS.projects.superalgos.functionLibraries.singleMarketFunctions.validateOutputDatasets(processIndex, outputDatasets, callBackFunction) !== true) { return }
|
||||
|
||||
/* Second Phase: Bilding the chart data structure */
|
||||
|
||||
/*
|
||||
This phase is about transforming the inputs into a format,
|
||||
or data structure that can be used in Javascript Code and
|
||||
Formula nodes to access Indicator's data.
|
||||
*/
|
||||
|
||||
let exchangeList = Array.from(dataDependenciesModule.filters.exchange.list.keys())
|
||||
let marketList = Array.from(dataDependenciesModule.filters.market.list.keys())
|
||||
|
||||
for (let e = 0; e < exchangeList.length; e++) {
|
||||
let currentExchange = exchangeList[e]
|
||||
for (let m = 0; m < marketList.length; m++) {
|
||||
let currentMarket = marketList[m]
|
||||
let splittedMarket = currentMarket.split('-')
|
||||
let baseAsset = splittedMarket[0]
|
||||
let quotedAsset = splittedMarket[1]
|
||||
|
||||
/* Market Files */
|
||||
for (let j = 0; j < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length; j++) {
|
||||
let timeFrameLabel = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[j][1]
|
||||
let dataFiles = multiTimeFrameDataFiles.get(currentExchange + '-' + currentMarket + '-' + timeFrameLabel)
|
||||
let products = {}
|
||||
|
||||
if (dataFiles !== undefined && dataFiles.size > 0) {
|
||||
TS.projects.superalgos.functionLibraries.singleMarketFunctions.inflateDatafiles(processIndex, dataFiles, dataDependencies, products, mainDependency, currentTimeFrame)
|
||||
|
||||
let propertyName = 'at' + timeFrameLabel.replace('-', '')
|
||||
addProducs(propertyName, products)
|
||||
}
|
||||
}
|
||||
|
||||
/* Daily Files */
|
||||
for (let j = 0; j < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length; j++) {
|
||||
let timeFrameLabel = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[j][1]
|
||||
let dataFiles = multiTimeFrameDataFiles.get(currentExchange + '-' + currentMarket + '-' + timeFrameLabel)
|
||||
let products = {}
|
||||
|
||||
if (dataFiles !== undefined && dataFiles.size > 0) {
|
||||
TS.projects.superalgos.functionLibraries.singleMarketFunctions.inflateDatafiles(processIndex, dataFiles, dataDependencies, products, mainDependency, currentTimeFrame)
|
||||
|
||||
let propertyName = 'at' + timeFrameLabel.replace('-', '')
|
||||
addProducs(propertyName, products)
|
||||
}
|
||||
}
|
||||
|
||||
/* Single Files */
|
||||
{
|
||||
let dataFiles = multiTimeFrameDataFiles.get(currentExchange + '-' + currentMarket + '-' + 'Single Files')
|
||||
let products = {}
|
||||
|
||||
if (dataFiles !== undefined && dataFiles.size > 0) {
|
||||
TS.projects.superalgos.functionLibraries.singleMarketFunctions.inflateDatafiles(processIndex, dataFiles, dataDependencies, products, mainDependency, currentTimeFrame)
|
||||
|
||||
let propertyName = 'atAnyTimeFrame'
|
||||
addProducs(propertyName, products)
|
||||
}
|
||||
}
|
||||
|
||||
function addProducs(propertyName, products) {
|
||||
/*
|
||||
The chart data structure allow users to simplify the syntax when they are using
|
||||
the default exchange and the default market.
|
||||
*/
|
||||
if (currentExchange === dataDependenciesModule.defaultExchange && currentMarket === dataDependenciesModule.defaultMarket) {
|
||||
chart[propertyName] = products
|
||||
}
|
||||
/*
|
||||
The market data structure allow users to simplify the syntax when they are using
|
||||
the default exchange.
|
||||
*/
|
||||
if (currentExchange === dataDependenciesModule.defaultExchange) {
|
||||
if (market[baseAsset] === undefined) {
|
||||
market[baseAsset] = {}
|
||||
}
|
||||
if (market[baseAsset][quotedAsset] === undefined) {
|
||||
market[baseAsset][quotedAsset] = {}
|
||||
}
|
||||
if (market[baseAsset][quotedAsset].chart === undefined) {
|
||||
market[baseAsset][quotedAsset].chart = {}
|
||||
}
|
||||
market[baseAsset][quotedAsset].chart[propertyName] = products
|
||||
}
|
||||
|
||||
if (exchange[currentExchange] === undefined) {
|
||||
exchange[currentExchange] = {}
|
||||
}
|
||||
if (exchange[currentExchange].market === undefined) {
|
||||
exchange[currentExchange].market = {}
|
||||
}
|
||||
if (exchange[currentExchange].market[baseAsset] === undefined) {
|
||||
exchange[currentExchange].market[baseAsset] = {}
|
||||
}
|
||||
if (exchange[currentExchange].market[baseAsset][quotedAsset] === undefined) {
|
||||
exchange[currentExchange].market[baseAsset][quotedAsset] = {}
|
||||
}
|
||||
if (exchange[currentExchange].market[baseAsset][quotedAsset].chart === undefined) {
|
||||
exchange[currentExchange].market[baseAsset][quotedAsset].chart = {}
|
||||
}
|
||||
exchange[currentExchange].market[baseAsset][quotedAsset].chart[propertyName] = products
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function generateOutput() {
|
||||
async function outputManagement() {
|
||||
await tradingOutputModuleObject.start(
|
||||
chart,
|
||||
market,
|
||||
exchange,
|
||||
currentTimeFrame,
|
||||
currentTimeFrameLabel,
|
||||
currentTimeFrame.value,
|
||||
currentTimeFrame.label,
|
||||
tradingProcessDate
|
||||
)
|
||||
|
||||
@@ -827,108 +277,6 @@
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_RESUMING = false
|
||||
}
|
||||
|
||||
async function writeProcessFiles() {
|
||||
let outputDatasets = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset')
|
||||
|
||||
await writeTimeFramesFiles(currentTimeFrame, currentTimeFrameLabel)
|
||||
await writeDataRanges()
|
||||
|
||||
if (currentTimeFrame > TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[0][0]) {
|
||||
await writeMarketStatusReport(currentTimeFrameLabel)
|
||||
} else {
|
||||
await writeDailyStatusReport(currentTimeFrameLabel)
|
||||
}
|
||||
|
||||
async function writeDataRanges() {
|
||||
for (
|
||||
let outputDatasetIndex = 0;
|
||||
outputDatasetIndex < outputDatasets.length;
|
||||
outputDatasetIndex++
|
||||
) {
|
||||
let productCodeName = outputDatasets[outputDatasetIndex].referenceParent.parentNode.config.codeName
|
||||
await writeDataRange(productCodeName)
|
||||
}
|
||||
|
||||
async function writeDataRange(productCodeName) {
|
||||
let dataRange = {
|
||||
begin: contextVariables.dateBeginOfMarket.valueOf(),
|
||||
end: tradingProcessDate.valueOf() + TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS
|
||||
}
|
||||
|
||||
let fileContent = JSON.stringify(dataRange)
|
||||
let fileName = '/Data.Range.json'
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Output/" + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME + "/" + productCodeName + "/" + 'Multi-Period-Daily' + fileName
|
||||
|
||||
let response = await fileStorage.asyncCreateTextFile(filePath, fileContent + '\n')
|
||||
|
||||
if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
throw (response.err)
|
||||
}
|
||||
|
||||
/*
|
||||
Raise the event that the Data Range was Updated.
|
||||
*/
|
||||
let key = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + productCodeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName
|
||||
let event = {
|
||||
dateRange: dataRange
|
||||
}
|
||||
|
||||
TS.projects.superalgos.globals.taskConstants.EVENT_SERVER_CLIENT_MODULE_OBJECT.raiseEvent(key, 'Data Range Updated', event)
|
||||
}
|
||||
}
|
||||
|
||||
async function writeTimeFramesFiles(currentTimeFrame, currentTimeFrameLabel) {
|
||||
|
||||
for (
|
||||
let outputDatasetIndex = 0;
|
||||
outputDatasetIndex < outputDatasets.length;
|
||||
outputDatasetIndex++
|
||||
) {
|
||||
let productCodeName = outputDatasets[outputDatasetIndex].referenceParent.parentNode.config.codeName
|
||||
await writeTimeFramesFile(currentTimeFrameLabel, productCodeName, 'Multi-Period-Daily')
|
||||
await writeTimeFramesFile(currentTimeFrameLabel, productCodeName, 'Multi-Period-Market')
|
||||
|
||||
async function writeTimeFramesFile(currentTimeFrameLabel, productCodeName, processType) {
|
||||
|
||||
let timeFramesArray = []
|
||||
timeFramesArray.push(currentTimeFrameLabel)
|
||||
|
||||
let fileContent = JSON.stringify(timeFramesArray)
|
||||
let fileName = '/Time.Frames.json'
|
||||
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Output/" + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME + "/" + productCodeName + "/" + processType + fileName
|
||||
|
||||
let response = await fileStorage.asyncCreateTextFile(filePath, fileContent + '\n')
|
||||
if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
throw (response.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function writeDailyStatusReport(currentTimeFrameLabel) {
|
||||
let reportKey = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName
|
||||
let thisReport = statusDependencies.statusReports.get(reportKey)
|
||||
|
||||
thisReport.file.lastFile = tradingProcessDate
|
||||
thisReport.file.simulationState = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE
|
||||
thisReport.file.timeFrames = currentTimeFrameLabel
|
||||
await thisReport.asyncSave()
|
||||
}
|
||||
|
||||
async function writeMarketStatusReport(currentTimeFrameLabel) {
|
||||
let reportKey = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName
|
||||
let thisReport = statusDependencies.statusReports.get(reportKey)
|
||||
|
||||
thisReport.file.lastExecution = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME
|
||||
thisReport.file.simulationState = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE
|
||||
thisReport.file.timeFrames = currentTimeFrameLabel
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.newInternalLoop(tradingProcessDate)
|
||||
await thisReport.asyncSave()
|
||||
}
|
||||
}
|
||||
|
||||
function checkIfSessionMustStop() {
|
||||
|
||||
if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.type === 'Backtesting Session') {
|
||||
@@ -969,22 +317,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function asyncGetDatasetFile(datasetModule, filePath, fileName) {
|
||||
|
||||
let promise = new Promise((resolve, reject) => {
|
||||
|
||||
datasetModule.getTextFile(filePath, fileName, onFileReceived)
|
||||
function onFileReceived(err, text) {
|
||||
|
||||
let response = {
|
||||
err: err,
|
||||
text: text
|
||||
}
|
||||
resolve(response)
|
||||
}
|
||||
})
|
||||
|
||||
return promise
|
||||
}
|
||||
}
|
||||
-1
@@ -310,7 +310,6 @@ exports.newSuperalgosBotModulesTradingSimulation = function (processIndex) {
|
||||
let currentDateString = heartBeatDate.getUTCFullYear() + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(heartBeatDate.getUTCMonth() + 1, 2) + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(heartBeatDate.getUTCDate(), 2)
|
||||
let currentDate = new Date(heartBeatDate)
|
||||
let percentage = TS.projects.superalgos.utilities.dateTimeFunctions.getPercentage(fromDate, currentDate, lastDate)
|
||||
|
||||
/*
|
||||
Theere are a few tasks that we need to do only when the date changes,
|
||||
otherwise it would be suboptimal.
|
||||
|
||||
@@ -282,7 +282,7 @@
|
||||
switch (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.name) {
|
||||
case 'Low-Frequency-Trading-Process': {
|
||||
processFramework = TS.projects.superalgos.botModules.tradingProcess.newSuperalgosBotModulesTradingProcess(processIndex);
|
||||
intitializeProcessFramework();
|
||||
startProcessFramework();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -335,71 +335,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
function intitializeProcessFramework() {
|
||||
try {
|
||||
processFramework.initialize(statusDependencies, dataDependencies, onInizialized);
|
||||
|
||||
function onInizialized(err) {
|
||||
try {
|
||||
switch (err.result) {
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> intitializeProcessFramework -> onInizialized -> Execution finished well.");
|
||||
startProcessFramework();
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> intitializeProcessFramework -> onInizialized -> Retry Later. Requesting Execution Retry.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Operation Failed. Aborting the process.");
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized > Unhandled custom response received. -> err = " + err.message);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Unhandled err.result received. -> err = " + err.message);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> intitializeProcessFramework -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.stopProcess(processIndex, callBackFunction, nextLoopTimeoutHandle)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function startProcessFramework() {
|
||||
try {
|
||||
processFramework.start(onFinished);
|
||||
processFramework.start(statusDependencies, dataDependencies, onFinished);
|
||||
|
||||
function onFinished(err) {
|
||||
try {
|
||||
processFramework.finalize()
|
||||
processFramework = undefined
|
||||
dataDependencies.finalize()
|
||||
dataDependencies = undefined
|
||||
|
||||
@@ -0,0 +1,502 @@
|
||||
exports.newSuperalgosFunctionLibrariesDataDependenciesFunctions = function () {
|
||||
/*
|
||||
This module contains the functions that will allow you to load in memory
|
||||
the data files which a process depends on, and later build the
|
||||
data structures that will allow users to write conditions and formulas
|
||||
using these data structures.
|
||||
*/
|
||||
const MODULE_NAME = "Data Dependency Function"
|
||||
|
||||
let thisObject = {
|
||||
processSingleFiles: processSingleFiles,
|
||||
processMarketFiles: processMarketFiles,
|
||||
processDailyFiles: processDailyFiles,
|
||||
buildDataStructures: buildDataStructures
|
||||
}
|
||||
|
||||
return thisObject
|
||||
|
||||
async function processSingleFiles(
|
||||
processIndex,
|
||||
dataFiles,
|
||||
multiTimeFrameDataFiles,
|
||||
dataDependenciesModule
|
||||
) {
|
||||
|
||||
/*
|
||||
We will iterate through all the exchanges and markets involved.
|
||||
*/
|
||||
let exchangeList = Array.from(dataDependenciesModule.filters.exchange.list.keys())
|
||||
let marketList = Array.from(dataDependenciesModule.filters.market.list.keys())
|
||||
|
||||
for (let e = 0; e < exchangeList.length; e++) {
|
||||
let currentExchange = exchangeList[e]
|
||||
for (let m = 0; m < marketList.length; m++) {
|
||||
let currentMarket = marketList[m]
|
||||
|
||||
dataFiles = new Map()
|
||||
|
||||
for (let dependencyIndex = 0; dependencyIndex < dataDependenciesModule.curatedDependencyNodeArray.length; dependencyIndex++) {
|
||||
let dependency = dataDependenciesModule.curatedDependencyNodeArray[dependencyIndex]
|
||||
let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex]
|
||||
|
||||
if (datasetModule.node.config.codeName !== "Single-File") {
|
||||
continue
|
||||
}
|
||||
|
||||
if (datasetModule.exchange !== currentExchange) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (datasetModule.market !== currentMarket) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (dataDependenciesModule.filters.exchange.timeFrames.get(datasetModule.exchange + '-' + datasetModule.market + '-' + datasetModule.product + '-' + 'atAnyTimeFrame') !== true) {
|
||||
/*
|
||||
If we can not find the current data set is used at the current time
|
||||
frame we will skip this file.
|
||||
*/
|
||||
continue
|
||||
}
|
||||
|
||||
let fileName = "Data.json"
|
||||
let filePath = datasetModule.node.parentNode.config.codeName + '/' + datasetModule.node.config.codeName
|
||||
|
||||
/* We cut the async calls via callBacks at this point, so as to have a clearer code upstream */
|
||||
let response = await TS.projects.superalgos.utilities.miscellaneousFunctions.asyncGetDatasetFile(datasetModule, filePath, fileName)
|
||||
|
||||
if (response.err.message === 'File does not exist.') {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] File not Found. This process will wait until you run your Data Mining and this file is created. File = " + filePath + '/' + fileName)
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] Your strategy depends on the dataset " + dependency.name + '.')
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] The reason that it depends on this dataset is becuase in one of your condition's Javascript Code node, you have written an expression that references this dataset. If you don't want to depend on this dataset, just locate that code and remove the mention.")
|
||||
return false
|
||||
}
|
||||
|
||||
if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
throw (response.err)
|
||||
}
|
||||
|
||||
let dataFile = JSON.parse(response.text)
|
||||
dataFiles.set(dependency.id, dataFile)
|
||||
}
|
||||
|
||||
let mapKey = currentExchange + '-' + currentMarket + '-' + "Single Files"
|
||||
multiTimeFrameDataFiles.set(mapKey, dataFiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function processMarketFiles(
|
||||
processIndex,
|
||||
dataFiles,
|
||||
multiTimeFrameDataFiles,
|
||||
dataDependenciesModule,
|
||||
currentTimeFrame,
|
||||
userDefinedTimeFrame,
|
||||
initialDatetime,
|
||||
finalDatetime
|
||||
) {
|
||||
/*
|
||||
We do market files first since if the simulation is run on daily files, there will
|
||||
be a loop to get each of those files and we do not need that loop to reload market files.
|
||||
*/
|
||||
|
||||
/*
|
||||
We will iterate through all the exchanges and markets involved.
|
||||
*/
|
||||
let exchangeList = Array.from(dataDependenciesModule.filters.exchange.list.keys())
|
||||
let marketList = Array.from(dataDependenciesModule.filters.market.list.keys())
|
||||
|
||||
for (let e = 0; e < exchangeList.length; e++) {
|
||||
let currentExchange = exchangeList[e]
|
||||
for (let m = 0; m < marketList.length; m++) {
|
||||
let currentMarket = marketList[m]
|
||||
/*
|
||||
We will iterate through all posible timeFrames.
|
||||
*/
|
||||
for (let n = 0; n < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length; n++) {
|
||||
const timeFrame = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][0]
|
||||
const timeFrameLabel = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1]
|
||||
|
||||
dataFiles = new Map()
|
||||
|
||||
/* Current Time Frame detection */
|
||||
if (userDefinedTimeFrame === timeFrameLabel) {
|
||||
currentTimeFrame.value = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][0]
|
||||
currentTimeFrame.label = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1]
|
||||
}
|
||||
|
||||
/* Loop across the list of curated dependencies */
|
||||
for (let dependencyIndex = 0; dependencyIndex < dataDependenciesModule.curatedDependencyNodeArray.length; dependencyIndex++) {
|
||||
let dependency = dataDependenciesModule.curatedDependencyNodeArray[dependencyIndex]
|
||||
let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex]
|
||||
|
||||
if (dependency.referenceParent.config.codeName !== "Multi-Period-Market") {
|
||||
continue
|
||||
}
|
||||
|
||||
if (datasetModule.exchange !== currentExchange) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (datasetModule.market !== currentMarket) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (dataDependenciesModule.filters.exchange.timeFrames.get(datasetModule.exchange + '-' + datasetModule.market + '-' + datasetModule.product + '-' + timeFrameLabel) !== true) {
|
||||
/*
|
||||
If we can not find the current data set is used at the current time
|
||||
frame we will skip this file, unless we are in the only special
|
||||
case that we are retrieving candles.
|
||||
*/
|
||||
if (!(userDefinedTimeFrame === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) {
|
||||
continue
|
||||
}
|
||||
if (currentExchange !== dataDependenciesModule.defaultExchange || currentMarket !== dataDependenciesModule.defaultMarket) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
let fileName = "Data.json"
|
||||
let filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel
|
||||
|
||||
/* We cut the async calls via callBacks at this point, so as to have a clearer code upstream */
|
||||
let response = await TS.projects.superalgos.utilities.miscellaneousFunctions.asyncGetDatasetFile(datasetModule, filePath, fileName)
|
||||
|
||||
if (response.err.message === 'File does not exist.') {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] File not Found. This process will wait until you run your Data Mining and this file is created. File = " + filePath + '/' + fileName)
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] Your strategy depends on the dataset " + dependency.name + '.')
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] The reason that it depends on this dataset is becuase in one of your condition's Javascript Code node, you have written an expression that references this dataset. If you don't want to depend on this dataset, just locate that code and remove the mention.")
|
||||
return false
|
||||
}
|
||||
|
||||
if (response.err.result !== TS.projects.superalgos.globals.standardResponses.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) {
|
||||
/*
|
||||
Here we will discard all the records in a file that are outside of the current time range.
|
||||
We will include the las element previous to the begining of the time range. This is needed
|
||||
because during the simulation, the current period is not the open one, but the previous to
|
||||
the open, and if we do not include the previous to the initial datetime there will be no
|
||||
current objects at the begining of the simulation for many time frames.
|
||||
*/
|
||||
let beginIndex
|
||||
let endIndex
|
||||
let result = []
|
||||
for (let i = 0; i < recordDefinition.properties.length; i++) {
|
||||
let property = recordDefinition.properties[i]
|
||||
if (property.config.codeName === 'begin') {
|
||||
beginIndex = i
|
||||
}
|
||||
if (property.config.codeName === 'end') {
|
||||
endIndex = i
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < dataFile.length; i++) {
|
||||
let dataRecord = dataFile[i]
|
||||
let begin = dataRecord[beginIndex]
|
||||
let end = dataRecord[endIndex]
|
||||
if (end + timeFrame < initialDatetime - 1) { continue } // /1 because we need the previous closed element
|
||||
if (begin > finalDatetime) { continue }
|
||||
result.push(dataRecord)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
let mapKey = currentExchange + '-' + currentMarket + '-' + TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1]
|
||||
multiTimeFrameDataFiles.set(mapKey, dataFiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
async function processDailyFiles(
|
||||
processIndex,
|
||||
dataFiles,
|
||||
multiTimeFrameDataFiles,
|
||||
dataDependenciesModule,
|
||||
currentTimeFrame,
|
||||
userDefinedTimeFrame,
|
||||
processDate
|
||||
) {
|
||||
/* Telling the world we are alive and doing well and which date we are processing right now. */
|
||||
let processingDateString = processDate.getUTCFullYear() + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processDate.getUTCMonth() + 1, 2) + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processDate.getUTCDate(), 2)
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, processingDateString, undefined, "Running...")
|
||||
|
||||
/*
|
||||
We will iterate through all the exchanges and markets involved.
|
||||
*/
|
||||
let exchangeList = Array.from(dataDependenciesModule.filters.exchange.list.keys())
|
||||
let marketList = Array.from(dataDependenciesModule.filters.market.list.keys())
|
||||
|
||||
for (let e = 0; e < exchangeList.length; e++) {
|
||||
let currentExchange = exchangeList[e]
|
||||
for (let m = 0; m < marketList.length; m++) {
|
||||
let currentMarket = marketList[m]
|
||||
/*
|
||||
We will iterate through all posible timeFrames.
|
||||
*/
|
||||
for (let n = 0; n < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length; n++) {
|
||||
const timeFrameLabel = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][1]
|
||||
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.validtimeFrames !== undefined) {
|
||||
let validPeriod = false
|
||||
for (let i = 0; i < TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.validtimeFrames.length; i++) {
|
||||
let period = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.validtimeFrames[i]
|
||||
if (period === timeFrameLabel) { validPeriod = true }
|
||||
}
|
||||
if (validPeriod === false) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if (userDefinedTimeFrame === timeFrameLabel) {
|
||||
currentTimeFrame.value = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][0]
|
||||
currentTimeFrame.label = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][1]
|
||||
}
|
||||
|
||||
dataFiles = new Map()
|
||||
|
||||
/*
|
||||
We will iterate through all dependencies, in order to load the
|
||||
files that later will end up at the chart data structure.
|
||||
*/
|
||||
for (let dependencyIndex = 0; dependencyIndex < dataDependenciesModule.curatedDependencyNodeArray.length; dependencyIndex++) {
|
||||
let dependency = dataDependenciesModule.curatedDependencyNodeArray[dependencyIndex]
|
||||
let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex]
|
||||
|
||||
if (dependency.referenceParent.config.codeName !== "Multi-Period-Daily") {
|
||||
continue
|
||||
}
|
||||
|
||||
if (datasetModule.exchange !== currentExchange) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (datasetModule.market !== currentMarket) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (dataDependenciesModule.filters.exchange.timeFrames.get(datasetModule.exchange + '-' + datasetModule.market + '-' + datasetModule.product + '-' + timeFrameLabel) !== true) {
|
||||
/*
|
||||
If we can not find the current data set is used at the current time
|
||||
frame we will skip this file, unless we are in the only special
|
||||
case that we are retrieving candles.
|
||||
*/
|
||||
if (!(userDefinedTimeFrame === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) {
|
||||
continue
|
||||
}
|
||||
if (currentExchange !== dataDependenciesModule.defaultExchange || currentMarket !== dataDependenciesModule.defaultMarket) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
We will need to fetch the data of the current day and the previous day, in order for .previous properties in conditions and formulas to work well.
|
||||
*/
|
||||
let previousDate = new Date(processDate.valueOf() - TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS)
|
||||
let currentDate = new Date(processDate.valueOf())
|
||||
|
||||
let previousFile = await getDataFileFromDate(previousDate)
|
||||
if (previousFile === false) { return false }
|
||||
let currentFile = await getDataFileFromDate(currentDate)
|
||||
if (currentFile === false) { return false }
|
||||
let bothFiles = previousFile.concat(currentFile)
|
||||
dataFiles.set(dependency.id, bothFiles)
|
||||
|
||||
async function getDataFileFromDate(dataFileDate) {
|
||||
|
||||
let dateForPath = dataFileDate.getUTCFullYear() + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(dataFileDate.getUTCMonth() + 1, 2) + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(dataFileDate.getUTCDate(), 2)
|
||||
let filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel + "/" + dateForPath
|
||||
let fileName = "Data.json"
|
||||
|
||||
/* We cut the async calls via callBacks at this point, so as to have a clearer code upstream */
|
||||
let response = await TS.projects.superalgos.utilities.miscellaneousFunctions.asyncGetDatasetFile(datasetModule, filePath, fileName)
|
||||
|
||||
if (response.err.message === 'File does not exist.') {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] File not Found. This process will wait until you run your Data Mining and this file is created. File = " + filePath + '/' + fileName)
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] Your strategy depends on the dataset " + dependency.name + '.')
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] The reason that it depends on this dataset is becuase in one of your condition's Javascript Code node, you have written an expression that references this dataset. If you don't want to depend on this dataset, just locate that code and remove the mention.")
|
||||
return false
|
||||
}
|
||||
if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
throw (response.err)
|
||||
}
|
||||
|
||||
return JSON.parse(response.text)
|
||||
}
|
||||
}
|
||||
let mapKey = currentExchange + '-' + currentMarket + '-' + TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][1]
|
||||
multiTimeFrameDataFiles.set(mapKey, dataFiles)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function buildDataStructures(
|
||||
processIndex,
|
||||
dataDependenciesModule,
|
||||
multiTimeFrameDataFiles,
|
||||
currentTimeFrame,
|
||||
chart,
|
||||
market,
|
||||
exchange,
|
||||
callBackFunction
|
||||
) {
|
||||
/* Fisrt Phase: Validations */
|
||||
let mainDependency = {}
|
||||
/*
|
||||
THe first thing we do is to build an array of all the
|
||||
declared dependencies of the Bot Process.
|
||||
*/
|
||||
let dataDependencies = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processDependencies, 'Data Dependency')
|
||||
/*
|
||||
Then we will filter out declared dependencies that are
|
||||
not referencing nodes currently present at the workspace.
|
||||
This will allow the user to have less Data Mines loaded at
|
||||
the workspace that the ones that a the Bot process depends on.
|
||||
*/
|
||||
dataDependencies = TS.projects.superalgos.utilities.nodeFunctions.filterOutNodeWihtoutReferenceParentFromNodeArray(dataDependencies)
|
||||
/*
|
||||
We will run some validations to prevent starting the process
|
||||
if all needed config and nodes are not present.
|
||||
*/
|
||||
if (TS.projects.superalgos.functionLibraries.singleMarketFunctions.validateDataDependencies(processIndex, dataDependencies, callBackFunction) !== true) { return }
|
||||
/*
|
||||
Next we will build an array of output datasets of this process.
|
||||
We are not going to use it right now, but later down the line,
|
||||
we do it just to be able to validate that all nodes and config
|
||||
are ok before letting this provess run too far.
|
||||
*/
|
||||
let outputDatasets = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset')
|
||||
/*
|
||||
Here we check that all output datasets configs are ok.
|
||||
*/
|
||||
if (TS.projects.superalgos.functionLibraries.singleMarketFunctions.validateOutputDatasets(processIndex, outputDatasets, callBackFunction) !== true) { return }
|
||||
|
||||
/* Second Phase: Bilding the chart data structure */
|
||||
|
||||
/*
|
||||
This phase is about transforming the inputs into a format,
|
||||
or data structure that can be used in Javascript Code and
|
||||
Formula nodes to access Indicator's data.
|
||||
*/
|
||||
|
||||
let exchangeList = Array.from(dataDependenciesModule.filters.exchange.list.keys())
|
||||
let marketList = Array.from(dataDependenciesModule.filters.market.list.keys())
|
||||
|
||||
for (let e = 0; e < exchangeList.length; e++) {
|
||||
let currentExchange = exchangeList[e]
|
||||
for (let m = 0; m < marketList.length; m++) {
|
||||
let currentMarket = marketList[m]
|
||||
let splittedMarket = currentMarket.split('-')
|
||||
let baseAsset = splittedMarket[0]
|
||||
let quotedAsset = splittedMarket[1]
|
||||
|
||||
/* Market Files */
|
||||
for (let j = 0; j < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length; j++) {
|
||||
let timeFrameLabel = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[j][1]
|
||||
let dataFiles = multiTimeFrameDataFiles.get(currentExchange + '-' + currentMarket + '-' + timeFrameLabel)
|
||||
let products = {}
|
||||
|
||||
if (dataFiles !== undefined && dataFiles.size > 0) {
|
||||
TS.projects.superalgos.functionLibraries.singleMarketFunctions.inflateDatafiles(processIndex, dataFiles, dataDependencies, products, mainDependency, currentTimeFrame.value)
|
||||
|
||||
let propertyName = 'at' + timeFrameLabel.replace('-', '')
|
||||
addProducs(propertyName, products)
|
||||
}
|
||||
}
|
||||
|
||||
/* Daily Files */
|
||||
for (let j = 0; j < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length; j++) {
|
||||
let timeFrameLabel = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[j][1]
|
||||
let dataFiles = multiTimeFrameDataFiles.get(currentExchange + '-' + currentMarket + '-' + timeFrameLabel)
|
||||
let products = {}
|
||||
|
||||
if (dataFiles !== undefined && dataFiles.size > 0) {
|
||||
TS.projects.superalgos.functionLibraries.singleMarketFunctions.inflateDatafiles(processIndex, dataFiles, dataDependencies, products, mainDependency, currentTimeFrame.value)
|
||||
|
||||
let propertyName = 'at' + timeFrameLabel.replace('-', '')
|
||||
addProducs(propertyName, products)
|
||||
}
|
||||
}
|
||||
|
||||
/* Single Files */
|
||||
{
|
||||
let dataFiles = multiTimeFrameDataFiles.get(currentExchange + '-' + currentMarket + '-' + 'Single Files')
|
||||
let products = {}
|
||||
|
||||
if (dataFiles !== undefined && dataFiles.size > 0) {
|
||||
TS.projects.superalgos.functionLibraries.singleMarketFunctions.inflateDatafiles(processIndex, dataFiles, dataDependencies, products, mainDependency, currentTimeFrame.value)
|
||||
|
||||
let propertyName = 'atAnyTimeFrame'
|
||||
addProducs(propertyName, products)
|
||||
}
|
||||
}
|
||||
|
||||
function addProducs(propertyName, products) {
|
||||
/*
|
||||
The chart data structure allow users to simplify the syntax when they are using
|
||||
the default exchange and the default market.
|
||||
*/
|
||||
if (currentExchange === dataDependenciesModule.defaultExchange && currentMarket === dataDependenciesModule.defaultMarket) {
|
||||
chart[propertyName] = products
|
||||
}
|
||||
/*
|
||||
The market data structure allow users to simplify the syntax when they are using
|
||||
the default exchange.
|
||||
*/
|
||||
if (currentExchange === dataDependenciesModule.defaultExchange) {
|
||||
if (market[baseAsset] === undefined) {
|
||||
market[baseAsset] = {}
|
||||
}
|
||||
if (market[baseAsset][quotedAsset] === undefined) {
|
||||
market[baseAsset][quotedAsset] = {}
|
||||
}
|
||||
if (market[baseAsset][quotedAsset].chart === undefined) {
|
||||
market[baseAsset][quotedAsset].chart = {}
|
||||
}
|
||||
market[baseAsset][quotedAsset].chart[propertyName] = products
|
||||
}
|
||||
|
||||
if (exchange[currentExchange] === undefined) {
|
||||
exchange[currentExchange] = {}
|
||||
}
|
||||
if (exchange[currentExchange].market === undefined) {
|
||||
exchange[currentExchange].market = {}
|
||||
}
|
||||
if (exchange[currentExchange].market[baseAsset] === undefined) {
|
||||
exchange[currentExchange].market[baseAsset] = {}
|
||||
}
|
||||
if (exchange[currentExchange].market[baseAsset][quotedAsset] === undefined) {
|
||||
exchange[currentExchange].market[baseAsset][quotedAsset] = {}
|
||||
}
|
||||
if (exchange[currentExchange].market[baseAsset][quotedAsset].chart === undefined) {
|
||||
exchange[currentExchange].market[baseAsset][quotedAsset].chart = {}
|
||||
}
|
||||
exchange[currentExchange].market[baseAsset][quotedAsset].chart[propertyName] = products
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
|
||||
exports.newSuperalgosFunctionLibrariesOutputManagementFunctions = function () {
|
||||
/*
|
||||
This module helps a bot process to manage it's output files, since it load
|
||||
the current state of it's output and allows the bot process to append info
|
||||
to it. It also allows the bot process to save all updated output.
|
||||
*/
|
||||
const MODULE_NAME = "Output Management Functions"
|
||||
|
||||
let thisObject = {
|
||||
readFiles: readFiles,
|
||||
writeFiles: writeFiles
|
||||
}
|
||||
return thisObject
|
||||
|
||||
async function readFiles(
|
||||
processIndex,
|
||||
outputDatasets,
|
||||
outputDatasetsMap,
|
||||
timeFrameLabel,
|
||||
tradingProcessDate,
|
||||
fileStorage
|
||||
) {
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES === true) {
|
||||
/*
|
||||
For Daily Files, we are going to initialize the outputs at the first execution
|
||||
if we are not resuming, but also at every following execution except when
|
||||
we are at the head of the market, because at the head of the market we need to
|
||||
append more data to the same output files that already exists.
|
||||
*/
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_FIRST_LOOP === true && TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_RESUMING === false) {
|
||||
await initializeOutputs()
|
||||
} else {
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.tradingEngine.current.episode.headOfTheMarket.value === true) {
|
||||
await loadFiles()
|
||||
} else {
|
||||
await initializeOutputs()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
Form Market Files, we are only going to initialize the outputs at the first run
|
||||
and if we are not resuming execution. Subsequent runs means that we are at the
|
||||
head of the market. Remember that backtests finishes the session once the reach
|
||||
the final datetime.
|
||||
*/
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_FIRST_LOOP === true && TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_RESUMING === false) {
|
||||
await initializeOutputs()
|
||||
} else {
|
||||
await loadFiles()
|
||||
}
|
||||
}
|
||||
|
||||
async function initializeOutputs() {
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES) {
|
||||
await initializeDailyFiles()
|
||||
} else {
|
||||
await initializeMarketFiles()
|
||||
}
|
||||
|
||||
async function initializeDailyFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
|
||||
if (dataset.config.type === 'Daily Files') {
|
||||
outputDatasetsMap.set(dataset.parentNode.config.codeName, [])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function initializeMarketFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
|
||||
if (dataset.config.type === 'Market Files') {
|
||||
outputDatasetsMap.set(dataset.parentNode.config.codeName, [])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function loadFiles() {
|
||||
/*
|
||||
This bot have an output of files that it generates. At every call to the bot, it needs to read the previously generated
|
||||
files in order to later append more information after the execution is over. Here in this function we are going to
|
||||
read those output files and get them ready for appending content during the simulation.
|
||||
*/
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES) {
|
||||
await readDailyFiles()
|
||||
} else {
|
||||
await readMarketFiles()
|
||||
}
|
||||
}
|
||||
|
||||
async function readMarketFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
|
||||
if (dataset.config.type === 'Market Files') {
|
||||
|
||||
let fileName = 'Data.json'
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + '/Output/' + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel
|
||||
|
||||
await readOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function readDailyFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
|
||||
if (dataset.config.type === 'Daily Files') {
|
||||
|
||||
let dateForPath = tradingProcessDate.getUTCFullYear() + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(tradingProcessDate.getUTCDate(), 2);
|
||||
let fileName = 'Data.json'
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + '/Output/' + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel + "/" + dateForPath
|
||||
|
||||
await readOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function readOutputFile(fileName, filePath, productName) {
|
||||
filePath += '/' + fileName
|
||||
|
||||
let response = await fileStorage.asyncGetTextFile(filePath, true)
|
||||
|
||||
if (response.err.message === 'File does not exist.') {
|
||||
outputDatasetsMap.set(productName, [])
|
||||
return
|
||||
}
|
||||
if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
throw (response.err)
|
||||
}
|
||||
outputDatasetsMap.set(productName, JSON.parse(response.text))
|
||||
}
|
||||
}
|
||||
|
||||
async function writeFiles(
|
||||
processIndex,
|
||||
outputDatasets,
|
||||
outputDatasetsMap,
|
||||
timeFrameLabel,
|
||||
tradingProcessDate,
|
||||
fileStorage
|
||||
) {
|
||||
/*
|
||||
The output of files which were appended with information during the simulation execution, now needs to be saved.
|
||||
*/
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES) {
|
||||
await writeDailyFiles()
|
||||
} else {
|
||||
await writeMarketFiles()
|
||||
}
|
||||
|
||||
async function writeMarketFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
|
||||
if (dataset.config.type === 'Market Files') {
|
||||
|
||||
let fileName = 'Data.json'
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + '/Output/' + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel
|
||||
|
||||
await writeOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function writeDailyFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
|
||||
if (dataset.config.type === 'Daily Files') {
|
||||
|
||||
let dateForPath = tradingProcessDate.getUTCFullYear() + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(tradingProcessDate.getUTCDate(), 2);
|
||||
let fileName = 'Data.json'
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + '/Output/' + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel + "/" + dateForPath
|
||||
|
||||
await writeOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function writeOutputFile(fileName, filePath, productName) {
|
||||
filePath += '/' + fileName
|
||||
let fileContent = JSON.stringify(outputDatasetsMap.get(productName))
|
||||
|
||||
let response = await fileStorage.asyncCreateTextFile(filePath, fileContent)
|
||||
|
||||
if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
throw (response.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
exports.newSuperalgosFunctionLibrariesProcessFilesFunctions = function () {
|
||||
/*
|
||||
This module contains the functions that will allow you to load the
|
||||
process context variables before you do your work, and to save the
|
||||
process files once you are done.
|
||||
*/
|
||||
const MODULE_NAME = "Process Files Functions"
|
||||
|
||||
let thisObject = {
|
||||
getContextVariables: getContextVariables,
|
||||
writeProcessFiles: writeProcessFiles
|
||||
}
|
||||
return thisObject
|
||||
|
||||
function getContextVariables(processIndex, contextVariables, statusDependencies, initialDatetime, callBackFunction) {
|
||||
try {
|
||||
let thisReport
|
||||
let statusReport
|
||||
|
||||
/* We are going to use the start date as beging of market date. */
|
||||
contextVariables.dateBeginOfMarket = TS.projects.superalgos.utilities.dateTimeFunctions.removeTime(initialDatetime)
|
||||
/*
|
||||
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")
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return false
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return false
|
||||
}
|
||||
|
||||
thisReport = statusReport.file
|
||||
|
||||
if (thisReport.lastFile === undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Undefined Last File. -> thisReport = " + JSON.stringify(thisReport))
|
||||
|
||||
let customOK = {
|
||||
result: TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result,
|
||||
message: "Dependency not ready."
|
||||
}
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> customOK = " + customOK.message)
|
||||
callBackFunction(customOK)
|
||||
return false
|
||||
}
|
||||
|
||||
contextVariables.dateEndOfMarket = new Date(thisReport.lastFile.valueOf())
|
||||
|
||||
/* Finally we get our own Status Report. */
|
||||
statusReport = statusDependencies.reportsByMainUtility.get("Self Reference")
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return false
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process.")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
return false
|
||||
}
|
||||
|
||||
thisReport = statusReport.file
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE = thisReport.simulationState
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE === undefined) { TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE = {} } // This should happen only when there is no status report
|
||||
|
||||
if (thisReport.lastFile !== undefined) {
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_RESUMING !== true) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> Starting from the begining because bot has just started and resume execution was true.")
|
||||
startFromBegining()
|
||||
return true
|
||||
}
|
||||
contextVariables.lastFile = new Date(thisReport.lastFile)
|
||||
return true
|
||||
|
||||
} else {
|
||||
/*
|
||||
We are here becuse either:
|
||||
1. There is no status report
|
||||
2. There is no Last File (this happens on Market Files)
|
||||
*/
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> Starting from the begining of the market because own status report not found or lastFile was undefined.")
|
||||
startFromBegining()
|
||||
return true
|
||||
}
|
||||
|
||||
function startFromBegining() {
|
||||
contextVariables.lastFile = new Date(contextVariables.dateBeginOfMarket.getUTCFullYear() + "-" + (contextVariables.dateBeginOfMarket.getUTCMonth() + 1) + "-" + contextVariables.dateBeginOfMarket.getUTCDate() + " " + "00:00" + TS.projects.superalgos.globals.timeConstants.GMT_SECONDS)
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> startFromBegining -> contextVariables.lastFile = " + contextVariables.lastFile)
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> err = " + err.stack)
|
||||
if (err.message === "Cannot read property 'file' of undefined") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. ")
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys))
|
||||
}
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
|
||||
async function writeProcessFiles(processIndex, contextVariables, currentTimeFrame, processDate, statusDependencies) {
|
||||
|
||||
let fileStorage = TS.projects.superalgos.taskModules.fileStorage.newFileStorage(processIndex)
|
||||
let outputDatasets = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset')
|
||||
|
||||
await writeTimeFramesFiles()
|
||||
await writeDataRanges()
|
||||
|
||||
if (currentTimeFrame.value > TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[0][0]) {
|
||||
await writeMarketStatusReport()
|
||||
} else {
|
||||
await writeDailyStatusReport()
|
||||
}
|
||||
|
||||
async function writeDataRanges() {
|
||||
for (
|
||||
let outputDatasetIndex = 0;
|
||||
outputDatasetIndex < outputDatasets.length;
|
||||
outputDatasetIndex++
|
||||
) {
|
||||
let productCodeName = outputDatasets[outputDatasetIndex].referenceParent.parentNode.config.codeName
|
||||
await writeDataRange(productCodeName)
|
||||
}
|
||||
|
||||
async function writeDataRange(productCodeName) {
|
||||
let dataRange = {
|
||||
begin: contextVariables.dateBeginOfMarket.valueOf(),
|
||||
end: processDate.valueOf() + TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS
|
||||
}
|
||||
|
||||
let fileContent = JSON.stringify(dataRange)
|
||||
let fileName = '/Data.Range.json'
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Output/" + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME + "/" + productCodeName + "/" + 'Multi-Period-Daily' + fileName
|
||||
|
||||
let response = await fileStorage.asyncCreateTextFile(filePath, fileContent + '\n')
|
||||
|
||||
if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
throw (response.err)
|
||||
}
|
||||
|
||||
/*
|
||||
Raise the event that the Data Range was Updated.
|
||||
*/
|
||||
let key = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + productCodeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName
|
||||
let event = {
|
||||
dateRange: dataRange
|
||||
}
|
||||
|
||||
TS.projects.superalgos.globals.taskConstants.EVENT_SERVER_CLIENT_MODULE_OBJECT.raiseEvent(key, 'Data Range Updated', event)
|
||||
}
|
||||
}
|
||||
|
||||
async function writeTimeFramesFiles() {
|
||||
|
||||
for (
|
||||
let outputDatasetIndex = 0;
|
||||
outputDatasetIndex < outputDatasets.length;
|
||||
outputDatasetIndex++
|
||||
) {
|
||||
let productCodeName = outputDatasets[outputDatasetIndex].referenceParent.parentNode.config.codeName
|
||||
await writeTimeFramesFile(productCodeName, 'Multi-Period-Daily')
|
||||
await writeTimeFramesFile(productCodeName, 'Multi-Period-Market')
|
||||
|
||||
async function writeTimeFramesFile(productCodeName, processType) {
|
||||
|
||||
let timeFramesArray = []
|
||||
timeFramesArray.push(currentTimeFrame.label)
|
||||
|
||||
let fileContent = JSON.stringify(timeFramesArray)
|
||||
let fileName = '/Time.Frames.json'
|
||||
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Output/" + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME + "/" + productCodeName + "/" + processType + fileName
|
||||
|
||||
let response = await fileStorage.asyncCreateTextFile(filePath, fileContent + '\n')
|
||||
if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
throw (response.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function writeDailyStatusReport() {
|
||||
let reportKey = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName
|
||||
let thisReport = statusDependencies.statusReports.get(reportKey)
|
||||
|
||||
thisReport.file.lastFile = processDate
|
||||
thisReport.file.simulationState = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE
|
||||
thisReport.file.timeFrames = currentTimeFrame.label
|
||||
await thisReport.asyncSave()
|
||||
}
|
||||
|
||||
async function writeMarketStatusReport() {
|
||||
let reportKey = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName
|
||||
let thisReport = statusDependencies.statusReports.get(reportKey)
|
||||
|
||||
thisReport.file.lastExecution = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME
|
||||
thisReport.file.simulationState = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE
|
||||
thisReport.file.timeFrames = currentTimeFrame.label
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.newInternalLoop(processDate)
|
||||
await thisReport.asyncSave()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,8 +113,10 @@
|
||||
we need to add the default exchange and market to these maps in order
|
||||
for the following sections to work.
|
||||
*/
|
||||
thisObject.filters.market.list.set(thisObject.defaultMarket, true)
|
||||
|
||||
thisObject.filters.exchange.list.set(thisObject.defaultExchange, true)
|
||||
thisObject.filters.exchange.markets.set(thisObject.defaultExchange + '-' + thisObject.defautMarket, true)
|
||||
thisObject.filters.exchange.markets.set(thisObject.defaultExchange + '-' + thisObject.defaultMarket, true)
|
||||
}
|
||||
/*
|
||||
For each dependency declared at the curatedDependencyNodeArray, we will initialize a
|
||||
|
||||
@@ -14,9 +14,9 @@ exports.newSuperalgosUtilitiesDateTimeFunctions = function () {
|
||||
}
|
||||
|
||||
function getPercentage(fromDate, currentDate, lastDate) {
|
||||
let fromDays = Math.trunc(fromDate.valueOf() / TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS)
|
||||
let currentDays = Math.trunc(currentDate.valueOf() / TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS)
|
||||
let lastDays = Math.trunc((lastDate.valueOf() - TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS) / TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS)
|
||||
let fromDays = fromDate.valueOf()
|
||||
let currentDays = currentDate.valueOf()
|
||||
let lastDays = lastDate.valueOf()
|
||||
let percentage = (currentDays - fromDays) * 100 / (lastDays - fromDays)
|
||||
if ((lastDays - fromDays) === 0) {
|
||||
percentage = 100
|
||||
|
||||
@@ -3,7 +3,8 @@ exports.newSuperalgosUtilitiesMiscellaneousFunctions = function () {
|
||||
let thisObject = {
|
||||
genereteUniqueId: genereteUniqueId,
|
||||
truncateToThisPrecision: truncateToThisPrecision,
|
||||
pad: pad
|
||||
pad: pad,
|
||||
asyncGetDatasetFile: asyncGetDatasetFile
|
||||
}
|
||||
|
||||
return thisObject
|
||||
@@ -23,4 +24,25 @@ exports.newSuperalgosUtilitiesMiscellaneousFunctions = function () {
|
||||
str = str.toString();
|
||||
return str.length < max ? pad("0" + str, max) : str;
|
||||
}
|
||||
|
||||
async function asyncGetDatasetFile(datasetModule, filePath, fileName) {
|
||||
/*
|
||||
This function helps a caller to use await syntax while the called
|
||||
function uses callbacks, specifically for retrieving files.
|
||||
*/
|
||||
let promise = new Promise((resolve, reject) => {
|
||||
|
||||
datasetModule.getTextFile(filePath, fileName, onFileReceived)
|
||||
function onFileReceived(err, text) {
|
||||
|
||||
let response = {
|
||||
err: err,
|
||||
text: text
|
||||
}
|
||||
resolve(response)
|
||||
}
|
||||
})
|
||||
|
||||
return promise
|
||||
}
|
||||
}
|
||||
@@ -111,13 +111,15 @@ function newSuperalgosFunctionLibraryChartingSpaceFunctions() {
|
||||
let fordwardTestingSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Forward Testing Session')
|
||||
let paperTradingSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Paper Trading Session')
|
||||
let liveTradingSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Live Trading Session')
|
||||
let learningSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Learning Session')
|
||||
let backLearningSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Back Learning Session')
|
||||
let liveLearningSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Live Learning Session')
|
||||
|
||||
scanSessionArray(backtestingSessionsArray)
|
||||
scanSessionArray(fordwardTestingSessionsArray)
|
||||
scanSessionArray(paperTradingSessionsArray)
|
||||
scanSessionArray(liveTradingSessionsArray)
|
||||
scanSessionArray(learningSessionsArray)
|
||||
scanSessionArray(backLearningSessionsArray)
|
||||
scanSessionArray(liveLearningSessionsArray)
|
||||
|
||||
function scanSessionArray(sessionsArray) {
|
||||
for (let i = 0; i < sessionsArray.length; i++) {
|
||||
|
||||
@@ -331,8 +331,11 @@ function newSuperalgosFunctionLibraryCryptoEcosystemFunctions() {
|
||||
UI.projects.superalgos.utilities.menu.menuClickOfNodeArray(marketLearningTask.learningMineTasks, 'Add All Tasks', true)
|
||||
|
||||
/* This will be needed at the charting space, for creating Dashboards */
|
||||
let learningSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(marketLearningTask, 'Learning Session')
|
||||
learningSessionsCreatedArray = learningSessionsCreatedArray.concat(learningSessionsArray)
|
||||
let backLearningSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(marketLearningTask, 'Back Learning Session')
|
||||
let liveLearningSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(marketLearningTask, 'Live Learning Session')
|
||||
learningSessionsCreatedArray = learningSessionsCreatedArray
|
||||
.concat(backLearningSessionsArray)
|
||||
.concat(liveLearningSessionsArray)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -133,9 +133,11 @@ function newSuperalgosFunctionLibraryDataStorageFunctions() {
|
||||
let networkNode = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(node, 'Network Node', undefined, true, false, true, false)
|
||||
if (networkNode === undefined) { return }
|
||||
|
||||
let learningSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Learning Session')
|
||||
let backLearningSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Back Learning Session')
|
||||
let liveLearningSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Live Learning Session')
|
||||
|
||||
addMissingSession(learningSessionsArray)
|
||||
addMissingSession(backLearningSessionsArray)
|
||||
addMissingSession(liveLearningSessionsArray)
|
||||
|
||||
function addMissingSession(sessionsArray) {
|
||||
for (let i = 0; i < sessionsArray.length; i++) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
function newSuperalgosFunctionLibraryLearningSessionFunctions() {
|
||||
thisObject = {
|
||||
syncronizeSessionWithBackEnd: syncronizeSessionWithBackEnd,
|
||||
syncronizeSessionWithBackEnd: syncronizeSessionWithBackEnd,
|
||||
runSession: runSession,
|
||||
stopSession: stopSession
|
||||
}
|
||||
@@ -8,7 +8,12 @@ function newSuperalgosFunctionLibraryLearningSessionFunctions() {
|
||||
return thisObject
|
||||
|
||||
function syncronizeSessionWithBackEnd(node) {
|
||||
let networkNode = validations(node)
|
||||
let validationsResult = validations(node)
|
||||
if (validationsResult === undefined) {
|
||||
/* If something fails at validations we just quit. */
|
||||
return
|
||||
}
|
||||
let networkNode = validationsResult.networkNode
|
||||
if (networkNode === undefined) {
|
||||
/* Nodes that do not belong to a network can not get ready. */
|
||||
return
|
||||
@@ -27,7 +32,7 @@ function newSuperalgosFunctionLibraryLearningSessionFunctions() {
|
||||
|
||||
function onStatus(message) {
|
||||
eventsServerClient.stopListening(key, eventSubscriptionIdOnStatus, node.id)
|
||||
if (message.event.status === 'Learning Session Runnning' ) {
|
||||
if (message.event.status === 'Learning Session Runnning') {
|
||||
node.payload.uiObject.menu.internalClick('Run Learning Session')
|
||||
}
|
||||
}
|
||||
@@ -37,7 +42,12 @@ function newSuperalgosFunctionLibraryLearningSessionFunctions() {
|
||||
}
|
||||
|
||||
function runSession(node, resume, callBackFunction) {
|
||||
let networkNode = validations(node)
|
||||
let validationsResult = validations(node)
|
||||
if (validationsResult === undefined) {
|
||||
/* If something fails at validations we just quit. */
|
||||
return
|
||||
}
|
||||
let networkNode = validationsResult.networkNode
|
||||
if (networkNode === undefined) {
|
||||
/* This means that the validations failed. */
|
||||
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
|
||||
@@ -51,15 +61,16 @@ function newSuperalgosFunctionLibraryLearningSessionFunctions() {
|
||||
let key = node.name + '-' + node.type + '-' + node.id
|
||||
|
||||
let lightingPath = '' +
|
||||
'Trading System->' +
|
||||
'Learning System->' +
|
||||
'Dynamic Indicators->Indicator Function->Formula->' +
|
||||
'Trading Strategy->' +
|
||||
'Learning Strategy->' +
|
||||
'Trigger Stage->Trigger On Event->Trigger Off Event->Take Position Event->' +
|
||||
'Announcement->Announcement Formula->' +
|
||||
'Open Stage->' +
|
||||
'Manage Stage->' +
|
||||
'Managed Stop Loss->Managed Take Profit->' +
|
||||
'Phase->Formula->Next Phase Event->Move To Phase Event->Phase->' +
|
||||
'Close Stage Event->' +
|
||||
'Situation->Condition->Javascript Code->' +
|
||||
'Close Stage->' +
|
||||
'Initial Targets->Target Size In Base Asset->Target Size In Quoted Asset->Target Rate->Formula->' +
|
||||
@@ -73,10 +84,10 @@ function newSuperalgosFunctionLibraryLearningSessionFunctions() {
|
||||
'Market Order->Limit Order->' +
|
||||
'Simulated Exchange Events->Simulated Partial Fill->Simulated Actual Rate->Simulated Fees Paid->Formula->'
|
||||
|
||||
let tradingSystem = UI.projects.superalgos.functionLibraries.protocolNode.getProtocolNode(node.tradingSystemReference.payload.referenceParent, false, true, true, false, false, lightingPath)
|
||||
let learningSystem = UI.projects.superalgos.functionLibraries.protocolNode.getProtocolNode(node.learningSystemReference.payload.referenceParent, false, true, true, false, false, lightingPath)
|
||||
|
||||
lightingPath = '' +
|
||||
'Trading Engine->' +
|
||||
'Learning Engine->' +
|
||||
'Dynamic Indicators->Indicator Function->' +
|
||||
'Current->Last->Previous->' +
|
||||
'Episode->' +
|
||||
@@ -111,10 +122,10 @@ function newSuperalgosFunctionLibraryLearningSessionFunctions() {
|
||||
'Balance->Begin Balance->End Balance->' +
|
||||
'Index->Situation Name->Formula->Periods->'
|
||||
|
||||
let tradingEngine = UI.projects.superalgos.functionLibraries.protocolNode.getProtocolNode(node.tradingEngineReference.payload.referenceParent, false, true, true, false, false, lightingPath)
|
||||
let learningEngine = UI.projects.superalgos.functionLibraries.protocolNode.getProtocolNode(node.learningEngineReference.payload.referenceParent, false, true, true, false, false, lightingPath)
|
||||
|
||||
lightingPath = '' +
|
||||
'Learning Session->' +
|
||||
'Back Learning Session->Live Learning Session->' +
|
||||
'Learning Parameters->' +
|
||||
'Session Base Asset->Session Quoted Asset->Time Range->Time Frame->Slippage->Fee Structure->Snapshots->Heartbeats->User Defined Parameters->' +
|
||||
'Exchange Account Asset->Asset->' +
|
||||
@@ -122,13 +133,23 @@ function newSuperalgosFunctionLibraryLearningSessionFunctions() {
|
||||
|
||||
let session = UI.projects.superalgos.functionLibraries.protocolNode.getProtocolNode(node, false, true, true, false, false, lightingPath)
|
||||
|
||||
let dependencyFilter = UI.projects.superalgos.functionLibraries.dependenciesFilter.createDependencyFilter(node.tradingSystemReference.payload.referenceParent)
|
||||
let defaultExchange = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(validationsResult.exchange.payload, 'codeName')
|
||||
let defaultMarket =
|
||||
UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(validationsResult.market.baseAsset.payload.referenceParent.payload, 'codeName')
|
||||
+ '-' +
|
||||
UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(validationsResult.market.quotedAsset.payload.referenceParent.payload, 'codeName')
|
||||
|
||||
let dependencyFilter = UI.projects.superalgos.functionLibraries.dependenciesFilter.createDependencyFilter(
|
||||
defaultExchange,
|
||||
defaultMarket,
|
||||
node.learningSystemReference.payload.referenceParent
|
||||
)
|
||||
|
||||
/* Raise event to run the session */
|
||||
let event = {
|
||||
session: JSON.stringify(session),
|
||||
tradingSystem: JSON.stringify(tradingSystem),
|
||||
tradingEngine: JSON.stringify(tradingEngine),
|
||||
learningSystem: JSON.stringify(learningSystem),
|
||||
learningEngine: JSON.stringify(learningEngine),
|
||||
dependencyFilter: JSON.stringify(dependencyFilter),
|
||||
resume: resume
|
||||
}
|
||||
@@ -146,13 +167,18 @@ function newSuperalgosFunctionLibraryLearningSessionFunctions() {
|
||||
}
|
||||
|
||||
function stopSession(node, callBackFunction) {
|
||||
let networkNode = validations(node)
|
||||
let validationsResult = validations(node)
|
||||
if (validationsResult === undefined) {
|
||||
/* If something fails at validations we just quit. */
|
||||
return
|
||||
}
|
||||
let networkNode = validationsResult.networkNode
|
||||
if (networkNode === undefined) {
|
||||
/* This means that the validations failed. */
|
||||
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let eventsServerClient = UI.projects.superalgos.spaces.designSpace.workspace.eventsServerClients.get(networkNode.id)
|
||||
|
||||
let key = node.name + '-' + node.type + '-' + node.id
|
||||
@@ -162,6 +188,9 @@ function newSuperalgosFunctionLibraryLearningSessionFunctions() {
|
||||
}
|
||||
|
||||
function validations(node) {
|
||||
|
||||
let result = {}
|
||||
|
||||
if (node.payload.parentNode === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Session needs a Process Instance parent to be able to run.')
|
||||
return
|
||||
@@ -182,54 +211,94 @@ function newSuperalgosFunctionLibraryLearningSessionFunctions() {
|
||||
return
|
||||
}
|
||||
|
||||
let taskManager = node.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode
|
||||
result.taskManager = node.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode
|
||||
|
||||
if (taskManager.payload.parentNode === undefined) {
|
||||
if (result.taskManager.payload.parentNode === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Session needs to be inside Mine Tasks.')
|
||||
return
|
||||
}
|
||||
|
||||
if (taskManager.payload.parentNode.payload.parentNode === undefined) {
|
||||
if (result.taskManager.payload.parentNode.payload.parentNode === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Session needs to be inside Market Tasks.')
|
||||
return
|
||||
}
|
||||
|
||||
if (taskManager.payload.parentNode.payload.parentNode.payload.parentNode === undefined) {
|
||||
if (result.taskManager.payload.parentNode.payload.parentNode.payload.parentNode === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Session needs to be inside Exchange Tasks.')
|
||||
return
|
||||
}
|
||||
|
||||
if (taskManager.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Session needs to be inside a Testing or Production Trading Tasks.')
|
||||
if (result.taskManager.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Session needs to be inside a Testing or Production Learning Tasks.')
|
||||
return
|
||||
}
|
||||
|
||||
if (taskManager.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode === undefined) {
|
||||
if (result.taskManager.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Session needs to be inside a Network Node.')
|
||||
return
|
||||
}
|
||||
|
||||
let networkNode = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(taskManager, 'Network Node', undefined, true, false, true, false)
|
||||
result.networkNode = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(result.taskManager, 'Network Node', undefined, true, false, true, false)
|
||||
|
||||
if (node.tradingSystemReference === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Session needs a child Trading System Reference.')
|
||||
if (node.learningSystemReference === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Session needs a child Learning System Reference.')
|
||||
return
|
||||
}
|
||||
|
||||
if (node.tradingEngineReference === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Session needs a child Trading Engine Reference.')
|
||||
if (node.learningEngineReference === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Session needs a child Learning Engine Reference.')
|
||||
return
|
||||
}
|
||||
|
||||
if (node.tradingSystemReference.payload.referenceParent === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Trading System Reference needs to reference a Trading System.')
|
||||
if (node.learningSystemReference.payload.referenceParent === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Learning System Reference needs to reference a Learning System.')
|
||||
return
|
||||
}
|
||||
|
||||
if (node.tradingEngineReference.payload.referenceParent === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Trading Engine Reference needs to reference a Trading Engine.')
|
||||
if (node.learningEngineReference.payload.referenceParent === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Learning Engine Reference needs to reference a Learning Engine.')
|
||||
return
|
||||
}
|
||||
return networkNode
|
||||
|
||||
if (result.taskManager.payload.parentNode.payload.parentNode.payload.referenceParent === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Session needs to have a Default Market.')
|
||||
return
|
||||
}
|
||||
|
||||
result.market = result.taskManager.payload.parentNode.payload.parentNode.payload.referenceParent
|
||||
|
||||
if (result.market.payload.parentNode === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Default Market needs to be a child of Exchange Markets.')
|
||||
return
|
||||
}
|
||||
|
||||
if (result.market.payload.parentNode.payload.parentNode === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Exchange Markets neeed to be a child of Crypto Exchange.')
|
||||
return
|
||||
}
|
||||
|
||||
if (result.market.baseAsset === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Default Market needs to have a Base Asset.')
|
||||
return
|
||||
}
|
||||
|
||||
if (result.market.quotedAsset === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Default Market needs to have a Quoted Asset.')
|
||||
return
|
||||
}
|
||||
|
||||
if (result.market.baseAsset.payload.referenceParent === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Market Base Asset needs to reference an Asset.')
|
||||
return
|
||||
}
|
||||
|
||||
if (result.market.quotedAsset.payload.referenceParent === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Market Quoted Asset needs to reference an Asset.')
|
||||
return
|
||||
}
|
||||
|
||||
result.exchange = result.market.payload.parentNode.payload.parentNode
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,7 @@ function newSuperalgosFunctionLibraryTaskFunctions() {
|
||||
'Market Base Asset->Market Quoted Asset->Asset->' +
|
||||
'Project Data Tasks->Project Trading Tasks->Project Learning Tasks->Project Definition->' +
|
||||
'Backtesting Session->Live Trading Session->Paper Trading Session->Forward Testing Session->' +
|
||||
'Learning Session->' +
|
||||
'Back Learning Session->Live Learning Session->' +
|
||||
'Process Definition->' +
|
||||
'Process Output->' +
|
||||
'Output Dataset Folder->Output Dataset Folder->Output Dataset Folder->Output Dataset Folder->Output Dataset Folder->' +
|
||||
@@ -171,7 +171,7 @@ function newSuperalgosFunctionLibraryTaskFunctions() {
|
||||
'Task Manager->Task->' +
|
||||
'Indicator Bot Instance->Sensor Bot Instance->Trading Bot Instance->Learning Bot Instance->' +
|
||||
'Indicator Process Instance->Sensor Process Instance->Trading Process Instance->Learning Process Instance->' +
|
||||
'Paper Trading Session->Forward Testing Session->Backtesting Session->Live Trading Session->Learning Session->' +
|
||||
'Paper Trading Session->Forward Testing Session->Backtesting Session->Live Trading Session->Back Learning Session->Live Learning Session->' +
|
||||
'Market->' +
|
||||
'Process Definition->'
|
||||
|
||||
@@ -719,23 +719,28 @@ function newSuperalgosFunctionLibraryTaskFunctions() {
|
||||
}
|
||||
|
||||
function addDataTasks() {
|
||||
addTaskForTradinSystem()
|
||||
addTasks()
|
||||
}
|
||||
|
||||
function addLearningTasks() {
|
||||
addTaskForTradinSystem()
|
||||
for (let i = 0; i < rootNodes.length; i++) {
|
||||
let rootNode = rootNodes[i]
|
||||
if (rootNode.type === 'Learning System') {
|
||||
addTasks(rootNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addTradingTasks() {
|
||||
for (let i = 0; i < rootNodes.length; i++) {
|
||||
let rootNode = rootNodes[i]
|
||||
if (rootNode.type === 'Trading System') {
|
||||
addTaskForTradinSystem(rootNode)
|
||||
addTasks(rootNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addTaskForTradinSystem(tradingSystem) {
|
||||
function addTasks(systemNode) {
|
||||
let mine = node.payload.referenceParent
|
||||
|
||||
addTasksForBotArray(mine.sensorBots)
|
||||
@@ -751,8 +756,8 @@ function newSuperalgosFunctionLibraryTaskFunctions() {
|
||||
|
||||
let task = UI.projects.superalgos.functionLibraries.uiObjectsFromNodes.addUIObject(taskManager, 'Task')
|
||||
|
||||
if (tradingSystem !== undefined) {
|
||||
task.name = tradingSystem.name
|
||||
if (systemNode !== undefined) {
|
||||
task.name = systemNode.name
|
||||
} else {
|
||||
task.name = bot.name
|
||||
}
|
||||
@@ -833,7 +838,7 @@ function newSuperalgosFunctionLibraryTaskFunctions() {
|
||||
if (rootNode.type === 'Trading Engine' && rootNode.isPlugin === true) {
|
||||
let tradingEngine = rootNode
|
||||
session.tradingEngineReference.payload.referenceParent = tradingEngine
|
||||
session.tradingSystemReference.payload.referenceParent = tradingSystem
|
||||
session.tradingSystemReference.payload.referenceParent = systemNode
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -842,9 +847,26 @@ function newSuperalgosFunctionLibraryTaskFunctions() {
|
||||
processInstance = UI.projects.superalgos.functionLibraries.uiObjectsFromNodes.addUIObject(botInstance, 'Learning Process Instance')
|
||||
processInstance.payload.referenceParent = process
|
||||
|
||||
if (node.payload.parentNode === undefined) { return }
|
||||
if (node.payload.parentNode.payload === undefined) { return }
|
||||
if (node.payload.parentNode.payload.parentNode === undefined) { return }
|
||||
if (node.payload.parentNode.payload.parentNode.payload === undefined) { return }
|
||||
if (node.payload.parentNode.payload.parentNode.payload.parentNode === undefined) { return }
|
||||
if (node.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode === undefined) { return }
|
||||
|
||||
let environment = node.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode
|
||||
let session
|
||||
|
||||
addSession('Learning Session')
|
||||
switch (environment.type) {
|
||||
case 'Testing Learning Tasks': {
|
||||
addSession('Backtesting Session')
|
||||
break
|
||||
}
|
||||
case 'Production Learning Tasks': {
|
||||
addSession('Live Learning Session')
|
||||
break
|
||||
}
|
||||
}
|
||||
break
|
||||
|
||||
function addSession(sessionType) {
|
||||
@@ -856,10 +878,10 @@ function newSuperalgosFunctionLibraryTaskFunctions() {
|
||||
|
||||
for (let m = 0; m < rootNodes.length; m++) {
|
||||
let rootNode = rootNodes[m]
|
||||
if (rootNode.type === 'Trading Engine' && rootNode.isPlugin === true) {
|
||||
let tradingEngine = rootNode
|
||||
session.tradingEngineReference.payload.referenceParent = tradingEngine
|
||||
session.tradingSystemReference.payload.referenceParent = tradingSystem
|
||||
if (rootNode.type === 'Learning Engine' && rootNode.isPlugin === true) {
|
||||
let learningEngine = rootNode
|
||||
session.learningEngineReference.payload.referenceParent = learningEngine
|
||||
session.learningSystemReference.payload.referenceParent = systemNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ function newSuperalgosDocsSearchEngine() {
|
||||
}
|
||||
|
||||
function setUpSearchEngine(callbackFunction) {
|
||||
callbackFunction()
|
||||
return
|
||||
|
||||
let totalAsyncCallsMade = 0
|
||||
let totalAsyncCallsFinished = 0
|
||||
|
||||
@@ -141,7 +141,7 @@ function newUiObjectMessage() {
|
||||
} else {
|
||||
backgroundColor = UI.projects.superalgos.spaces.floatingSpace.style.backgroundColor
|
||||
borderColor = color
|
||||
lineWidth = 0.5
|
||||
lineWidth = 0
|
||||
}
|
||||
|
||||
let params = {
|
||||
|
||||
@@ -169,7 +169,7 @@ function newLayer() {
|
||||
'Data Mines Data->Trading Mines Data->Learning Mines Data->Data Storage->Network Node->' +
|
||||
'Data Storage->Network Node->' +
|
||||
'Backtesting Session->Paper Trading Session->Forward Testing Session->Live Trading Session->' +
|
||||
'Learning Session->' +
|
||||
'Back Learning Session->Live Learning Session->' +
|
||||
'Trading System Reference->Trading Engine Reference->Trading System->Trading Engine->' +
|
||||
'Market->Market Base Asset->Asset->' +
|
||||
'Market Quoted Asset->Asset->' +
|
||||
|
||||
@@ -72,6 +72,8 @@ For example, if your Github username is John, the command will look like this:
|
||||
git clone https://github.com/John/Superalgos
|
||||
```
|
||||
|
||||
Ok, you have installed Superalgos. To run the App, jump to the section Usage below.
|
||||
|
||||
## Instalation Notes
|
||||
|
||||
**1.** You need to make a fork so that you may contribute work. Superalgos is a Community project and you are expected to contribute, like everyone else. You don't need to be a technical person to contribute. Fixing a typo in the docs or translating a paragraph into your native language are valuable contributions too. Superalgos has built-in features that make contributing easy. Help make Superalgos better and Superalgos will better serve you! [Free-riding is not cool](https://en.wikipedia.org/wiki/Free-rider_problem), particularly on free, open-source, Community-driven projects.
|
||||
|
||||
Reference in new issue
Block a user