From b966f2e6a5199ba2a72759c5c5569dbc2ed565b6 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 29 Nov 2021 16:39:24 +0100 Subject: [PATCH] Integration of Trading Bot with Portfolio Manager Part 1 --- .../Low-Frequency-Trading/TradingStages.js | 38 +++++----- .../Low-Frequency-Trading/TradingSystem.js | 73 ++++++++++--------- .../TS/Modules/PortfolioManagerClient.js | 39 +++++++++- 3 files changed, 96 insertions(+), 54 deletions(-) diff --git a/Projects/Algorithmic-Trading/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingStages.js b/Projects/Algorithmic-Trading/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingStages.js index 3e2efe827..e29bc737a 100644 --- a/Projects/Algorithmic-Trading/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingStages.js +++ b/Projects/Algorithmic-Trading/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingStages.js @@ -99,13 +99,13 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) { tradingPositionModuleObject.cycleBasedStatistics() } - function runTriggerStage() { + async function runTriggerStage() { /* We check if we will be triggering on, off or taking position. */ - checkTriggerOn() - checkTriggerOff() - checkTakePosition() + await checkTriggerOn() + await checkTriggerOff() + await checkTakePosition() async function checkTriggerOn() { if ( @@ -224,7 +224,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) { let triggerStage = strategy.triggerStage tradingSystem.evalConditions(strategy, 'Take Position Event') - tradingSystem.evalFormulas(strategy, 'Take Position Event') + await tradingSystem.evalFormulas(strategy, 'Take Position Event') if (triggerStage !== undefined) { if (triggerStage.takePosition !== undefined) { @@ -276,7 +276,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) { async function runOpenStage() { checkIfWeNeedToAbortTheStage() - runWhenStatusIsOpening() + await runWhenStatusIsOpening() await runWhenStatusIsOpen() await runWhenStatusIsClosing() @@ -293,7 +293,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) { } } - function runWhenStatusIsOpening() { + async function runWhenStatusIsOpening() { /* Opening Status Procedure */ if (tradingEngine.tradingCurrent.strategyOpenStage.status.value === 'Opening') { /* @@ -315,7 +315,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) { TS.projects.foundations.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT.initializeNode(tradingEngine.exchangeOrders) /* Entry Position size and rate */ - tradingSystem.evalFormulas(tradingSystemStage, 'Initial Targets') + await tradingSystem.evalFormulas(tradingSystemStage, 'Initial Targets') tradingPositionModuleObject.initialTargets(tradingSystemStage, tradingEngineStage) initializeStageTargetSize() @@ -338,7 +338,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) { /* Evaluate conditions and formulas so they are ready during the execution run */ tradingSystem.evalConditions(executionNode, 'Open Execution') - tradingSystem.evalFormulas(executionNode, 'Open Execution') + await tradingSystem.evalFormulas(executionNode, 'Open Execution') await tradingExecutionModuleObject.runExecution( executionNode, @@ -368,7 +368,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) { and cancel the ones that were not. */ tradingSystem.evalConditions(tradingSystemStage, 'Open Execution') - tradingSystem.evalFormulas(tradingSystemStage, 'Open Execution') + await tradingSystem.evalFormulas(tradingSystemStage, 'Open Execution') await tradingExecutionModuleObject.runExecution( executionNode, @@ -424,12 +424,12 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) { } } - function runManageStage() { + async function runManageStage() { if (tradingEngine.tradingCurrent.tradingEpisode.cycle.value !== 'First') { return } runWhenStatusIsOpening() - runWhenStatusIsOpen() + await runWhenStatusIsOpen() function runWhenStatusIsOpening() { /* Opening Status Procedure */ @@ -455,7 +455,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) { } } - function runWhenStatusIsOpen() { + async function runWhenStatusIsOpen() { /* Open Status Procedure */ if (tradingEngine.tradingCurrent.strategyManageStage.status.value === 'Open') { checkUserDefinedCode('Manage Stage', 'Running', 'first'); @@ -464,7 +464,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) { /* Evaluate all the stage conditions and formulas to have them ready */ tradingSystem.evalConditions(manageStage, 'Manage Stage') - tradingSystem.evalFormulas(manageStage, 'Manage Stage') + await tradingSystem.evalFormulas(manageStage, 'Manage Stage') /* Stop Loss Management */ checkStopPhasesEvents() @@ -829,11 +829,11 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) { async function runCloseStage() { - runWhenStatusIsOpening() + await runWhenStatusIsOpening() await runWhenStatusIsOpen() await runWhenStatusIsClosing() - function runWhenStatusIsOpening() { + async function runWhenStatusIsOpening() { /* Opening Status Procedure */ if (tradingEngine.tradingCurrent.strategyCloseStage.status.value === 'Opening') { @@ -853,7 +853,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) { let tradingSystemStage = tradingSystem.tradingStrategies[tradingEngine.tradingCurrent.strategy.index.value].closeStage /* Exit Position size and rate */ - tradingSystem.evalFormulas(tradingSystemStage, 'Initial Targets') + await tradingSystem.evalFormulas(tradingSystemStage, 'Initial Targets') if (tradingPositionModuleObject.initialTargets(tradingSystemStage, tradingEngine.tradingCurrent.strategyCloseStage, 'Close Stage') === false) { //console.log("No Close-Stage Target Asset to Trade: Strategy Closing."); } @@ -885,7 +885,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) { let executionNode = tradingSystemStage.closeExecution tradingSystem.evalConditions(tradingSystemStage, 'Close Execution') - tradingSystem.evalFormulas(tradingSystemStage, 'Close Execution') + await tradingSystem.evalFormulas(tradingSystemStage, 'Close Execution') await tradingExecutionModuleObject.runExecution( executionNode, @@ -915,7 +915,7 @@ exports.newAlgorithmicTradingBotModulesTradingStages = function (processIndex) { and cancel the ones that were not. */ tradingSystem.evalConditions(tradingSystemStage, 'Close Execution') - tradingSystem.evalFormulas(tradingSystemStage, 'Close Execution') + await tradingSystem.evalFormulas(tradingSystemStage, 'Close Execution') await tradingExecutionModuleObject.runExecution( executionNode, diff --git a/Projects/Algorithmic-Trading/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingSystem.js b/Projects/Algorithmic-Trading/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingSystem.js index 606af9450..c48fc4e43 100644 --- a/Projects/Algorithmic-Trading/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingSystem.js +++ b/Projects/Algorithmic-Trading/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingSystem.js @@ -27,6 +27,7 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) { let dynamicIndicators let tradingStagesModuleObject = TS.projects.algorithmicTrading.botModules.tradingStages.newAlgorithmicTradingBotModulesTradingStages(processIndex) + let portfolioManagerClient = TS.projects.portfolioManagement.modules.portfolioManagerClient.newPortfolioManagementModulesPortfolioManagerClient(processIndex) let taskParameters = { market: TS.projects.foundations.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + @@ -70,12 +71,12 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) { evalNode(startingNode, 'Conditions', descendentOfNodeType) } - tradingSystem.evalFormulas = function (startingNode, descendentOfNodeType) { - evalNode(startingNode, 'Formulas', descendentOfNodeType) + tradingSystem.evalFormulas = async function (startingNode, descendentOfNodeType) { + await evalNode(startingNode, 'Formulas', descendentOfNodeType) } tradingSystem.evalUserCode = function (startingNode, descendentOfNodeType) { - evalNode(startingNode, 'User Codes', descendentOfNodeType); + evalNode(startingNode, 'User Codes', descendentOfNodeType); } tradingSystem.addError = function (errorDataArray) { @@ -203,13 +204,13 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) { buildDynamicIndicators() /* Run the Trigger Stage */ - tradingStagesModuleObject.runTriggerStage() + await tradingStagesModuleObject.runTriggerStage() /* Run the Open Stage */ await tradingStagesModuleObject.runOpenStage() /* Run the Manage Stage */ - tradingStagesModuleObject.runManageStage() + await tradingStagesModuleObject.runManageStage() /* Run the Close Stage */ await tradingStagesModuleObject.runCloseStage() @@ -234,7 +235,7 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) { } } - function evalNode(node, evaluating, descendentOfNodeType, isDescendent) { + async function evalNode(node, evaluating, descendentOfNodeType, isDescendent, parentNode) { if (node === undefined) { return } /* Verify if this node is descendent of the specified node type */ @@ -257,18 +258,18 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) { if (node.code !== undefined) { /* We will eval this formula */ if (isDescendent === true) { - evalFormula(node) + await evalFormula(node, parentNode) } } } /* Here we check if there is a User Defined-Javascript Code to be evaluated: */ if (node.type === 'Javascript Code' && evaluating === 'User Codes') { - if (node.code !== undefined) { - if (isDescendent === true) { - evalJSCode(node); + if (node.code !== undefined) { + if (isDescendent === true) { + evalJSCode(node); + } } - } } /* Now we go down through all this node children */ @@ -284,7 +285,7 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) { case 'node': { if (property.name !== previousPropertyName) { if (node[property.name] !== undefined) { - evalNode(node[property.name], evaluating, descendentOfNodeType, isDescendent) + await evalNode(node[property.name], evaluating, descendentOfNodeType, isDescendent, node) } previousPropertyName = property.name } @@ -294,7 +295,7 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) { if (node[property.name] !== undefined) { let nodePropertyArray = node[property.name] for (let m = 0; m < nodePropertyArray.length; m++) { - evalNode(nodePropertyArray[m], evaluating, descendentOfNodeType, isDescendent) + await evalNode(nodePropertyArray[m], evaluating, descendentOfNodeType, isDescendent, node) } } break @@ -357,7 +358,7 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) { TS.projects.foundations.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[INFO] evalCondition -> value = ' + value) } - function evalFormula(node) { + async function evalFormula(node, parentNode) { let value let errorMessage let docs @@ -365,6 +366,10 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) { try { TS.projects.foundations.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) + + let response = await portfolioManagerClient.askPortfolioFormulaManager(parentNode, value) + value = response.value + } catch (err) { /* One possible error is that the formula references a .previous that is undefined. This @@ -423,29 +428,29 @@ exports.newAlgorithmicTradingBotModulesTradingSystem = function (processIndex) { } function evalJSCode(node) { - let value - let errorMessage - let docs + let value + let errorMessage + let docs - try { - value = eval(node.code); + try { + value = eval(node.code); - } catch (err) { - value = 0 - errorMessage = err.message - docs = { - project: 'Foundations', - category: 'Topic', - type: 'TS LF Trading Bot Error - Evaluating User Code Error', - placeholder: {} + } catch (err) { + value = 0 + errorMessage = err.message + docs = { + project: 'Foundations', + category: 'Topic', + type: 'TS LF Trading Bot Error - Evaluating User Code Error', + placeholder: {} + } + TS.projects.education.utilities.docsFunctions.buildPlaceholder(docs, err, node.name, node.code, undefined) } - TS.projects.education.utilities.docsFunctions.buildPlaceholder(docs, err, node.name, node.code, undefined) - } - if (errorMessage !== undefined) { - tradingSystem.addError([node.id, errorMessage, docs]) - TS.projects.foundations.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[INFO] evalFormula -> errorMessage = ' + errorMessage) - return - } + if (errorMessage !== undefined) { + tradingSystem.addError([node.id, errorMessage, docs]) + TS.projects.foundations.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, '[INFO] evalFormula -> errorMessage = ' + errorMessage) + return + } } } \ No newline at end of file diff --git a/Projects/Portfolio-Management/TS/Modules/PortfolioManagerClient.js b/Projects/Portfolio-Management/TS/Modules/PortfolioManagerClient.js index 2adc51a68..af6ecf67c 100644 --- a/Projects/Portfolio-Management/TS/Modules/PortfolioManagerClient.js +++ b/Projects/Portfolio-Management/TS/Modules/PortfolioManagerClient.js @@ -58,7 +58,44 @@ exports.newPortfolioManagementModulesPortfolioManagerClient = function (processI return response } - async function askPortfolioFormulaManager() { + async function askPortfolioFormulaManager(formulaParentNode, formulaValue) { + let reponse = { + value: formulaValue, + reason: "No need to ask Portfolio Manager" + } + if (formulaParentNode === undefined) { + return reponse + } + if (formulaParentNode.askPortfolioFormulaManager === undefined) { + return reponse + } + + if (formulaValue === true) { + /* + First we will check if the Portfolio Manager confirms this formula + value. + */ + if (formulaParentNode.askPortfolioEventsManager.confirmFormula !== undefined) { + let message = { + question: "Confirm This Formula Value", + formula: formulaParentNode.type + } + reponse = await portfolioManagerEventsClient.sendMessage(message) + } + } else { + /* + In this case, we will check if the Porfolio Manager would like to + replace this formula value for something else. + */ + if (formulaParentNode.askPortfolioEventsManager.raiseEvent !== undefined) { + let message = { + question: "Give me a Value for this Formula", + formula: formulaParentNode.type + } + reponse = await portfolioManagerEventsClient.sendMessage(message) + } + } + return response } } \ No newline at end of file