From dc8ef4d0105df4e3f01f0fe5ce5cf14d7c961109 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 30 Nov 2020 16:00:04 +0100 Subject: [PATCH] Cleaning Learning --- TaskServer/LearningSession.js | 459 ------------- .../ReinforcementLearning/LearningBot.js | 633 +----------------- .../MarkovDecisionProcess.js | 198 +----- 3 files changed, 2 insertions(+), 1288 deletions(-) diff --git a/TaskServer/LearningSession.js b/TaskServer/LearningSession.js index ce4154f30..7ce970666 100644 --- a/TaskServer/LearningSession.js +++ b/TaskServer/LearningSession.js @@ -6,468 +6,9 @@ exports.newLearningSession = function (processIndex, bot, parentLogger) { initialize: initialize } - const SOCIAL_BOTS_MODULE = require('./SocialBots.js') - TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SOCIAL_BOTS_MODULE = SOCIAL_BOTS_MODULE.newSocialBots(bot, parentLogger) - return thisObject; function initialize(pProcessConfig, callBackFunction) { - try { - /* Check if there is a session */ - if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session === undefined) { - parentLogger.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. - */ - 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. */ - global.EVENT_SERVER_CLIENT_MODULE.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) - global.EVENT_SERVER_CLIENT_MODULE.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) - global.EVENT_SERVER_CLIENT_MODULE.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) - global.EVENT_SERVER_CLIENT_MODULE.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) - - /* Heartbeats sent to the UI */ - bot.sessionHeartBeat = sessionHeartBeat - - callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE) - return - - function onSessionStatus() { - if (bot.SESSION_STATUS === 'Running') { - let event = { - status: 'Learning Session Runnning' - } - global.EVENT_SERVER_CLIENT_MODULE.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' - } - global.EVENT_SERVER_CLIENT_MODULE.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 (bot.SESSION_STATUS === 'Idle' || bot.SESSION_STATUS === 'Running') { - parentLogger.write(MODULE_NAME, "[WARN] onSessionRun -> Event received to run the Session while it was already running. ") - return - } - - /* We are going to run the Definition comming at the event. */ - TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_SYSTEM_NODE = JSON.parse(message.event.tradingSystem) - TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_NODE = JSON.parse(message.event.tradingEngine) - bot.LEARNING_SESSION = 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 - bot.LEARNING_SESSION.stop = stopSession // stop function - - 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 (bot.LEARNING_SESSION.type) { - case 'Backtesting Session': { - allGood = startBackTesting(message) - break - } - case 'Live Trading Session': { - allGood = startLiveTrading(message) - break - } - case 'Fordward Testing Session': { - allGood = startFordwardTesting(message) - break - } - case 'Paper Trading Session': { - allGood = startPaperTrading(message) - break - } - } - if (allGood === true) { - bot.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 - parentLogger.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(bot.LEARNING_SESSION.type + " '" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.name + "' is starting.") - } catch (err) { - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onSessionRun -> err = " + err.stack); - } - } - - function onSessionStop() { - stopSession('Session Stopped From the User Interface.') - } - - function onSessionResume(message) { - try { - if (bot.LEARNING_SESSION.stop === undefined) { - parentLogger.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 (bot.SESSION_STATUS === 'Idle' || bot.SESSION_STATUS === 'Running') { - parentLogger.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(bot.LEARNING_SESSION.type + " '" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.name + "' is resuming.") - } catch (err) { - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onSessionResume -> err = " + err.stack); - } - } - - function stopSession(commandOrigin) { - - TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SOCIAL_BOTS_MODULE.sendMessage(bot.LEARNING_SESSION.type + " '" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].session.name + "' is stopping " + commandOrigin) - TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SOCIAL_BOTS_MODULE.finalize() - TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_STOPPING = true - parentLogger.write(MODULE_NAME, '[IMPORTANT] stopSession -> Stopping the Session now. ') - TS.projects.superalgos.functionLibraries.sessionFunctions.sessionInfo(processIndex, bot.LEARNING_SESSION, commandOrigin, parentLogger) - } - - 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 (bot.LEARNING_SESSION.config !== undefined) { - config = bot.LEARNING_SESSION.config - if (config.folderName === undefined) { - bot.LEARNING_SESSION.folderName = 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 { - bot.LEARNING_SESSION.folderName = 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 (bot.LEARNING_SESSION.learningParameters === undefined) { - let errorMessage = "Session Node with no Parameters." - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage) - TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, bot.LEARNING_SESSION, errorMessage, parentLogger) - return false - } - - /* Time Range */ - if (bot.LEARNING_SESSION.learningParameters.timeRange === undefined) { // if the Time Range is missing we create a default one. - bot.LEARNING_SESSION.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 (bot.LEARNING_SESSION.type === 'Backtesting Session') { - if (isNaN(new Date(bot.LEARNING_SESSION.learningParameters.timeRange.config.initialDatetime)).valueOf()) { - let errorMessage = "sessionParameters.timeRange.config.initialDatetime is not a valid date." - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage) - TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, bot.LEARNING_SESSION.learningParameters, errorMessage, parentLogger) - return false - } - } - if (isNaN(new Date(bot.LEARNING_SESSION.learningParameters.timeRange.config.finalDatetime)).valueOf()) { - let errorMessage = "sessionParameters.timeRange.config.initialDatetime is not a valid date." - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage) - TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, bot.LEARNING_SESSION.learningParameters, errorMessage, parentLogger) - 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 (bot.LEARNING_SESSION.type) { - case 'Backtesting Session': { - useDefaultDatetimes(aYearAgo, today) - break - } - case 'Live Trading Session': { - useDefaultDatetimes(today, aYearFromNow) - break - } - case 'Fordward Testing Session': { - useDefaultDatetimes(today, aYearFromNow) - break - } - case 'Paper Trading 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 (bot.LEARNING_SESSION.type === 'Backtesting Session') { - if (bot.LEARNING_SESSION.learningParameters.timeRange.config.initialDatetime === undefined) { - bot.LEARNING_SESSION.learningParameters.timeRange.config.initialDatetime = initialDefault - } else { - bot.LEARNING_SESSION.learningParameters.timeRange.config.initialDatetime = (new Date(bot.LEARNING_SESSION.learningParameters.timeRange.config.initialDatetime)).valueOf() - } - } else { - /* Non backtest session can start from the past only if explicitly configured that way */ - if (bot.LEARNING_SESSION.learningParameters.timeRange.config.initialDatetime === undefined || bot.LEARNING_SESSION.learningParameters.timeRange.config.allowStartingFromThePast !== true) { - bot.LEARNING_SESSION.learningParameters.timeRange.config.initialDatetime = initialDefault - } else { - bot.LEARNING_SESSION.learningParameters.timeRange.config.initialDatetime = (new Date(bot.LEARNING_SESSION.learningParameters.timeRange.config.initialDatetime)).valueOf() - } - } - - /* Final Datetime */ - if (bot.LEARNING_SESSION.learningParameters.timeRange.config.finalDatetime === undefined) { - bot.LEARNING_SESSION.learningParameters.timeRange.config.finalDatetime = finalDefault - } else { - bot.LEARNING_SESSION.learningParameters.timeRange.config.finalDatetime = (new Date(bot.LEARNING_SESSION.learningParameters.timeRange.config.finalDatetime)).valueOf() - } - } - - /* Time Frame */ - if (bot.LEARNING_SESSION.learningParameters.timeFrame === undefined) { - let errorMessage = "Session Parameters Node with no Time Frame." - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage) - TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, bot.LEARNING_SESSION.learningParameters, errorMessage, parentLogger) - return false - } - if (bot.LEARNING_SESSION.learningParameters.timeFrame.config.label === undefined) { - let errorMessage = "Session Parameters Node with no Time Frame Label configuration." - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage) - TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, bot.LEARNING_SESSION.learningParameters.timeFrame, errorMessage, parentLogger) - return false - } - bot.LEARNING_SESSION.learningParameters.timeFrame.config.value = getTimeFrameFromLabel(bot.LEARNING_SESSION.learningParameters.timeFrame.config.label) - if (bot.LEARNING_SESSION.learningParameters.timeFrame.config.value === undefined) { - let errorMessage = "Config error: label value not recognized. Try 01-min or 01-hs for example." - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage) - TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, bot.LEARNING_SESSION.learningParameters.timeFrame, errorMessage, parentLogger) - return false - } - - /* Session Base Asset */ - if (bot.LEARNING_SESSION.learningParameters.sessionBaseAsset === undefined) { - let errorMessage = "Session Parameters Node with no Session Base Asset." - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage) - TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, bot.LEARNING_SESSION.learningParameters, errorMessage, parentLogger) - return false - } - if (bot.LEARNING_SESSION.learningParameters.sessionBaseAsset.config.initialBalance === undefined) { - let errorMessage = "Session Parameters Session Base Asset with no initialBalance configuration." - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage) - TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, bot.LEARNING_SESSION.learningParameters.sessionBaseAsset, errorMessage, parentLogger) - return false - } - - /* Session Quoted Asset */ - if (bot.LEARNING_SESSION.learningParameters.sessionQuotedAsset === undefined) { - let errorMessage = "Session Parameters Node with no Session Quoted Asset." - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage) - TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, bot.LEARNING_SESSION.learningParameters, errorMessage, parentLogger) - return false - } - if (bot.LEARNING_SESSION.learningParameters.sessionQuotedAsset.config.initialBalance === undefined) { - let errorMessage = "Session Parameters Session Quoted Asset with no initialBalance configuration." - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage) - TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, bot.LEARNING_SESSION.learningParameters.sessionQuotedAsset, errorMessage, parentLogger) - return false - } - - /* Slippage */ - if (bot.LEARNING_SESSION.learningParameters.slippage === undefined) { // if the Slippage is missing we create a default one. - bot.LEARNING_SESSION.learningParameters.slippage = { - name: 'Missing Slippage', - type: 'Slippage', - config: { - marketOrderRate: 0, - stopLoss: 0, - takeProfit: 0 - } - } - } - if (bot.LEARNING_SESSION.learningParameters.slippage.config.marketOrderRate === undefined) { // if the marketOrderRate is missing we create a default one. - bot.LEARNING_SESSION.learningParameters.slippage.config.marketOrderRate = 0 - } - if (bot.LEARNING_SESSION.learningParameters.slippage.config.stopLoss === undefined) { // if the stopLoss is missing we create a default one. - bot.LEARNING_SESSION.learningParameters.slippage.config.stopLoss = 0 - } - if (bot.LEARNING_SESSION.learningParameters.slippage.config.takeProfit === undefined) { // if the takeProfit is missing we create a default one. - bot.LEARNING_SESSION.learningParameters.slippage.config.takeProfit = 0 - } - - /* Fee Structure */ - if (bot.LEARNING_SESSION.learningParameters.feeStructure === undefined) { // if the Fee Structure is missing we create a default one. - bot.LEARNING_SESSION.learningParameters.feeStructure = { - name: 'Missing Fee Structure', - type: 'Fee Structure', - config: { - maker: 0, - taker: 0 - } - } - } - if (bot.LEARNING_SESSION.learningParameters.feeStructure.config.maker === undefined) { // if the maker is missing we create a default one. - bot.LEARNING_SESSION.learningParameters.feeStructure.config.maker = 0 - } - if (bot.LEARNING_SESSION.learningParameters.feeStructure.config.taker === undefined) { // if the taker is missing we create a default one. - bot.LEARNING_SESSION.learningParameters.feeStructure.config.taker = 0 - } - - return true - } - - function startBackTesting(message) { - return true - } - - function checkKey() { - if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference === undefined) { - let errorMessage = "Key Reference not defined. Please check that and try again." - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkKey -> " + errorMessage) - TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, bot.LEARNING_SESSION, errorMessage, parentLogger) - return false - } - if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference.referenceParent === undefined) { - let errorMessage = "Key Reference not referencing an Exchange Account Key. Please check that and try again." - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkKey -> " + errorMessage) - TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, bot.LEARNING_SESSION, errorMessage, parentLogger) - return false - } - if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference.referenceParent.config.codeName === undefined) { - let errorMessage = "Key 'codeName' undefined. Paste there you key. Please check that and try again." - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkKey -> " + errorMessage) - TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, bot.LEARNING_SESSION, errorMessage, parentLogger) - return false - } - if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference.referenceParent.config.secret === undefined) { - let errorMessage = "Key 'secret' undefined. Paste there you key secret. Please check that and try again." - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkKey -> " + errorMessage) - TS.projects.superalgos.functionLibraries.sessionFunctions.sessionError(processIndex, bot.LEARNING_SESSION, errorMessage, parentLogger) - return false - } - return true - } - - function startLiveTrading() { - return checkKey() - } - - function startFordwardTesting() { - if (checkKey() === false) { return false } - - /* Reduce the balance */ - let balancePercentage = 1 // This is the default value - - if (bot.LEARNING_SESSION.config.balancePercentage !== undefined) { - balancePercentage = bot.LEARNING_SESSION.config.balancePercentage - } - - bot.LEARNING_SESSION.learningParameters.sessionBaseAsset.config.initialBalance = bot.LEARNING_SESSION.learningParameters.sessionBaseAsset.config.initialBalance * balancePercentage / 100 - bot.LEARNING_SESSION.learningParameters.sessionQuotedAsset.config.initialBalance = bot.LEARNING_SESSION.learningParameters.sessionQuotedAsset.config.initialBalance * balancePercentage / 100 - - bot.LEARNING_SESSION.learningParameters.sessionBaseAsset.config.minimumBalance = bot.LEARNING_SESSION.learningParameters.sessionBaseAsset.config.minimumBalance * balancePercentage / 100 - bot.LEARNING_SESSION.learningParameters.sessionQuotedAsset.config.minimumBalance = bot.LEARNING_SESSION.learningParameters.sessionQuotedAsset.config.minimumBalance * balancePercentage / 100 - - bot.LEARNING_SESSION.learningParameters.sessionBaseAsset.config.maximumBalance = bot.LEARNING_SESSION.learningParameters.sessionBaseAsset.config.maximumBalance * balancePercentage / 100 - bot.LEARNING_SESSION.learningParameters.sessionQuotedAsset.config.maximumBalance = bot.LEARNING_SESSION.learningParameters.sessionQuotedAsset.config.maximumBalance * balancePercentage / 100 - - pProcessConfig.normalWaitTime = bot.LEARNING_SESSION.learningParameters.timeFrame.config.value - - return true - } - - function startPaperTrading(message) { - return true - } - - 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 - } - } - } - - function sessionHeartBeat(processingDate, percentage, status) { - let event = { - seconds: (new Date()).getSeconds(), - processingDate: processingDate, - percentage: percentage, - status: status - } - global.EVENT_SERVER_CLIENT_MODULE.raiseEvent(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY, 'Heartbeat', event) - - if (TS.projects.superalgos.globals.taskVariables.IS_TASK_STOPPING === true) { - TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_STOPPING = true - parentLogger.write(MODULE_NAME, '[IMPORTANT] sessionHeartBeat -> Stopping the Session now. ') - } - } - - } catch (err) { - parentLogger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); - callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE); - } } }; diff --git a/TaskServer/ReinforcementLearning/LearningBot.js b/TaskServer/ReinforcementLearning/LearningBot.js index ac95ff13a..2e4c5789a 100644 --- a/TaskServer/ReinforcementLearning/LearningBot.js +++ b/TaskServer/ReinforcementLearning/LearningBot.js @@ -25,641 +25,10 @@ exports.newLearningBot = function (processIndex, bot, parentLogger) { return thisObject; function initialize(pProcessConfig, callBackFunction) { - /* This function is exactly the same in the 3 modules representing the 2 different bot types loops. */ - try { - processConfig = pProcessConfig; - if (bot.repo === undefined) { - /* The code of the bot is defined at the UI. No need to load a file with the code. */ - session.initialize(processConfig, callBackFunction) - } - - } catch (err) { - parentLogger.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; - if (FULL_LOG === true) { parentLogger.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 (logger !== undefined) { - logger.finalize() - } - logger = DEBUG_MODULE.newDebugLog(processIndex); - TS.projects.superalgos.globals.taskVariables.LOGGER_MAP.set(MODULE_NAME + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].id, logger) - logger.bot = bot; - logger.initialize(); - - TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).MAIN_LOOP_COUNTER++; - bot.loopStartTime = new Date().valueOf(); - - let nextWaitTime; - - /* We tell the UI that we are running. */ - TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, undefined, undefined, "Running...") - - /* We define here all the modules that the rest of the infraestructure, including the bots themselves can consume. */ - const UTILITIES = require(TS.projects.superalgos.globals.nodeJSConstants.REQUIRE_ROOT_DIR + 'CloudUtilities'); - const STATUS_REPORT = require(TS.projects.superalgos.globals.nodeJSConstants.REQUIRE_ROOT_DIR + 'StatusReport'); - const STATUS_DEPENDENCIES = require(TS.projects.superalgos.globals.nodeJSConstants.REQUIRE_ROOT_DIR + 'StatusDependencies'); - const DATA_DEPENDENCIES = require(TS.projects.superalgos.globals.nodeJSConstants.REQUIRE_ROOT_DIR + 'DataDependencies'); - const DATA_SET = require(TS.projects.superalgos.globals.nodeJSConstants.REQUIRE_ROOT_DIR + 'DataSet'); - const PROCESS_EXECUTION_EVENTS = require(TS.projects.superalgos.globals.nodeJSConstants.REQUIRE_ROOT_DIR + 'ProcessExecutionEvents'); - const PROCESS_OUTPUT = require(TS.projects.superalgos.globals.nodeJSConstants.REQUIRE_ROOT_DIR + 'ProcessOutput'); - - /* 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. */ - bot.processDatetime = 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 */ - logger.newMainLoop() - - /* Checking if we need to need to emit any event */ - if (bot.SESSION_STATUS === 'Idle' && TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_STOPPING === false) { - bot.SESSION_STATUS = 'Running' - } - - if (bot.SESSION_STATUS === 'Running' && TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_STOPPING === true) { - bot.SESSION_STATUS = 'Stopped' - } - - TS.projects.superalgos.functionLibraries.sessionFunctions.emitSessionStatus(bot.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) { - - if (FULL_LOG === true) { logger.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 = PROCESS_EXECUTION_EVENTS.newProcessExecutionEvents(processIndex, bot, logger) - processExecutionEvents.initialize(processConfig, onInizialized); - - function onInizialized(err) { - try { - switch (err.result) { - case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: { - logger.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. - logger.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. - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Operation Failed. Aborting the process."); - global.unexpectedError = err.message - processStopped() - return - } - default: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result); - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Unhandled err.result received. -> err = " + err.message); - global.unexpectedError = err.message - processStopped() - return - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> err = " + err.stack); - global.unexpectedError = err.message - processStopped() - return - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeProcessExecutionEvents -> err = " + err.stack); - global.unexpectedError = err.message - processStopped() - return - } - } - - function startProcessExecutionEvents() { - try { - processExecutionEvents.start(onStarted); - - function onStarted(err) { - try { - switch (err.result) { - case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: { - logger.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. - logger.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. - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessExecutionEvents -> onStarted -> Operation Failed. Aborting the process."); - global.unexpectedError = err.message - processStopped() - return - } - default: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessExecutionEvents -> onStarted -> Unhandled err.result received. -> err.result = " + err.result); - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessExecutionEvents -> onStarted -> Unhandled err.result received. -> err = " + err.message); - global.unexpectedError = err.message - processStopped() - return - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessExecutionEvents -> onStarted -> err = " + err.stack); - global.unexpectedError = err.message - processStopped() - return - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessExecutionEvents -> err = " + err.stack); - global.unexpectedError = err.message - processStopped() - return - } - } - - function initializeStatusDependencies() { - try { - statusDependencies = STATUS_DEPENDENCIES.newStatusDependencies(processIndex, bot, logger, STATUS_REPORT, UTILITIES, PROCESS_OUTPUT); - statusDependencies.initialize(onInizialized); - - function onInizialized(err) { - try { - switch (err.result) { - case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: { - logger.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. - logger.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. - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeStatusDependencies -> onInizialized -> Operation Failed. Aborting the process."); - global.unexpectedError = err.message - processStopped() - return - } - default: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeStatusDependencies -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result); - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeStatusDependencies -> onInizialized -> Unhandled err.result received. -> err = " + err.message); - global.unexpectedError = err.message - processStopped() - return - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeStatusDependencies -> onInizialized -> err = " + err.stack); - global.unexpectedError = err.message - processStopped() - return - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeStatusDependencies -> err = " + err.stack); - global.unexpectedError = err.message - processStopped() - return - } - } - - function initializeDataDependencies() { - try { - dataDependencies = DATA_DEPENDENCIES.newDataDependencies(processIndex, bot, logger, DATA_SET); - dataDependencies.initialize(onInizialized); - - function onInizialized(err) { - try { - switch (err.result) { - case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeDataDependencies -> onInizialized -> Execution finished well."); } - switch (processConfig.framework.name) { - case 'Low-Frequency-Trading-Process': { - processFramework = TRADING_PROCESS_MODULE.newMachineLearningProcess(bot, logger, UTILITIES); - intitializeProcessFramework(); - break; - } - default: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Process Framework not Supported."); - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Process Framework Name = " + processConfig.framework.name); - global.unexpectedError = err.message - processStopped() - 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. - logger.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. - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Operation Failed. Aborting the process."); - global.unexpectedError = err.message - processStopped() - return - } - default: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result); - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Unhandled err.result received. -> err = " + err.message); - global.unexpectedError = err.message - processStopped() - return - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> err = " + err.stack); - global.unexpectedError = err.message - processStopped() - return - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> err = " + err.stack); - global.unexpectedError = err.message - processStopped() - return - } - } - - function intitializeProcessFramework() { - try { - processFramework.initialize(processConfig, statusDependencies, dataDependencies, onInizialized); - - function onInizialized(err) { - try { - switch (err.result) { - case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: { - logger.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. - logger.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. - logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Operation Failed. Aborting the process."); - global.unexpectedError = err.message - processStopped() - return - } - case TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized > Unhandled custom response received. -> err = " + err.message); - global.unexpectedError = err.message - processStopped() - return - } - default: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result); - logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Unhandled err.result received. -> err = " + err.message); - global.unexpectedError = err.message - processStopped() - return - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> err = " + err.stack); - global.unexpectedError = err.message - processStopped() - return - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> err = " + err.stack); - global.unexpectedError = err.message - processStopped() - return - } - } - - function startProcessFramework() { - try { - processFramework.start(onFinished); - - function onFinished(err) { - try { - processFramework.finalize() - processFramework = undefined - dataDependencies.finalize() - dataDependencies = undefined - statusDependencies.finalize() - statusDependencies = undefined - - switch (err.result) { - case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: { - logger.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. - logger.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. - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Operation Failed. Aborting the process."); - global.unexpectedError = err.message - processStopped() - return - } - case TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result: { - - switch (err.message) { - case "Dependency does not exist.": { - logger.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.": { - logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> Dependency not ready. This Loop will go to sleep."); - nextWaitTime = 'Sleep'; - loopControl(nextWaitTime); - return; - } - default: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled custom response received. -> err = " + err.message); - global.unexpectedError = err.message - processStopped() - return - } - } - } - default: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled err.result received. -> err.result = " + err.result); - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled err.result received. -> err = " + err.message); - global.unexpectedError = err.message - processStopped() - return - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> err = " + err.stack); - global.unexpectedError = err.message - processStopped() - return - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> err = " + err.stack); - global.unexpectedError = err.message - processStopped() - 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: { - logger.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. - logger.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. - logger.write(MODULE_NAME, "[ERROR] run -> loop -> finishProcessExecutionEvents -> onFinished -> Operation Failed. Aborting the process."); - global.unexpectedError = err.message - processStopped() - return - } - default: { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> finishProcessExecutionEvents -> onFinished -> Unhandled err.result received. -> err.result = " + err.result); - logger.write(MODULE_NAME, "[ERROR] run -> loop -> finishProcessExecutionEvents -> onFinished -> Unhandled err.result received. -> err = " + err.message); - global.unexpectedError = err.message - processStopped() - return - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> finishProcessExecutionEvents -> onFinished -> err = " + err.stack); - global.unexpectedError = err.message - processStopped() - return - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> finishProcessExecutionEvents -> err = " + err.stack); - global.unexpectedError = err.message - processStopped() - return - } - } - - function loopControl(nextWaitTime) { - if (FULL_LOG === true) { logger.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() { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> onStop -> Stopping the Loop Gracefully. See you next time!"); } - logger.persist(); - - global.EVENT_SERVER_CLIENT_MODULE.raiseEvent(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY, 'Stopped') - processStopped() - 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 = processConfig.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. ") - logger.persist(); - } - break - case 'Normal': { - let waitTime - if (processConfig.waitsForExecutionFinishedEvent === true) { - waitTime = 0 - } else { - switch (bot.LEARNING_SESSION.type) { - case 'Live Trading Session': { - waitTime = bot.LEARNING_SESSION.learningParameters.timeFrame.config.value - break - } - case 'Fordward Tessting Session': { - waitTime = bot.LEARNING_SESSION.learningParameters.timeFrame.config.value - break - } - case 'Paper Trading Session': { - waitTime = bot.LEARNING_SESSION.learningParameters.timeFrame.config.value - break - } - case 'Backtesting Session': { - waitTime = 0 - break - } - } - } - - if (FULL_LOG === true) { logger.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.") - logger.persist(); - } - break; - case 'Retry': { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.retryWaitTime / 1000) + " seconds."); } - nextLoopTimeoutHandle = setTimeout(loop, processConfig.retryWaitTime); - TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, undefined, undefined, "Trying to recover from some problem. Waiting " + processConfig.retryWaitTime / 1000 + " seconds for next execution.") - logger.persist(); - } - break; - case 'Sleep': { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.sleepWaitTime / 60000) + " minutes."); } - nextLoopTimeoutHandle = setTimeout(loop, processConfig.sleepWaitTime); - TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, undefined, undefined, "Waiting " + processConfig.sleepWaitTime / 60000 + " minutes for next execution.") - logger.persist(); - } - break; - case 'Coma': { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.comaWaitTime / 3600000) + " hours."); } - nextLoopTimeoutHandle = setTimeout(loop, processConfig.comaWaitTime); - TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, undefined, undefined, "Waiting " + processConfig.comaWaitTime / 3600000 + " hours for next execution.") - logger.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) { - logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> err = " + err.stack); - global.unexpectedError = err.message - processStopped() - return - } - } - - } catch (err) { - parentLogger.write(MODULE_NAME, "[ERROR] run -> loop -> err = " + err.stack); - global.unexpectedError = err.message - processStopped() - return - } - } - - function processStopped() { - if (global.unexpectedError !== undefined) { - TS.projects.superalgos.functionLibraries.processFunctions.processError(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_KEY, undefined, "An unexpected error caused the Process to stop.") - } else { - global.EVENT_SERVER_CLIENT_MODULE.raiseEvent(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_KEY, 'Stopped') - } - sessionStopped() - logger.persist(); - clearTimeout(nextLoopTimeoutHandle); - if (global.unexpectedError !== undefined) { - callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE) - } else { - callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE) - } - } - - function sessionStopped() { - if (bot.SESSION_STATUS === 'Running') { - global.EVENT_SERVER_CLIENT_MODULE.raiseEvent(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_KEY, 'Stopped') - bot.SESSION_STATUS = 'Stopped' - } - } - - } catch (err) { - parentLogger.write(MODULE_NAME, "[ERROR] run -> err = " + err.stack); - clearTimeout(nextLoopTimeoutHandle); - callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE); - } } }; diff --git a/TaskServer/ReinforcementLearning/MarkovDecisionProcess.js b/TaskServer/ReinforcementLearning/MarkovDecisionProcess.js index 03b831ab0..9e2072835 100644 --- a/TaskServer/ReinforcementLearning/MarkovDecisionProcess.js +++ b/TaskServer/ReinforcementLearning/MarkovDecisionProcess.js @@ -1,218 +1,22 @@ exports.newMarkovDecisionProcess = function newMarkovDecisionProcess(bot, logger) { - /* - We call the Trading Engine to the data structure that is needed in order to exevute the - trading protocol with the specific rules defined at the Trading System. - */ + const MODULE_NAME = 'Markov Decision Process' let thisObject = { - mantain: mantain, - reset: reset, - getNodeById: getNodeById, - cloneValues: cloneValues, - setCurrentCandle: setCurrentCandle, - setCurrentCycle: setCurrentCycle, - initializeNode: initializeNode, initialize: initialize, finalize: finalize } - let tradingEngine - let sessionParameters - let nodesMap = new Map() - return thisObject function initialize() { - tradingEngine = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.tradingEngine - sessionParameters = bot.LEARNING_SESSION.learningParameters - initializeNodeMap(tradingEngine) - - 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 Trading Engine hiriarchy and - apply the initial value to the value property when needed - */ - initializeNode(tradingEngine) - } } function finalize() { - tradingEngine = undefined - sessionParameters = undefined - nodesMap = undefined - } - - function mantain() { - } - - function reset() { } - function getNodeById(NodeId) { - return nodesMap.get(NodeId) - } - function setCurrentCandle(candle) { - tradingEngine.current.episode.candle.begin.value = candle.begin - tradingEngine.current.episode.candle.end.value = candle.end - tradingEngine.current.episode.candle.open.value = candle.open - tradingEngine.current.episode.candle.close.value = candle.close - tradingEngine.current.episode.candle.min.value = candle.min - tradingEngine.current.episode.candle.max.value = candle.max - } - - function setCurrentCycle(cycle) { - tradingEngine.current.episode.cycle.value = cycle - tradingEngine.current.episode.cycle.lastBegin.value = tradingEngine.current.episode.cycle.begin.value - tradingEngine.current.episode.cycle.lastEnd.value = tradingEngine.current.episode.cycle.end.value - switch (cycle) { - case 'First': { - tradingEngine.current.episode.cycle.begin.value = - tradingEngine.current.episode.candle.begin.value + - sessionParameters.timeFrame.config.value - tradingEngine.current.episode.cycle.end.value = - tradingEngine.current.episode.candle.begin.value + - sessionParameters.timeFrame.config.value + - sessionParameters.timeFrame.config.value / 2 - 1 - break - } - case 'Second': { - tradingEngine.current.episode.cycle.begin.value = - tradingEngine.current.episode.candle.begin.value + - sessionParameters.timeFrame.config.value + - sessionParameters.timeFrame.config.value / 2 - tradingEngine.current.episode.cycle.end.value = - tradingEngine.current.episode.candle.begin.value + - sessionParameters.timeFrame.config.value + - sessionParameters.timeFrame.config.value * 4 / 4 - 1 - break - } - } - } - - 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 nodeDefinition = TS.projects.superalgos.globals.taskConstants.APP_SCHEMA_MAP.get(originNode.project + '-' + originNode.type) - if (nodeDefinition === undefined) { return } - - if (nodeDefinition.properties !== 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 < nodeDefinition.properties.length; i++) { - let property = nodeDefinition.properties[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 nodeDefinition = TS.projects.superalgos.globals.taskConstants.APP_SCHEMA_MAP.get(node.project + '-' + node.type) - if (nodeDefinition === undefined) { return } - - if (nodeDefinition.properties !== 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 < nodeDefinition.properties.length; i++) { - let property = nodeDefinition.properties[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 nodeDefinition = TS.projects.superalgos.globals.taskConstants.APP_SCHEMA_MAP.get(node.project + '-' + node.type) - if (nodeDefinition === undefined) { return } - - if (nodeDefinition.properties !== 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 < nodeDefinition.properties.length; i++) { - let property = nodeDefinition.properties[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 - } - } - } - } - } }