Files
Superalgos/Projects/Foundations/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingPosition.js
T

534 lines
28 KiB
JavaScript

exports.newFoundationsBotModulesTradingPosition = function (processIndex) {
/*
This module packages all functions related to Positions.
*/
const MODULE_NAME = 'Trading Position'
let thisObject = {
mantain: mantain,
reset: reset,
cycleBasedStatistics: cycleBasedStatistics,
openPosition: openPosition,
closingPosition: closingPosition,
closePosition: closePosition,
applyStopLossFormula: applyStopLossFormula,
applyTakeProfitFormula: applyTakeProfitFormula,
updateStopLoss: updateStopLoss,
updateTakeProfit: updateTakeProfit,
initialTargets: initialTargets,
updateEnds: updateEnds,
resetTradingEngineDataStructure: resetTradingEngineDataStructure,
updateCounters: updateCounters,
initialize: initialize,
finalize: finalize
}
let tradingEngine
let tradingSystem
let sessionParameters
return thisObject
function initialize() {
tradingSystem = TS.projects.foundations.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.tradingSystem
tradingEngine = TS.projects.foundations.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.tradingEngine
sessionParameters = TS.projects.foundations.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters
}
function finalize() {
tradingEngine = undefined
tradingSystem = undefined
sessionParameters = undefined
}
function mantain() {
updateCounters()
updateEnds()
}
function reset() {
resetTradingEngineDataStructure()
}
function openPosition(situationName) {
/* Starting begin and end */
tradingEngine.tradingCurrent.position.begin.value = tradingEngine.tradingCurrent.tradingEpisode.cycle.lastBegin.value
tradingEngine.tradingCurrent.position.end.value = tradingEngine.tradingCurrent.tradingEpisode.cycle.lastEnd.value
/* Recording the opening at the Trading Engine Data Structure */
tradingEngine.tradingCurrent.position.status.value = 'Open'
tradingEngine.tradingCurrent.position.serialNumber.value = tradingEngine.tradingCurrent.tradingEpisode.tradingEpisodeCounters.positions.value + 1
tradingEngine.tradingCurrent.position.identifier.value = SA.projects.foundations.utilities.miscellaneousFunctions.genereteUniqueId()
tradingEngine.tradingCurrent.position.beginRate.value = tradingEngine.tradingCurrent.tradingEpisode.candle.close.value
tradingEngine.tradingCurrent.position.positionBaseAsset.beginBalance.value = tradingEngine.tradingCurrent.tradingEpisode.episodeBaseAsset.balance.value
tradingEngine.tradingCurrent.position.positionQuotedAsset.beginBalance.value = tradingEngine.tradingCurrent.tradingEpisode.episodeQuotedAsset.balance.value
tradingEngine.tradingCurrent.position.situationName.value = situationName
/* Initializing Stop and Take Phase */
tradingEngine.tradingCurrent.position.stopLoss.stopLossPhase.value = 1
tradingEngine.tradingCurrent.position.takeProfit.takeProfitPhase.value = 1
/* Updating Episode Counters */
tradingEngine.tradingCurrent.tradingEpisode.tradingEpisodeCounters.positions.value++
/* Inicializing this counter */
tradingEngine.tradingCurrent.tradingEpisode.distanceToTradingEvent.takePosition.value = 1
/* Remember the balance we had before taking the position to later calculate profit or loss */
tradingEngine.tradingCurrent.position.positionBaseAsset.beginBalance = tradingEngine.tradingCurrent.tradingEpisode.episodeBaseAsset.balance.value
tradingEngine.tradingCurrent.position.positionQuotedAsset.beginBalance = tradingEngine.tradingCurrent.tradingEpisode.episodeQuotedAsset.balance.value
}
function closingPosition(exitType) {
tradingEngine.tradingCurrent.position.status.value = 'Closing'
tradingEngine.tradingCurrent.position.exitType.value = exitType
/*
By the time we figured out that the stop loss or take profit were hit, or
for whatever reason the position needs to be closed, the take profit and
stop loss values for the next candle have already been calculated. In order
to avoid being plotted, we will put them in zero.
*/
tradingEngine.tradingCurrent.position.stopLoss.value = 0
tradingEngine.tradingCurrent.position.takeProfit.value = 0
}
function closePosition() {
tradingEngine.tradingCurrent.position.status.value = 'Closed'
tradingEngine.tradingCurrent.position.end.value = tradingEngine.tradingCurrent.tradingEpisode.cycle.lastEnd.value
tradingEngine.tradingCurrent.position.endRate.value = tradingEngine.tradingCurrent.tradingEpisode.candle.close.value
tradingEngine.tradingCurrent.position.positionBaseAsset.endBalance.value = tradingEngine.tradingCurrent.tradingEpisode.episodeBaseAsset.balance.value
tradingEngine.tradingCurrent.position.positionQuotedAsset.endBalance.value = tradingEngine.tradingCurrent.tradingEpisode.episodeQuotedAsset.balance.value
/*
Now that the position is closed, it is the right time to move this position from current to last at the Trading Engine data structure.
*/
TS.projects.foundations.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT.cloneValues(tradingEngine.tradingCurrent.position, tradingEngine.tradingLast.position)
cycleBasedStatistics()
/* Updating Hits & Fails */
if (tradingEngine.tradingCurrent.position.positionBaseAsset.profitLoss.value > 0) {
tradingEngine.tradingCurrent.tradingEpisode.episodeBaseAsset.hits.value++
}
if (tradingEngine.tradingCurrent.position.positionBaseAsset.profitLoss.value < 0) {
tradingEngine.tradingCurrent.tradingEpisode.episodeBaseAsset.fails.value++
}
if (tradingEngine.tradingCurrent.position.positionQuotedAsset.profitLoss.value > 0) {
tradingEngine.tradingCurrent.tradingEpisode.episodeQuotedAsset.hits.value++
}
if (tradingEngine.tradingCurrent.position.positionQuotedAsset.profitLoss.value < 0) {
tradingEngine.tradingCurrent.tradingEpisode.episodeQuotedAsset.fails.value++
}
}
function applyStopLossFormula(formulas, formulaId) {
updateStopLossTakeProfitFinalValue(tradingEngine.tradingCurrent.position.stopLoss)
tradingEngine.tradingCurrent.position.stopLoss.value = formulas.get(formulaId)
updateStopLossTakeProfitInitialValue(tradingEngine.tradingCurrent.position.stopLoss)
updateStopLossTakeProfitBeginEnd(tradingEngine.tradingCurrent.position.stopLoss)
}
function applyTakeProfitFormula(formulas, formulaId) {
updateStopLossTakeProfitFinalValue(tradingEngine.tradingCurrent.position.takeProfit)
tradingEngine.tradingCurrent.position.takeProfit.value = formulas.get(formulaId)
updateStopLossTakeProfitInitialValue(tradingEngine.tradingCurrent.position.takeProfit)
updateStopLossTakeProfitBeginEnd(tradingEngine.tradingCurrent.position.takeProfit)
}
function updateStopLossTakeProfitInitialValue(node) {
/*
We store the first Stop Loss or Take Profit value in a separate node.
To know if it is the first one we compare its current value to the initial value.
*/
if (node.initialValue.value === node.initialValue.config.initialValue) {
node.initialValue.value = node.value
}
}
function updateStopLossTakeProfitFinalValue(node) {
/*
We set the final value just before calculating the new value, since the new calculated
value is going to be discarded if the position is closed after it is calculated, but
during the same candle.
*/
node.finalValue.value = node.value
}
function updateStopLossTakeProfitBeginEnd(node) {
/*
Both the Stop Loss and the Take Profit have their own Begin and End.
The reason for this is because they represent targets to be checked
at the next candle, so it does not apply that they share the begin and
end of the position itself.
*/
node.begin.value =
tradingEngine.tradingCurrent.tradingEpisode.candle.begin.value +
sessionParameters.timeFrame.config.value
node.end.value =
tradingEngine.tradingCurrent.tradingEpisode.candle.end.value +
sessionParameters.timeFrame.config.value
}
function updateStopLoss(phase) {
tradingEngine.tradingCurrent.position.stopLoss.stopLossPhase.value = phase
}
function updateTakeProfit(phase) {
tradingEngine.tradingCurrent.position.takeProfit.takeProfitPhase.value = phase
}
function initialTargets(tradingSystemStageNode, tradingEngineStageNode, stageName) {
if (tradingSystemStageNode.initialTargets === undefined) {
const message = 'Initial Targets Node Missing'
let docs = {
project: 'Foundations',
category: 'Topic',
type: 'TS LF Trading Bot Error - ' + message,
placeholder: {}
}
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode, docs)
}
setTargetRate()
return setTargetSize(stageName)
function setTargetRate() {
if (tradingSystemStageNode.initialTargets.targetRate === undefined) {
const message = 'Target Rate Node Missing'
let docs = {
project: 'Foundations',
category: 'Topic',
type: 'TS LF Trading Bot Error - ' + message,
placeholder: {}
}
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets, docs)
}
if (tradingSystemStageNode.initialTargets.targetRate.formula === undefined) {
const message = 'Formula Node Missing'
let docs = {
project: 'Foundations',
category: 'Topic',
type: 'TS LF Trading Bot Error - ' + message,
placeholder: {}
}
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetRate, docs)
}
let value = tradingSystem.formulas.get(tradingSystemStageNode.initialTargets.targetRate.formula.id)
if (value === undefined) {
const message = 'Target Rate Node Value Undefined'
let docs = {
project: 'Foundations',
category: 'Topic',
type: 'TS LF Trading Bot Error - ' + message,
placeholder: {}
}
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetRate, docs)
}
if (isNaN(value)) {
const message = 'Target Rate Node Value Not A Number'
let docs = {
project: 'Foundations',
category: 'Topic',
type: 'TS LF Trading Bot Error - ' + message,
placeholder: {}
}
TS.projects.education.utilities.docsFunctions.buildPlaceholder(docs, undefined, undefined, undefined, undefined, value, undefined)
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetRate, docs)
}
switch (tradingSystemStageNode.type) {
case 'Open Stage': {
tradingEngine.tradingCurrent.position.entryTargetRate.value = TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(value, 10)
break
}
case 'Close Stage': {
tradingEngine.tradingCurrent.position.exitTargetRate.value = TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(value, 10)
break
}
}
}
function setTargetSize(stageName) {
/* Basic Validation */
if (
tradingSystemStageNode.initialTargets.targetSizeInBaseAsset !== undefined &&
tradingSystemStageNode.initialTargets.targetSizeInQuotedAsset !== undefined
) {
// 'Only Target Size In Base Asset or Target Size In Quoted Asset is allowed.'
const message = 'Only One Target Size Allowed'
let docs = {
project: 'Foundations',
category: 'Topic',
type: 'TS LF Trading Bot Error - ' + message,
placeholder: {}
}
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets, docs)
}
/* Position In Base Asset */
if (tradingSystemStageNode.initialTargets.targetSizeInBaseAsset !== undefined) {
if (tradingSystemStageNode.initialTargets.targetSizeInBaseAsset.formula !== undefined) {
let value = tradingSystem.formulas.get(tradingSystemStageNode.initialTargets.targetSizeInBaseAsset.formula.id)
if (value === undefined) {
const message = 'Target Size Value Undefined'
let docs = {
project: 'Foundations',
category: 'Topic',
type: 'TS LF Trading Bot Error - ' + message,
placeholder: {}
}
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetSizeInBaseAsset, docs)
}
if (value === 0) {
if (stageName === 'Close Stage') {
return false;
}
const message = 'Target Size Value Zero'
let docs = {
project: 'Foundations',
category: 'Topic',
type: 'TS LF Trading Bot Error - ' + message,
placeholder: {}
}
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetSizeInBaseAsset, docs)
}
switch (tradingSystemStageNode.type) {
case 'Open Stage': {
tradingEngine.tradingCurrent.position.positionBaseAsset.entryTargetSize.value = TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(value, 10)
tradingEngine.tradingCurrent.position.positionQuotedAsset.entryTargetSize.value =
TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(value * tradingEngine.tradingCurrent.position.entryTargetRate.value, 10)
break
}
case 'Close Stage': {
tradingEngine.tradingCurrent.position.positionBaseAsset.exitTargetSize.value = TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(value, 10)
tradingEngine.tradingCurrent.position.positionQuotedAsset.exitTargetSize.value =
TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(value * tradingEngine.tradingCurrent.position.exitTargetRate.value, 10)
break
}
}
/* Remember how the end user defined this stage. */
tradingEngineStageNode.stageDefinedIn.value = 'Base Asset'
} else {
const message = 'Formula Node Missing'
let docs = {
project: 'Foundations',
category: 'Topic',
type: 'TS LF Trading Bot Error - ' + message,
placeholder: {}
}
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetSizeInBaseAsset, docs)
}
}
/* Position In Quoted Asset */
if (tradingSystemStageNode.initialTargets.targetSizeInQuotedAsset !== undefined) {
if (tradingSystemStageNode.initialTargets.targetSizeInQuotedAsset.formula !== undefined) {
let value = tradingSystem.formulas.get(tradingSystemStageNode.initialTargets.targetSizeInQuotedAsset.formula.id)
if (value === undefined) {
const message = 'Target Size Value Undefined'
let docs = {
project: 'Foundations',
category: 'Topic',
type: 'TS LF Trading Bot Error - ' + message,
placeholder: {}
}
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetSizeInQuotedAsset, docs)
}
if (value === 0) {
const message = 'Target Size Value Zero'
let docs = {
project: 'Foundations',
category: 'Topic',
type: 'TS LF Trading Bot Error - ' + message,
placeholder: {}
}
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetSizeInQuotedAsset, docs)
}
switch (tradingSystemStageNode.type) {
case 'Open Stage': {
tradingEngine.tradingCurrent.position.positionQuotedAsset.entryTargetSize.value = TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(value, 10)
tradingEngine.tradingCurrent.position.positionBaseAsset.entryTargetSize.value =
TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(value / tradingEngine.tradingCurrent.position.entryTargetRate.value, 10)
break
}
case 'Close Stage': {
tradingEngine.tradingCurrent.position.positionQuotedAsset.exitTargetSize.value = TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(value, 10)
tradingEngine.tradingCurrent.position.positionBaseAsset.exitTargetSize.value =
TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(value / tradingEngine.tradingCurrent.position.exitTargetRate.value, 10)
break
}
}
/* Remember how the end user defined this stage. */
tradingEngineStageNode.stageDefinedIn.value = 'Quoted Asset'
} else {
const message = 'Formula Node Missing'
let docs = {
project: 'Foundations',
category: 'Topic',
type: 'TS LF Trading Bot Error - ' + message,
placeholder: {}
}
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetSizeInQuotedAsset, docs)
}
}
}
}
function updateEnds() {
if (tradingEngine.tradingCurrent.position.status.value === 'Open') {
tradingEngine.tradingCurrent.position.end.value = tradingEngine.tradingCurrent.position.end.value + sessionParameters.timeFrame.config.value
tradingEngine.tradingCurrent.position.endRate.value = tradingEngine.tradingCurrent.tradingEpisode.candle.close.value
tradingEngine.tradingCurrent.position.positionBaseAsset.endBalance.value = tradingEngine.tradingCurrent.tradingEpisode.episodeBaseAsset.balance.value
tradingEngine.tradingCurrent.position.positionQuotedAsset.endBalance.value = tradingEngine.tradingCurrent.tradingEpisode.episodeQuotedAsset.balance.value
}
}
function resetTradingEngineDataStructure() {
if (tradingEngine.tradingCurrent.position.status.value === 'Closed') {
TS.projects.foundations.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT.initializeNode(tradingEngine.tradingCurrent.position)
}
}
function updateCounters() {
if (tradingEngine.tradingCurrent.position.status.value === 'Open') {
tradingEngine.tradingCurrent.position.positionCounters.periods.value++
}
}
function cycleBasedStatistics() {
calculateAssetsStatistics()
calculatePositionStatistics()
function calculateAssetsStatistics() {
/* Profit Loss Calculation */
tradingEngine.tradingCurrent.position.positionBaseAsset.profitLoss.value =
tradingEngine.tradingCurrent.tradingEpisode.episodeBaseAsset.balance.value -
tradingEngine.tradingCurrent.position.positionBaseAsset.beginBalance
tradingEngine.tradingCurrent.position.positionQuotedAsset.profitLoss.value =
tradingEngine.tradingCurrent.tradingEpisode.episodeQuotedAsset.balance.value -
tradingEngine.tradingCurrent.position.positionQuotedAsset.beginBalance
tradingEngine.tradingCurrent.position.positionBaseAsset.profitLoss.value = TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(tradingEngine.tradingCurrent.position.positionBaseAsset.profitLoss.value, 10)
tradingEngine.tradingCurrent.position.positionQuotedAsset.profitLoss.value = TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(tradingEngine.tradingCurrent.position.positionQuotedAsset.profitLoss.value, 10)
/* ROI Calculation */
tradingEngine.tradingCurrent.position.positionBaseAsset.ROI.value =
tradingEngine.tradingCurrent.position.positionBaseAsset.profitLoss.value * 100 /
tradingEngine.tradingCurrent.strategyOpenStage.stageBaseAsset.targetSize.value
tradingEngine.tradingCurrent.position.positionQuotedAsset.ROI.value =
tradingEngine.tradingCurrent.position.positionQuotedAsset.profitLoss.value * 100 /
tradingEngine.tradingCurrent.strategyOpenStage.stageQuotedAsset.targetSize.value
tradingEngine.tradingCurrent.position.positionBaseAsset.ROI.value = TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(tradingEngine.tradingCurrent.position.positionBaseAsset.ROI.value, 10)
tradingEngine.tradingCurrent.position.positionQuotedAsset.ROI.value = TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(tradingEngine.tradingCurrent.position.positionQuotedAsset.ROI.value, 10)
/* Hit Fail Calculation */
if (tradingEngine.tradingCurrent.position.positionBaseAsset.ROI.value > 0) {
tradingEngine.tradingCurrent.position.positionBaseAsset.hitFail.value = 'Hit'
}
if (tradingEngine.tradingCurrent.position.positionBaseAsset.ROI.value < 0) {
tradingEngine.tradingCurrent.position.positionBaseAsset.hitFail.value = 'Fail'
}
if (tradingEngine.tradingCurrent.position.positionBaseAsset.ROI.value === 0) {
tradingEngine.tradingCurrent.position.positionBaseAsset.hitFail.value = 'Even'
}
if (tradingEngine.tradingCurrent.position.positionQuotedAsset.ROI.value > 0) {
tradingEngine.tradingCurrent.position.positionQuotedAsset.hitFail.value = 'Hit'
}
if (tradingEngine.tradingCurrent.position.positionQuotedAsset.ROI.value < 0) {
tradingEngine.tradingCurrent.position.positionQuotedAsset.hitFail.value = 'Fail'
}
if (tradingEngine.tradingCurrent.position.positionQuotedAsset.ROI.value === 0) {
tradingEngine.tradingCurrent.position.positionQuotedAsset.hitFail.value = 'Even'
}
}
function calculatePositionStatistics() {
/* Profit Loss Calculation */
tradingEngine.tradingCurrent.position.positionStatistics.profitLoss.value =
(
tradingEngine.tradingCurrent.tradingEpisode.episodeBaseAsset.profitLoss.value * tradingEngine.tradingCurrent.position.endRate.value +
tradingEngine.tradingCurrent.tradingEpisode.episodeQuotedAsset.profitLoss.value
)
tradingEngine.tradingCurrent.position.positionStatistics.profitLoss.value = TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(tradingEngine.tradingCurrent.position.positionStatistics.profitLoss.value, 10)
/* ROI Calculation */
tradingEngine.tradingCurrent.position.positionStatistics.ROI.value =
(
tradingEngine.tradingCurrent.position.positionStatistics.profitLoss.value
)
* 100 /
(
tradingEngine.tradingCurrent.position.positionBaseAsset.beginBalance * tradingEngine.tradingCurrent.position.beginRate.value +
tradingEngine.tradingCurrent.position.positionQuotedAsset.beginBalance
)
tradingEngine.tradingCurrent.position.positionStatistics.ROI.value = TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(tradingEngine.tradingCurrent.position.positionStatistics.ROI.value, 10)
/* Hit Fail Calculation */
if (tradingEngine.tradingCurrent.position.positionStatistics.ROI.value > 0) {
tradingEngine.tradingCurrent.position.positionStatistics.hitFail.value = 'Hit'
}
if (tradingEngine.tradingCurrent.position.positionStatistics.ROI.value < 0) {
tradingEngine.tradingCurrent.position.positionStatistics.hitFail.value = 'Fail'
}
if (tradingEngine.tradingCurrent.position.positionStatistics.ROI.value === 0) {
tradingEngine.tradingCurrent.position.positionStatistics.hitFail.value = 'Even'
}
/* Days Calculation */
tradingEngine.tradingCurrent.position.positionStatistics.days.value =
tradingEngine.tradingCurrent.position.positionCounters.periods.value *
sessionParameters.timeFrame.config.value / SA.projects.foundations.globals.timeConstants.ONE_DAY_IN_MILISECONDS
tradingEngine.tradingCurrent.position.positionStatistics.days.value = TS.projects.foundations.utilities.miscellaneousFunctions.truncateToThisPrecision(tradingEngine.tradingCurrent.position.positionStatistics.days.value, 10)
}
}
function badDefinitionUnhandledException(err, message, node, docs) {
tradingSystem.addError([node.id, message, docs])
TS.projects.foundations.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] -> " + message);
TS.projects.foundations.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] -> node.name = " + node.name);
TS.projects.foundations.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] -> node.type = " + node.type);
TS.projects.foundations.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] -> node.config = " + JSON.stringify(node.config));
if (err !== undefined) {
TS.projects.foundations.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] -> err.stack = " + err.stack);
}
throw 'Error Already Recorded'
}
}