From 481986cc459eb15ab8af2b2b90cf88e5fc2d8d02 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 10 May 2020 08:43:04 +0200 Subject: [PATCH 01/44] Update Commons.js --- Commons.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index 70200a529..4d628a7bd 100644 --- a/Commons.js +++ b/Commons.js @@ -3,6 +3,7 @@ const FULL_LOG = true; const LOG_FILE_CONTENT = false; const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; + const ONE_MIN_IN_MILISECONDS = 60 * 1000; const MODULE_NAME = "Commons"; @@ -284,7 +285,8 @@ let yesterday = {} let system = { // These are the available system variables to be used in User Code and Formulas timeFrame: timeFrame, - ONE_DAY_IN_MILISECONDS: ONE_DAY_IN_MILISECONDS + ONE_DAY_IN_MILISECONDS: ONE_DAY_IN_MILISECONDS, + ONE_MIN_IN_MILISECONDS: ONE_MIN_IN_MILISECONDS } let variable = {} // This is the structure where the user will define its own variables that will be shared across different code blocks and formulas. let results = [] From b69a9416cab9b5d56095d9089e283f17990fea3b Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 10 May 2020 14:17:10 +0200 Subject: [PATCH 02/44] Snapshots --- TradingBot.js | 140 +++++++++++++++++-------------------------- TradingSimulation.js | 116 ++++++++++++++++++++++++++++++++--- package-lock.json | 18 +++--- 3 files changed, 172 insertions(+), 102 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index 1a2852487..c0af44f59 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -121,6 +121,7 @@ const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; const STRATEGIES_FOLDER_NAME = "Simulation-Strategies"; const TRADES_FOLDER_NAME = "Simulation-Trades"; + const SNAPSHOTS_FOLDER_NAME = "Snapshots"; const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; @@ -129,6 +130,10 @@ let strategiesArray let tradesArray + let snapshotHeaders + let triggerOnSnapshot + let takePositionSnapshot + let tradingSystem = {}; tradingSimulation.runSimulation( @@ -142,7 +147,7 @@ writeFiles, callBackFunction) - function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray) { + function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pSnapshotHeaders, pTriggerOnSnapshot, pTakePositionSnapshot) { tradingSystem = pTradingSystem recordsArray = pRecordsArray @@ -150,11 +155,16 @@ strategiesArray = pStrategiesArray tradesArray = pTradesArray + snapshotHeaders = pSnapshotHeaders + triggerOnSnapshot = pTriggerOnSnapshot + takePositionSnapshot = pTakePositionSnapshot + if (timeFrame > global.dailyFilePeriods[0][0]) { writeMarketFiles() } else { writeDailyFiles() } + } function writeMarketFiles() { @@ -474,7 +484,7 @@ } - callBackFunction(global.DEFAULT_OK_RESPONSE); + writeSnapshotFiles(); } catch (err) { @@ -489,97 +499,52 @@ } } - } + function writeSnapshotFiles() { - function writeDailyFiles() { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> Entering function."); } + writeSnapshotFile(triggerOnSnapshot, 'Trigger-On', onFinish) - writeRecordsFile(); + function onFinish() { + writeSnapshotFile(takePositionSnapshot, 'Take-Position', callBackFunction) + } + + } - /* TODO : NEXT function is a work in progress, not used today */ - function writeFinalResults() { + function writeSnapshotFile(snapshotArray, pFileName, callBack) { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeFinalResults -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeSnapshotFile -> Entering function."); } - if ( // We only write this file if we are at the head of the market. - Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS - !== - Math.trunc((new Date()).valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS - ) { - writeRecordsFile(); - return; - } - - let separator = ""; let fileRecordCounter = 0; let fileContent = ""; + let separator = "\r\n"; - for (let i = 0; i < recordsArray.length; i++) { - - let record = recordsArray[i]; - - /* Will only add to the file the records of the current day */ - - if (record.begin < currentDay.valueOf()) { continue; } - - fileContent = fileContent + separator + '[' + - record.begin + "," + - record.end + "," + - record.type + "," + - record.marketRate + "," + - record.amount + "," + - record.balanceA + "," + - record.balanceB + "," + - record.profit + "," + - record.lastTradeProfitLoss + "," + - record.stopLoss + "," + - record.roundtrips + "," + - record.hits + "," + - record.fails + "," + - record.hitRatio + "," + - record.ROI + "," + - record.periods + "," + - record.days + "," + - record.anualizedRateOfReturn + "," + - record.positionRate + "," + - record.lastTradeROI + "," + - record.strategy + "," + - record.strategyStageNumber + "," + - record.takeProfit + "," + - record.stopLossPhase + "," + - record.takeProfitPhase + "," + - JSON.stringify(record.executionRecord) + "," + - record.positionSize + "," + - record.initialBalanceA + "," + - record.minimumBalanceA + "," + - record.maximumBalanceA + "," + - record.initialBalanceB + "," + - record.minimumBalanceB + "," + - record.maximumBalanceB + "," + - record.baseAsset + "," + - record.quotedAsset + "," + - record.marketBaseAsset + "," + - record.marketQuotedAsset + "," + - record.positionPeriods + "," + - record.positionDays + "," + - record.distanceToLastTriggerOn + "," + - record.distanceToLastTriggerOff + "," + - record.distanceToLastTakePosition + "," + - record.distanceToLastClosePosition + "]"; - - if (separator === "") { separator = ","; } + parseRecord(snapshotHeaders) + for (let i = 0; i < snapshotArray.length; i++) { + let record = snapshotArray[i]; + parseRecord(record) fileRecordCounter++; + } + + function parseRecord(record) { + for (let j = 0; j < record.length; j++) { + let property = record[j] + + fileContent = fileContent + '' + property + if (j !== record.length - 1) { + fileContent = fileContent + "," + } + } + fileContent = fileContent + separator } - fileContent = "[" + fileContent + "]"; + fileContent = "" + fileContent + ""; - let fileName = 'Data.json'; - let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timeFrameLabel; + let fileName = pFileName + '.csv'; + let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SNAPSHOTS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timeFrameLabel; filePath += '/' + fileName fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); @@ -588,35 +553,42 @@ try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> fileContent = " + fileContent); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> fileContent = " + fileContent); } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> market = " + market.baseAsset + "_" + market.quotedAsset); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> market = " + market.baseAsset + "_" + market.quotedAsset); callBackFunction(err); return; } - writeRecordsFile(); + callBack(global.DEFAULT_OK_RESPONSE); } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } + } + + function writeDailyFiles() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> Entering function."); } + + writeRecordsFile(); + function writeRecordsFile() { try { diff --git a/TradingSimulation.js b/TradingSimulation.js index 1e924e89c..9fc408d30 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -39,6 +39,10 @@ } else { processingDailyFiles = true } + + let snapshotHeaders + let triggerOnSnapshot = []; + let takePositionSnapshot = []; let recordsArray = []; let conditionsArray = []; @@ -500,6 +504,14 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Entering function."); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Processing candle # " + currentCandleIndex); } + /* We are going to take snapshots of the values of indicators at key moments of the sumulation. */ + + let snapshotKeys = new Map() + snapshotLoopHeaders = [] + snapshotDataRecord = [] + addToTriggerOnSnapshot = false + addToTakePositionSnapshot = false + let announcementsToBeMade = [] let candle = candles[currentCandleIndex]; @@ -767,7 +779,9 @@ if (initialDefinition.positionSize !== undefined) { if (initialDefinition.positionSize.formula !== undefined) { try { - positionSize = eval(initialDefinition.positionSize.formula.code); + let code = initialDefinition.positionSize.formula.code + positionSize = eval(code); + addCodeToSnapshot(code) } catch (err) { initialDefinition.positionSize.formula.error = err.message } @@ -794,7 +808,9 @@ if (initialDefinition.positionRate !== undefined) { if (initialDefinition.positionRate.formula !== undefined) { try { + let code = initialDefinition.positionRate.formula.code positionRate = eval(initialDefinition.positionRate.formula.code); + addCodeToSnapshot(code) } catch (err) { initialDefinition.positionRate.formula.error = err.message } @@ -821,7 +837,9 @@ if (phase.formula !== undefined) { try { - formulaValue = eval(phase.formula.code); + let code = phase.formula.code + formulaValue = eval(code); + addCodeToSnapshot(code) if (formulaValue === Infinity) { formulaError = "Formula evaluates to Infinity." formulaValue = MAX_STOP_LOSS_VALUE @@ -910,7 +928,9 @@ if (phase.formula !== undefined) { try { - formulaValue = eval(phase.formula.code); + let code = phase.formula.code + formulaValue = eval(code); + addCodeToSnapshot(code) if (formulaValue === Infinity) { formulaValue = MAX_TAKE_PROFIT_VALUE if (takeProfitStage === 'Open Stage') { @@ -1007,7 +1027,9 @@ if (phase.formula !== undefined) { try { - formulaValue = eval(phase.formula.code); + let code = phase.formula.code + formulaValue = eval(code); + addCodeToSnapshot(code) if (formulaValue === Infinity) { formulaError = "" formulaValue = MAX_STOP_LOSS_VALUE @@ -1096,7 +1118,9 @@ if (phase.formula !== undefined) { try { - formulaValue = eval(phase.formula.code); + let code = phase.formula.code + formulaValue = eval(code); + addCodeToSnapshot(code) if (formulaValue === Infinity) { formulaError = "Formula evaluates to Infinity." formulaValue = MAX_TAKE_PROFIT_VALUE @@ -1181,7 +1205,9 @@ let value try { - value = eval(node.code); + let code = node.code + value = eval(code); + addCodeToSnapshot(code) } catch (err) { /* One possible error is that the conditions references a .previous that is undefined. For this @@ -1319,6 +1345,7 @@ } checkAnnouncements(triggerStage.triggerOn) + addToTriggerOnSnapshot = true if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Switching to Trigger Stage because conditions at Trigger On Event were met."); } break; @@ -1452,6 +1479,7 @@ currentTrade.takePositionSituation = situation.name checkAnnouncements(triggerStage.takePosition) + addToTakePositionSnapshot = true if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Conditions at the Take Position Event were met."); } break; @@ -2186,6 +2214,7 @@ } takePositionAtSimulation() + return function putOpeningOrder() { @@ -2914,6 +2943,21 @@ } } + /* Add to Snapshot */ + if (addToTakePositionSnapshot === true) { + takePositionSnapshot.push(snapshotDataRecord) + addToTakePositionSnapshot = false + } + + if (addToTriggerOnSnapshot === true) { + triggerOnSnapshot.push(snapshotDataRecord) + addToTriggerOnSnapshot = false + } + + if (snapshotHeaders === undefined) { + snapshotHeaders = JSON.parse(JSON.stringify(snapshotLoopHeaders)) + } + makeAnnoucements() // After everything at the simulation level was done, we will do the annoucements that are pending. } @@ -3005,10 +3049,63 @@ } } } + + function addCodeToSnapshot(code) { + if (code === undefined) { return } + + try { + let instructionsArray = code.split(' ') + for (let i = 0; i < instructionsArray.length; i++) { + let instruction = instructionsArray[i] + instruction = instruction.replace('(', '') + instruction = instruction.replace(')', '') + instruction = instruction.replace(//g, '') + instruction = instruction.replace(/<=/g, '') + instruction = instruction.replace(/>=/g, '') + instruction = instruction.replace(/!=/g, '') + instruction = instruction.replace(/!==/g, '') + instruction = instruction.replace(/==/g, '') + instruction = instruction.replace(/===/g, '') + if (instruction.indexOf('chart') >= 0) { + let parts = instruction.split('.') + let timeFrame = parts[1] + let product = parts[2] + let property + checkPrevious(3) + function checkPrevious(index) { + property = parts[index] + if (property === 'previous') { + product = product + '.previous' + checkPrevious(index + 1) + } + } + + // Example: chart.at01hs.popularSMA.sma200 - chart.at01hs.popularSMA.sma100 < 10 + if (timeFrame !== 'atAnyTimeFrame') { + timeFrame = timeFrame.substring(2, 4) + '-' + timeFrame.substring(4, 7) + } + let key = timeFrame + '-' + product + '-' + property + let existingKey = snapshotKeys.get(key) + + if (existingKey === undefined) {// means that at the current loop this property of this product was not used before. + snapshotKeys.set(key, key) + snapshotLoopHeaders.push(key) + + let value = eval(instruction) + snapshotDataRecord.push(value) + } + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] runSimulation -> addCodeToSnapshot -> code = " + code); + logger.write(MODULE_NAME, "[ERROR] runSimulation -> addCodeToSnapshot -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } } - - function controlLoop() { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> controlLoop -> Entering function."); } @@ -3114,7 +3211,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> callback -> recordsArray.length = " + recordsArray.length); } - callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, tradesArray); + callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, tradesArray, snapshotHeaders, triggerOnSnapshot, takePositionSnapshot); } function getElement(pArray, currentCandle, datasetName) { @@ -3156,6 +3253,7 @@ } } } + catch (err) { logger.write(MODULE_NAME, "[ERROR] runSimulation -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); diff --git a/package-lock.json b/package-lock.json index 9da031d46..fc670f1b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "ccxt": { - "version": "1.25.80", - "resolved": "https://registry.npmjs.org/ccxt/-/ccxt-1.25.80.tgz", - "integrity": "sha512-AUWagxMa8PMexRabbktWezlmVacj6L2Ep4844ebIXUOyME2Ommg7O/9/pq0F2Ne1IHcJnNJzHrMYQvkh2gBtlw==" + "version": "1.27.45", + "resolved": "https://registry.npmjs.org/ccxt/-/ccxt-1.27.45.tgz", + "integrity": "sha512-4ADlbcIWDzIWjtLvsrtux5jMFj7pU4kVuiqtI2Btq6NEhQ4r/4+LirXdEFlCF6/wIU3XSHabxMd/8nu8HC1KJw==" }, "debug": { "version": "4.1.1", @@ -48,9 +48,9 @@ "integrity": "sha512-jLYV0DORrzY3xaz/S9ydJL6Iz7essZeAfnAavsJ+zsJGZ1MOnsS52yRjU3uF3pJa/lla7+wisp//fxOwOH8SKQ==" }, "telegraf": { - "version": "3.37.0", - "resolved": "https://registry.npmjs.org/telegraf/-/telegraf-3.37.0.tgz", - "integrity": "sha512-V3448qwfOolBqkIc87yxjW4zMvR2P6AIF24pPTlX9WhZPwA1TF/x3nQhnWPRLtGh2SJuvDcr83iTkXPXT7Opnw==", + "version": "3.38.0", + "resolved": "https://registry.npmjs.org/telegraf/-/telegraf-3.38.0.tgz", + "integrity": "sha512-va4VlrKWp64JrowFoZX/NPzzA6q38kvaIukVXOWFO1V+jR1G8+hCfgJy4TX8Z3rwLJzwaBEet1QhikHDRZWl3A==", "requires": { "debug": "4.1.1", "minimist": "1.2.5", @@ -66,9 +66,9 @@ "integrity": "sha512-njVv1EAhIZnmQVLocZEADYUyqA1WIXuVcDYlsp+mXua/XB0pxx+PKtMSPeZ/EE4wPWTw9h/hA9ASTT6yQelkiw==" }, "ws": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", - "integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==" + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz", + "integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==" } } } From 712d0afcdf5d87a76486fffda1fc7b7c0ec39417 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 10 May 2020 18:21:45 +0200 Subject: [PATCH 03/44] Update TradingSimulation.js --- TradingSimulation.js | 74 +++++++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index 9fc408d30..4cafa7c2a 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -43,6 +43,8 @@ let snapshotHeaders let triggerOnSnapshot = []; let takePositionSnapshot = []; + let lastTriggerOnSnapshot + let lastTakePositionSnapshot let recordsArray = []; let conditionsArray = []; @@ -509,8 +511,9 @@ let snapshotKeys = new Map() snapshotLoopHeaders = [] snapshotDataRecord = [] - addToTriggerOnSnapshot = false - addToTakePositionSnapshot = false + saveAsLastTriggerOnSnapshot = false + saveAsLastTakePositionSnapshot = false + addToSnapshots = false let announcementsToBeMade = [] let candle = candles[currentCandleIndex]; @@ -1345,7 +1348,7 @@ } checkAnnouncements(triggerStage.triggerOn) - addToTriggerOnSnapshot = true + saveAsLastTriggerOnSnapshot = true if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Switching to Trigger Stage because conditions at Trigger On Event were met."); } break; @@ -1479,7 +1482,7 @@ currentTrade.takePositionSituation = situation.name checkAnnouncements(triggerStage.takePosition) - addToTakePositionSnapshot = true + saveAsLastTakePositionSnapshot = true if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Conditions at the Take Position Event were met."); } break; @@ -2027,6 +2030,7 @@ currentTrade.endRate = closeRate; closePositionNow = true; + addToSnapshots = true if (processingDailyFiles) { if (positionedAtYesterday) { @@ -2099,6 +2103,7 @@ currentTrade.endRate = closeRate; closePositionNow = true; + addToSnapshots = true if (processingDailyFiles) { if (positionedAtYesterday) { @@ -2909,6 +2914,45 @@ } } + /* Snapshots Management (before we generate the trade record and delete that info) */ + if (saveAsLastTriggerOnSnapshot === true) { + lastTriggerOnSnapshot = snapshotDataRecord + saveAsLastTriggerOnSnapshot = false + } + + if (saveAsLastTakePositionSnapshot === true) { + lastTakePositionSnapshot = snapshotDataRecord + saveAsLastTakePositionSnapshot = false + } + + if (addToSnapshots === true) { + let closeValues = [ + roundtrips, // Trade Number + (new Date(candle.begin)).toISOString(), // Datetime + tradingSystem.strategies[currentStrategyIndex].name, // Strategy + currentStrategy.triggerOnSituation, // Trigger On Situation + currentTrade.takePositionSituation, // Take Position Situation + hitOrFial(), // Result + ROI, // ROI + simulationRecord.type.replace(/"/g, '') // Exit Type + ] + + function hitOrFial() { + if (ROI > 0) { return 'HIT' } else { return 'FAIL' } + } + + triggerOnSnapshot.push(closeValues.concat(lastTriggerOnSnapshot)) + takePositionSnapshot.push(closeValues.concat(lastTriggerOnSnapshot)) + lastTriggerOnSnapshot = undefined + lastTakePositionSnapshot = undefined + addToSnapshots = false + } + + let closeHeaders = ['Trade Number', 'Close Datetime', 'Strategy', 'Trigger On Situation', 'Take Position Situation', 'Result', 'ROI', 'Exit Type'] + if (snapshotHeaders === undefined) { + snapshotHeaders = closeHeaders.concat(JSON.parse(JSON.stringify(snapshotLoopHeaders))) + } + /* Prepare the information for the Trades File */ if (currentTrade.begin !== 0 && currentTrade.end !== 0) { @@ -2943,22 +2987,8 @@ } } - /* Add to Snapshot */ - if (addToTakePositionSnapshot === true) { - takePositionSnapshot.push(snapshotDataRecord) - addToTakePositionSnapshot = false - } - - if (addToTriggerOnSnapshot === true) { - triggerOnSnapshot.push(snapshotDataRecord) - addToTriggerOnSnapshot = false - } - - if (snapshotHeaders === undefined) { - snapshotHeaders = JSON.parse(JSON.stringify(snapshotLoopHeaders)) - } - - makeAnnoucements() // After everything at the simulation level was done, we will do the annoucements that are pending. + /* After everything at the simulation level was done, we will do the annoucements that are pending.*/ + makeAnnoucements() } function checkAnnouncements(node, value) { @@ -3067,6 +3097,8 @@ instruction = instruction.replace(/!==/g, '') instruction = instruction.replace(/==/g, '') instruction = instruction.replace(/===/g, '') + instruction = instruction.replace(/{/g, '') + instruction = instruction.replace(/}/g, '') if (instruction.indexOf('chart') >= 0) { let parts = instruction.split('.') let timeFrame = parts[1] @@ -3091,7 +3123,7 @@ if (existingKey === undefined) {// means that at the current loop this property of this product was not used before. snapshotKeys.set(key, key) snapshotLoopHeaders.push(key) - + let value = eval(instruction) snapshotDataRecord.push(value) } From 7d63716c102eb5bb0383da1a7946cdc948e2c715 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 11 May 2020 09:57:48 +0200 Subject: [PATCH 04/44] Update TradingSimulation.js --- TradingSimulation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index 4cafa7c2a..93c1c3b29 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -2933,12 +2933,12 @@ currentStrategy.triggerOnSituation, // Trigger On Situation currentTrade.takePositionSituation, // Take Position Situation hitOrFial(), // Result - ROI, // ROI + lastTradeROI, // ROI simulationRecord.type.replace(/"/g, '') // Exit Type ] function hitOrFial() { - if (ROI > 0) { return 'HIT' } else { return 'FAIL' } + if (lastTradeROI > 0) { return 'HIT' } else { return 'FAIL' } } triggerOnSnapshot.push(closeValues.concat(lastTriggerOnSnapshot)) From b4f8192e3a49a17d423f7b4bbe9ede4ba7b91b30 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 11 May 2020 11:35:04 +0200 Subject: [PATCH 05/44] snapshots on daily files --- TradingBot.js | 85 +++++++++++++++++++++++++++++++++++- TradingSimulation.js | 102 +++++++++++++++++++++++++++++++++---------- 2 files changed, 163 insertions(+), 24 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index c0af44f59..f17146049 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -927,7 +927,7 @@ } - callBackFunction(global.DEFAULT_OK_RESPONSE); + writeSnapshotFiles() } catch (err) { @@ -942,6 +942,89 @@ } } + function writeSnapshotFiles() { + + writeSnapshotFile(triggerOnSnapshot, 'Trigger-On', onFinish) + + function onFinish() { + writeSnapshotFile(takePositionSnapshot, 'Take-Position', callBackFunction) + } + + } + + function writeSnapshotFile(snapshotArray, pFileName, callBack) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeSnapshotFile -> Entering function."); } + + let fileRecordCounter = 0; + + let fileContent = ""; + let separator = "\r\n"; + + parseRecord(snapshotHeaders) + + for (let i = 0; i < snapshotArray.length; i++) { + let record = snapshotArray[i]; + parseRecord(record) + fileRecordCounter++; + } + + function parseRecord(record) { + for (let j = 0; j < record.length; j++) { + let property = record[j] + + fileContent = fileContent + '' + property + if (j !== record.length - 1) { + fileContent = fileContent + "," + } + } + fileContent = fileContent + separator + + } + + fileContent = "" + fileContent + ""; + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); + let fileName = pFileName + '.csv'; + let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SNAPSHOTS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timeFrameLabel + "/" + dateForPath; + filePath += '/' + fileName + + fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> market = " + market.baseAsset + "_" + market.quotedAsset); + + callBackFunction(err); + return; + + } + + callBack(global.DEFAULT_OK_RESPONSE); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeSnapshotFile -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } } } catch (err) { diff --git a/TradingSimulation.js b/TradingSimulation.js index 93c1c3b29..ca82f07f2 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -39,12 +39,6 @@ } else { processingDailyFiles = true } - - let snapshotHeaders - let triggerOnSnapshot = []; - let takePositionSnapshot = []; - let lastTriggerOnSnapshot - let lastTakePositionSnapshot let recordsArray = []; let conditionsArray = []; @@ -109,6 +103,15 @@ interExecutionMemory. */ + /* Snapshots of Trigger On and Take Positions */ + let snapshots = { + headers: undefined, + triggerOn: [], + takePosition: [], + lastTriggerOn: undefined, + lastTakePosition: undefined + } + /*Needed for statistics */ let previousBalanceBaseAsset = 0; let previousBalanceQuotedAsset = 0; @@ -187,6 +190,15 @@ /* Initialization */ + + yesterday.snapshots = { + headers: undefined, + triggerOn: [], + takePosition: [], + lastTriggerOn: undefined, + lastTakePosition: undefined + } + yesterday.stopLoss = 0 yesterday.takeProfit = 0 @@ -257,6 +269,14 @@ /* Initialize the data structure we will use inter execution. */ + interExecutionMemory.snapshots = { + headers: undefined, + triggerOn: [], + takePosition: [], + lastTriggerOn: undefined, + lastTakePosition: undefined + } + interExecutionMemory.stopLoss = 0 interExecutionMemory.takeProfit = 0 @@ -329,6 +349,14 @@ /* We get the initial values from the day previous to the candles we receive at the current execution */ + snapshots = { + headers: interExecutionMemory.snapshots.headers, + triggerOn: interExecutionMemory.snapshots.triggerOn, + takePosition: interExecutionMemory.snapshots.takePosition, + lastTriggerOn: interExecutionMemory.snapshots.lastTriggerOn, + lastTakePosition: interExecutionMemory.snapshots.lastTakePosition + } + stopLoss = interExecutionMemory.stopLoss takeProfit = interExecutionMemory.takeProfit @@ -404,6 +432,14 @@ /* For the case that any of these variables are not updated during the main loop, we need to store their value at the yesterday structure, otherwise it would be lost. */ + yesterday.snapshots = { + headers: snapshots.headers, + triggerOn: snapshots.triggerOn, + takePosition: snapshots.takePosition, + lastTriggerOn: snapshots.lastTriggerOn, + lastTakePosition: snapshots.lastTakePosition + } + yesterday.stopLoss = stopLoss yesterday.takeProfit = takeProfit @@ -2916,41 +2952,53 @@ /* Snapshots Management (before we generate the trade record and delete that info) */ if (saveAsLastTriggerOnSnapshot === true) { - lastTriggerOnSnapshot = snapshotDataRecord + snapshots.lastTriggerOn = snapshotDataRecord saveAsLastTriggerOnSnapshot = false } if (saveAsLastTakePositionSnapshot === true) { - lastTakePositionSnapshot = snapshotDataRecord + snapshots.lastTakePosition = snapshotDataRecord saveAsLastTakePositionSnapshot = false } if (addToSnapshots === true) { let closeValues = [ - roundtrips, // Trade Number - (new Date(candle.begin)).toISOString(), // Datetime - tradingSystem.strategies[currentStrategyIndex].name, // Strategy - currentStrategy.triggerOnSituation, // Trigger On Situation - currentTrade.takePositionSituation, // Take Position Situation - hitOrFial(), // Result - lastTradeROI, // ROI - simulationRecord.type.replace(/"/g, '') // Exit Type + roundtrips, // Trade Number + (new Date(candle.begin)).toISOString(), // Datetime + tradingSystem.strategies[currentStrategyIndex].name, // Strategy + currentStrategy.triggerOnSituation, // Trigger On Situation + currentTrade.takePositionSituation, // Take Position Situation + hitOrFial(), // Result + lastTradeROI, // ROI + simulationRecord.type.replace(/"/g, '') // Exit Type ] function hitOrFial() { if (lastTradeROI > 0) { return 'HIT' } else { return 'FAIL' } } - triggerOnSnapshot.push(closeValues.concat(lastTriggerOnSnapshot)) - takePositionSnapshot.push(closeValues.concat(lastTriggerOnSnapshot)) - lastTriggerOnSnapshot = undefined - lastTakePositionSnapshot = undefined + if (positionedAtYesterday === false) { + snapshots.triggerOn.push(closeValues.concat(snapshots.lastTriggerOn)) + snapshots.takePosition.push(closeValues.concat(snapshots.lastTriggerOn)) + } + snapshots.lastTriggerOn = undefined + snapshots.lastTakePosition = undefined addToSnapshots = false } let closeHeaders = ['Trade Number', 'Close Datetime', 'Strategy', 'Trigger On Situation', 'Take Position Situation', 'Result', 'ROI', 'Exit Type'] - if (snapshotHeaders === undefined) { - snapshotHeaders = closeHeaders.concat(JSON.parse(JSON.stringify(snapshotLoopHeaders))) + if (snapshots.headers === undefined) { + snapshots.headers = closeHeaders.concat(JSON.parse(JSON.stringify(snapshotLoopHeaders))) + } + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.snapshots.headers = snapshots.headers; + yesterday.snapshots.triggerOn = snapshots.triggerOn; + yesterday.snapshots.takePosition = snapshots.takePosition; + yesterday.snapshots.lastTriggerOn = snapshots.lastTriggerOn; + yesterday.snapshots.lastTakePosition = snapshots.lastTakePosition; + } } /* Prepare the information for the Trades File */ @@ -3176,6 +3224,14 @@ if (lastCandle.end === lastInstantOfTheDay) { + interExecutionMemory.snapshots = { + headers: yesterday.snapshots.headers, + triggerOn: yesterday.snapshots.triggerOn, + takePosition: yesterday.snapshots.takePosition, + lastTriggerOn: yesterday.snapshots.lastTriggerOn, + lastTakePosition: yesterday.snapshots.lastTakePosition + } + interExecutionMemory.stopLoss = yesterday.stopLoss interExecutionMemory.takeProfit = yesterday.takeProfit @@ -3243,7 +3299,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> callback -> recordsArray.length = " + recordsArray.length); } - callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, tradesArray, snapshotHeaders, triggerOnSnapshot, takePositionSnapshot); + callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, tradesArray, snapshots.headers, snapshots.triggerOn, snapshots.takePosition); } function getElement(pArray, currentCandle, datasetName) { From 8ad62e585c4a3ca30298a24c55537e130fc3d02f Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 11 May 2020 20:47:50 +0200 Subject: [PATCH 06/44] MIN_STOP_LOSS_VALUE changed --- TradingSimulation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index ca82f07f2..991d4931d 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -56,13 +56,13 @@ /* Stop Loss Management */ - const MIN_STOP_LOSS_VALUE = 1 // We can not let the stop be zero to avoid division by 0 error or infinity numbers as a result. + const MIN_STOP_LOSS_VALUE = 0.0000000001 // We can not let the stop be zero to avoid division by 0 error or infinity numbers as a result. const MAX_STOP_LOSS_VALUE = Number.MAX_SAFE_INTEGER let stopLoss = 0; /* Take Profit Management */ - const MIN_TAKE_PROFIT_VALUE = 1 // We can not let the buy order be zero to avoid division by 0 error or infinity numbers as a result. + const MIN_TAKE_PROFIT_VALUE = 0.0000000001 // We can not let the buy order be zero to avoid division by 0 error or infinity numbers as a result. const MAX_TAKE_PROFIT_VALUE = Number.MAX_SAFE_INTEGER let takeProfit = 0; From ceec49ebc6268832724bd4d64a57add960d8cfbd Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 May 2020 08:05:51 +0200 Subject: [PATCH 07/44] Update TradingSimulation.js --- TradingSimulation.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/TradingSimulation.js b/TradingSimulation.js index 991d4931d..b25db5c12 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -1327,6 +1327,11 @@ for (let j = 0; j < tradingSystem.strategies.length; j++) { + if ( + strategyStage !== 'No Stage' || + currentStrategyIndex !== -1 + ) {continue} + let strategy = tradingSystem.strategies[j]; let triggerStage = strategy.triggerStage From 2e4b7bd2d5e5b0a14b2051c2b76bd7bc1cc2fd46 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 May 2020 09:20:48 +0200 Subject: [PATCH 08/44] report fixed --- TradingSimulation.js | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index b25db5c12..5b75cb670 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -1343,7 +1343,10 @@ for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { let situation = triggerStage.triggerOn.situations[k]; - let passed = true; + let passed + if (situation.conditions.length > 0) { + passed = true + } for (let m = 0; m < situation.conditions.length; m++) { @@ -1415,7 +1418,10 @@ for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { let situation = triggerStage.triggerOff.situations[k]; - let passed = true; + let passed + if (situation.conditions.length > 0) { + passed = true + } for (let m = 0; m < situation.conditions.length; m++) { @@ -1482,7 +1488,10 @@ for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { let situation = triggerStage.takePosition.situations[k]; - let passed = true; + let passed + if (situation.conditions.length > 0) { + passed = true + } for (let m = 0; m < situation.conditions.length; m++) { @@ -1585,7 +1594,10 @@ for (let k = 0; k < nextPhaseEvent.situations.length; k++) { let situation = nextPhaseEvent.situations[k]; - let passed = true; + let passed + if (situation.conditions.length > 0) { + passed = true + } for (let m = 0; m < situation.conditions.length; m++) { @@ -1631,7 +1643,10 @@ for (let k = 0; k < moveToPhaseEvent.situations.length; k++) { let situation = moveToPhaseEvent.situations[k]; - let passed = true; + let passed + if (situation.conditions.length > 0) { + passed = true + } for (let m = 0; m < situation.conditions.length; m++) { @@ -1779,7 +1794,10 @@ for (let k = 0; k < nextPhaseEvent.situations.length; k++) { let situation = nextPhaseEvent.situations[k]; - let passed = true; + let passed + if (situation.conditions.length > 0) { + passed = true + } for (let m = 0; m < situation.conditions.length; m++) { @@ -1825,7 +1843,10 @@ for (let k = 0; k < moveToPhaseEvent.situations.length; k++) { let situation = moveToPhaseEvent.situations[k]; - let passed = true; + let passed + if (situation.conditions.length > 0) { + passed = true + } for (let m = 0; m < situation.conditions.length; m++) { @@ -2984,7 +3005,7 @@ if (positionedAtYesterday === false) { snapshots.triggerOn.push(closeValues.concat(snapshots.lastTriggerOn)) - snapshots.takePosition.push(closeValues.concat(snapshots.lastTriggerOn)) + snapshots.takePosition.push(closeValues.concat(snapshots.lastTakePosition)) } snapshots.lastTriggerOn = undefined snapshots.lastTakePosition = undefined From 0bd0b9cfcf0aa9ae9f58d65d8e87aa702d292e85 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 May 2020 14:53:57 +0200 Subject: [PATCH 09/44] Update TradingSimulation.js --- TradingSimulation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index 5b75cb670..0f0c30c34 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -2339,7 +2339,7 @@ if (baseAsset === bot.market.baseAsset) { orderSide = "sell" - orderPrice = tradePositionRate - 100 // This is going to be ingnored at the Exchange API for now since we only put market orders. + orderPrice = tradePositionRate amountA = tradePositionSize * orderPrice amountB = tradePositionSize @@ -2347,7 +2347,7 @@ } else { orderSide = "buy" - orderPrice = tradePositionRate // This is going to be ingnored at the Exchange API for now since we only put market orders. + orderPrice = tradePositionRate amountA = tradePositionSize amountB = tradePositionSize / orderPrice From 66a2a6a358f545517085bdd92c72b9aa6e39509b Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 May 2020 20:23:49 +0200 Subject: [PATCH 10/44] Update Commons.js --- Commons.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Commons.js b/Commons.js index 4d628a7bd..fcc9ded0b 100644 --- a/Commons.js +++ b/Commons.js @@ -56,6 +56,11 @@ callBackFunction(global.DEFAULT_FAIL_RESPONSE); return } + if (outputDatasetNode.referenceParent.parentNode === undefined) { + logger.write(MODULE_NAME, "[ERROR] start -> Dataset not a child of a Product Definition. Dataset = " + JSON.stringify(outputDatasetNode.referenceParent)); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return + } if (outputDatasetNode.referenceParent.parentNode.code.singularVariableName === undefined) { logger.write(MODULE_NAME, "[ERROR] start -> Product Definition without a Single Variable Name defined. Product Definition = " + JSON.stringify(outputDatasetNode.referenceParent.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); From 2e66ecd94b50381ab94e3b06d256a0dbb102ac3c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 18 May 2020 20:43:50 +0200 Subject: [PATCH 11/44] Strategy Name at Plotter --- TradingBot.js | 6 ++++-- TradingSimulation.js | 26 ++++++++++++++++++-------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index f17146049..fe866f88a 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -377,7 +377,8 @@ record.number + "," + record.beginRate + "," + record.endRate + "," + - '"' + record.triggerOnSituation + '"' + "]"; + '"' + record.triggerOnSituation + '"' + "," + + '"' + record.name + '"' + "]"; if (separator === "") { separator = ","; } @@ -813,7 +814,8 @@ record.number + "," + record.beginRate + "," + record.endRate + "," + - '"' + record.triggerOnSituation + '"' + "]"; + '"' + record.triggerOnSituation + '"' + "," + + '"' + record.name + '"' + "]"; if (separator === "") { separator = ","; } diff --git a/TradingSimulation.js b/TradingSimulation.js index 0f0c30c34..2cb22cc25 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -139,7 +139,8 @@ number: 0, beginRate: 0, endRate: 0, - triggerOnSituation: '' + triggerOnSituation: '', + name: '' } let currentTrade = { @@ -224,7 +225,8 @@ number: 0, beginRate: 0, endRate: 0, - triggerOnSituation: '' + triggerOnSituation: '', + name: '' } yesterday.currentTrade = { @@ -302,7 +304,8 @@ number: 0, beginRate: 0, endRate: 0, - triggerOnSituation: '' + triggerOnSituation: '', + name: '' } interExecutionMemory.currentTrade = { @@ -382,7 +385,8 @@ number: interExecutionMemory.currentStrategy.number, beginRate: interExecutionMemory.currentStrategy.beginRate, endRate: interExecutionMemory.currentStrategy.endRate, - triggerOnSituation: interExecutionMemory.currentStrategy.triggerOnSituation + triggerOnSituation: interExecutionMemory.currentStrategy.triggerOnSituation, + name: currentStrategy.name } currentTrade = { @@ -465,7 +469,8 @@ number: currentStrategy.number, beginRate: currentStrategy.beginRate, endRate: currentStrategy.endRate, - triggerOnSituation: currentStrategy.triggerOnSituation + triggerOnSituation: currentStrategy.triggerOnSituation, + name: currentStrategy.name } yesterday.currentTrade = { @@ -1371,6 +1376,7 @@ currentStrategy.beginRate = candle.min; currentStrategy.endRate = candle.min; // In case the strategy does not get exited currentStrategy.triggerOnSituation = situation.name + currentStrategy.name = strategy.name if (processingDailyFiles) { if (positionedAtYesterday) { @@ -1380,6 +1386,7 @@ yesterday.currentStrategy.beginRate = currentStrategy.beginRate; yesterday.currentStrategy.endRate = currentStrategy.endRate; yesterday.currentStrategy.triggerOnSituation = currentStrategy.triggerOnSituation; + yesterday.currentStrategy.name = currentStrategy.name; } } @@ -2941,7 +2948,8 @@ number: 0, beginRate: 0, endRate: 0, - triggerOnSituation: '' + triggerOnSituation: '', + name: '' } if (processingDailyFiles) { @@ -2953,7 +2961,8 @@ number: 0, beginRate: 0, endRate: 0, - triggerOnSituation: '' + triggerOnSituation: '', + name: '' } } } @@ -3283,7 +3292,8 @@ number: yesterday.currentStrategy.number, beginRate: yesterday.currentStrategy.beginRate, endRate: yesterday.currentStrategy.endRate, - triggerOnSituation: yesterday.currentStrategy.triggerOnSituation + triggerOnSituation: yesterday.currentStrategy.triggerOnSituation, + name: yesterday.currentStrategy.name } interExecutionMemory.currentTrade = { From 8d0dd2614d3731471065f1bb8be058b0471edd36 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 19 May 2020 12:17:47 +0200 Subject: [PATCH 12/44] yesterday code removed --- TradingSimulation.js | 748 ++++++------------------------------------- 1 file changed, 101 insertions(+), 647 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index 1e924e89c..f17d2e43c 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -26,7 +26,7 @@ timeFrame, timeFrameLabel, currentDay, - interExecutionMemory, + variable, exchangeAPI, callback, callBackFunction) { @@ -90,7 +90,7 @@ This is challenging when the simulation is executed using Daily Files, since each execution means a new day and these counters are meant to be kept along the whole market. - To overcome this problem, we use the interExecutionMemory to record the values of the current execution + To overcome this problem, we use the variable to record the values of the current execution when finish. But there are a few details: 1. When the process is at the head of the market, it executes multple times at the same day. @@ -98,9 +98,9 @@ 3. In Daily Files we are receiving candles from the current day and previous day, so we need to take care of not adding to the counters duplicate info when processing the day before candles. - To overcome these challenges we record the values of the counters and variables on the interExecutionMemory only when + To overcome these challenges we record the values of the counters and variables on the variable only when the day is complete and if we have a current Day. That menas that for Market Files we will never use - interExecutionMemory. + variable. */ /*Needed for statistics */ @@ -177,99 +177,30 @@ baseAsset = bot.VALUES_TO_USE.baseAsset quotedAsset = bot.VALUES_TO_USE.quotedAsset - let yesterday = {}; - /* Initialization */ - - yesterday.stopLoss = 0 - yesterday.takeProfit = 0 - - yesterday.previousBalanceBaseAsset = previousBalanceBaseAsset - yesterday.previousBalanceQuotedAsset = previousBalanceQuotedAsset - - yesterday.tradePositionRate = tradePositionRate - yesterday.tradePositionSize = tradePositionSize - - yesterday.currentStrategyIndex = currentStrategyIndex - yesterday.strategyStage = strategyStage - - yesterday.stopLossPhase = stopLossPhase - yesterday.stopLossStage = stopLossStage - - yesterday.takeProfitPhase = takeProfitPhase - yesterday.takeProfitStage = takeProfitStage - - yesterday.currentStrategy = { - begin: 0, - end: 0, - status: 0, - number: 0, - beginRate: 0, - endRate: 0, - triggerOnSituation: '' - } - - yesterday.currentTrade = { - begin: 0, - end: 0, - status: 0, - profit: 0, - exitType: 0, - beginRate: 0, - endRate: 0, - takePositionSituation: '' - } - - yesterday.balanceBaseAsset = balanceBaseAsset; - yesterday.balanceQuotedAsset = balanceQuotedAsset; - - yesterday.lastTradeProfitLoss = 0; - yesterday.profit = 0; - yesterday.lastTradeROI = 0; - - yesterday.roundtrips = 0; - yesterday.fails = 0; - yesterday.hits = 0; - yesterday.periods = 0; - yesterday.positionPeriods = 0; - - yesterday.distanceToLast = { - triggerOn: 0, - triggerOff: 0, - takePosition: 0, - closePosition: 0 - } - - yesterday.orderId = 0; - yesterday.messageId = 0; - - yesterday.hitRatio = 0; - yesterday.ROI = 0; - yesterday.anualizedRateOfReturn = 0; - - if (interExecutionMemory.roundtrips === undefined) { // This just means that the inter execution memory was never used before. + if (variable.roundtrips === undefined) { // This just means that the inter execution memory was never used before. /* Initialize the data structure we will use inter execution. */ - interExecutionMemory.stopLoss = 0 - interExecutionMemory.takeProfit = 0 + variable.stopLoss = 0 + variable.takeProfit = 0 - interExecutionMemory.previousBalanceBaseAsset = previousBalanceBaseAsset - interExecutionMemory.previousBalanceQuotedAsset = previousBalanceQuotedAsset + variable.previousBalanceBaseAsset = previousBalanceBaseAsset + variable.previousBalanceQuotedAsset = previousBalanceQuotedAsset - interExecutionMemory.tradePositionRate = tradePositionRate - interExecutionMemory.tradePositionSize = tradePositionSize + variable.tradePositionRate = tradePositionRate + variable.tradePositionSize = tradePositionSize - interExecutionMemory.currentStrategyIndex = currentStrategyIndex - interExecutionMemory.strategyStage = strategyStage + variable.currentStrategyIndex = currentStrategyIndex + variable.strategyStage = strategyStage - interExecutionMemory.stopLossPhase = stopLossPhase - interExecutionMemory.stopLossStage = stopLossStage + variable.stopLossPhase = stopLossPhase + variable.stopLossStage = stopLossStage - interExecutionMemory.takeProfitPhase = takeProfitPhase - interExecutionMemory.takeProfitStage = takeProfitStage + variable.takeProfitPhase = takeProfitPhase + variable.takeProfitStage = takeProfitStage - interExecutionMemory.currentStrategy = { + variable.currentStrategy = { begin: 0, end: 0, status: 0, @@ -279,7 +210,7 @@ triggerOnSituation: '' } - interExecutionMemory.currentTrade = { + variable.currentTrade = { begin: 0, end: 0, status: 0, @@ -290,171 +221,109 @@ takePositionSituation: '' } - interExecutionMemory.balanceBaseAsset = balanceBaseAsset; - interExecutionMemory.balanceQuotedAsset = balanceQuotedAsset; + variable.balanceBaseAsset = balanceBaseAsset; + variable.balanceQuotedAsset = balanceQuotedAsset; - interExecutionMemory.lastTradeProfitLoss = lastTradeProfitLoss; - interExecutionMemory.profit = profit; - interExecutionMemory.lastTradeROI = lastTradeROI; + variable.lastTradeProfitLoss = lastTradeProfitLoss; + variable.profit = profit; + variable.lastTradeROI = lastTradeROI; - interExecutionMemory.roundtrips = 0; - interExecutionMemory.fails = 0; - interExecutionMemory.hits = 0; - interExecutionMemory.periods = 0; - interExecutionMemory.positionPeriods = 0; + variable.roundtrips = 0; + variable.fails = 0; + variable.hits = 0; + variable.periods = 0; + variable.positionPeriods = 0; - interExecutionMemory.distanceToLast = { + variable.distanceToLast = { triggerOn: 0, triggerOff: 0, takePosition: 0, closePosition: 0 } - interExecutionMemory.orderId = 0; - interExecutionMemory.messageId = 0; + variable.orderId = 0; + variable.messageId = 0; - interExecutionMemory.hitRatio = 0; - interExecutionMemory.ROI = 0; - interExecutionMemory.anualizedRateOfReturn = 0; + variable.hitRatio = 0; + variable.ROI = 0; + variable.anualizedRateOfReturn = 0; - interExecutionMemory.announcements = [] + variable.announcements = [] } else { /* We get the initial values from the day previous to the candles we receive at the current execution */ - stopLoss = interExecutionMemory.stopLoss - takeProfit = interExecutionMemory.takeProfit + stopLoss = variable.stopLoss + takeProfit = variable.takeProfit - previousBalanceBaseAsset = interExecutionMemory.previousBalanceBaseAsset - previousBalanceQuotedAsset = interExecutionMemory.previousBalanceQuotedAsset + previousBalanceBaseAsset = variable.previousBalanceBaseAsset + previousBalanceQuotedAsset = variable.previousBalanceQuotedAsset - tradePositionRate = interExecutionMemory.tradePositionRate - tradePositionSize = interExecutionMemory.tradePositionSize + tradePositionRate = variable.tradePositionRate + tradePositionSize = variable.tradePositionSize - currentStrategyIndex = interExecutionMemory.currentStrategyIndex - strategyStage = interExecutionMemory.strategyStage + currentStrategyIndex = variable.currentStrategyIndex + strategyStage = variable.strategyStage - stopLossPhase = interExecutionMemory.stopLossPhase - stopLossStage = interExecutionMemory.stopLossStage + stopLossPhase = variable.stopLossPhase + stopLossStage = variable.stopLossStage - takeProfitPhase = interExecutionMemory.takeProfitPhase - takeProfitStage = interExecutionMemory.takeProfitStage + takeProfitPhase = variable.takeProfitPhase + takeProfitStage = variable.takeProfitStage currentStrategy = { - begin: interExecutionMemory.currentStrategy.begin, - end: interExecutionMemory.currentStrategy.end, - status: interExecutionMemory.currentStrategy.status, - number: interExecutionMemory.currentStrategy.number, - beginRate: interExecutionMemory.currentStrategy.beginRate, - endRate: interExecutionMemory.currentStrategy.endRate, - triggerOnSituation: interExecutionMemory.currentStrategy.triggerOnSituation + begin: variable.currentStrategy.begin, + end: variable.currentStrategy.end, + status: variable.currentStrategy.status, + number: variable.currentStrategy.number, + beginRate: variable.currentStrategy.beginRate, + endRate: variable.currentStrategy.endRate, + triggerOnSituation: variable.currentStrategy.triggerOnSituation } currentTrade = { - begin: interExecutionMemory.currentTrade.begin, - end: interExecutionMemory.currentTrade.end, - status: interExecutionMemory.currentTrade.status, - profit: interExecutionMemory.currentTrade.profit, - exitType: interExecutionMemory.currentTrade.exitType, - beginRate: interExecutionMemory.currentTrade.beginRate, - endRate: interExecutionMemory.currentTrade.endRate, - takePositionSituation: interExecutionMemory.currentTrade.takePositionSituation + begin: variable.currentTrade.begin, + end: variable.currentTrade.end, + status: variable.currentTrade.status, + profit: variable.currentTrade.profit, + exitType: variable.currentTrade.exitType, + beginRate: variable.currentTrade.beginRate, + endRate: variable.currentTrade.endRate, + takePositionSituation: variable.currentTrade.takePositionSituation } if (currentDay) { if (currentDay.valueOf() >= bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf() + ONE_DAY_IN_MILISECONDS) { // Only after the first day we start grabbing the balance from this memory. - balanceBaseAsset = interExecutionMemory.balanceBaseAsset; - balanceQuotedAsset = interExecutionMemory.balanceQuotedAsset; - - yesterday.balanceBaseAsset = balanceBaseAsset; - yesterday.balanceQuotedAsset = balanceQuotedAsset; + balanceBaseAsset = variable.balanceBaseAsset; + balanceQuotedAsset = variable.balanceQuotedAsset; } } - lastTradeProfitLoss = interExecutionMemory.lastTradeProfitLoss; - profit = interExecutionMemory.profit; - lastTradeROI = interExecutionMemory.lastTradeROI; + lastTradeProfitLoss = variable.lastTradeProfitLoss; + profit = variable.profit; + lastTradeROI = variable.lastTradeROI; - roundtrips = interExecutionMemory.roundtrips; - fails = interExecutionMemory.fails; - hits = interExecutionMemory.hits; - periods = interExecutionMemory.periods; - positionPeriods = interExecutionMemory.positionPeriods; + roundtrips = variable.roundtrips; + fails = variable.fails; + hits = variable.hits; + periods = variable.periods; + positionPeriods = variable.positionPeriods; - distanceToLast.triggerOn = interExecutionMemory.distanceToLast.triggerOn - distanceToLast.triggerOff = interExecutionMemory.distanceToLast.triggerOff - distanceToLast.takePosition = interExecutionMemory.distanceToLast.takePosition - distanceToLast.closePosition = interExecutionMemory.distanceToLast.closePosition + distanceToLast.triggerOn = variable.distanceToLast.triggerOn + distanceToLast.triggerOff = variable.distanceToLast.triggerOff + distanceToLast.takePosition = variable.distanceToLast.takePosition + distanceToLast.closePosition = variable.distanceToLast.closePosition - orderId = interExecutionMemory.orderId; // to be deprecated - messageId = interExecutionMemory.messageId; // to be deprecated + orderId = variable.orderId; // to be deprecated + messageId = variable.messageId; // to be deprecated - hitRatio = interExecutionMemory.hitRatio; - ROI = interExecutionMemory.ROI; - anualizedRateOfReturn = interExecutionMemory.anualizedRateOfReturn; + hitRatio = variable.hitRatio; + ROI = variable.ROI; + anualizedRateOfReturn = variable.anualizedRateOfReturn; - /* For the case that any of these variables are not updated during the main loop, we need to store their value at the yesterday structure, otherwise it would be lost. */ - - yesterday.stopLoss = stopLoss - yesterday.takeProfit = takeProfit - - yesterday.previousBalanceBaseAsset = previousBalanceBaseAsset - yesterday.previousBalanceQuotedAsset = previousBalanceQuotedAsset - - yesterday.tradePositionRate = tradePositionRate - yesterday.tradePositionSize = tradePositionSize - - yesterday.currentStrategyIndex = currentStrategyIndex; - yesterday.strategyStage = strategyStage; - - yesterday.stopLossPhase = stopLossPhase; - yesterday.stopLossStage = stopLossStage; - - yesterday.takeProfitPhase = takeProfitPhase; - yesterday.takeProfitStage = takeProfitStage; - - yesterday.currentStrategy = { - begin: currentStrategy.begin, - end: currentStrategy.end, - status: currentStrategy.status, - number: currentStrategy.number, - beginRate: currentStrategy.beginRate, - endRate: currentStrategy.endRate, - triggerOnSituation: currentStrategy.triggerOnSituation - } - - yesterday.currentTrade = { - begin: currentTrade.begin, - end: currentTrade.end, - status: currentTrade.status, - profit: currentTrade.profit, - exitType: currentTrade.exitType, - beginRate: currentTrade.beginRate, - endRate: currentTrade.endRate, - takePositionSituation: currentTrade.takePositionSituation - } - - yesterday.lastTradeProfitLoss = lastTradeProfitLoss; - yesterday.profit = profit; - yesterday.lastTradeROI = lastTradeROI; - - yesterday.roundtrips = roundtrips; - yesterday.fails = fails; - yesterday.hits = hits; - yesterday.periods = periods; - yesterday.positionPeriods = positionPeriods; - - yesterday.distanceToLast.triggerOn = distanceToLast.triggerOn - yesterday.distanceToLast.triggerOff = distanceToLast.triggerOff - yesterday.distanceToLast.takePosition = distanceToLast.takePosition - yesterday.distanceToLast.closePosition = distanceToLast.closePosition - - yesterday.hitRatio = hitRatio; - yesterday.ROI = ROI; - yesterday.anualizedRateOfReturn = anualizedRateOfReturn; } /* Main Array and Maps */ @@ -639,9 +508,6 @@ days = periods * timeFrame / ONE_DAY_IN_MILISECONDS; if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.periods = periods - } /* We skip the candle at the head of the market because currentCandleIndex has not closed yet. */ let candlesPerDay = ONE_DAY_IN_MILISECONDS / timeFrame @@ -1299,25 +1165,8 @@ currentStrategy.endRate = candle.min; // In case the strategy does not get exited currentStrategy.triggerOnSituation = situation.name - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.strategyStage = strategyStage; - yesterday.currentStrategyIndex = currentStrategyIndex; - yesterday.currentStrategy.begin = currentStrategy.begin; - yesterday.currentStrategy.beginRate = currentStrategy.beginRate; - yesterday.currentStrategy.endRate = currentStrategy.endRate; - yesterday.currentStrategy.triggerOnSituation = currentStrategy.triggerOnSituation; - } - } - distanceToLast.triggerOn = 1; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.distanceToLast.triggerOn = distanceToLast.triggerOn - } - } - checkAnnouncements(triggerStage.triggerOn) if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Switching to Trigger Stage because conditions at Trigger On Event were met."); } @@ -1368,25 +1217,8 @@ strategyStage = 'No Stage'; currentStrategyIndex = -1; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.currentStrategy.number = currentStrategy.number; - yesterday.currentStrategy.end = currentStrategy.end; - yesterday.currentStrategy.endRate = currentStrategy.endRate; - yesterday.currentStrategy.status = currentStrategy.status; - yesterday.strategyStage = strategyStage; - yesterday.currentStrategyIndex = currentStrategyIndex; - } - } - distanceToLast.triggerOff = 1; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.distanceToLast.triggerOff = distanceToLast.triggerOff - } - } - checkAnnouncements(triggerStage.triggerOff) if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Switching to No Stage because conditions at the Trigger Off Event were met."); } @@ -1438,16 +1270,6 @@ stopLossPhase = 0; takeProfitPhase = 0; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.strategyStage = strategyStage; - yesterday.stopLossStage = stopLossStage; - yesterday.takeProfitStage = takeProfitStage; - yesterday.stopLossPhase = stopLossPhase; - yesterday.takeProfitPhase = takeProfitPhase; - } - } - takePositionNow = true currentTrade.takePositionSituation = situation.name @@ -1537,14 +1359,6 @@ checkAnnouncements(manageStage, 'Take Profit') } - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.stopLossPhase = stopLossPhase; - yesterday.stopLossStage = stopLossStage; - yesterday.strategyStage = strategyStage; - } - } - checkAnnouncements(nextPhaseEvent) return; } @@ -1593,15 +1407,7 @@ strategyStage = 'Manage Stage' checkAnnouncements(manageStage, 'Take Profit') } - - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.stopLossPhase = stopLossPhase; - yesterday.stopLossStage = stopLossStage; - yesterday.strategyStage = strategyStage; - } - } - + checkAnnouncements(moveToPhaseEvent) return; } @@ -1641,12 +1447,6 @@ stopLoss = formulas.get(key) - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.stopLoss = stopLoss - } - } - if (stopLoss !== previousValue) { checkAnnouncements(phase, stopLoss) } @@ -1731,14 +1531,6 @@ checkAnnouncements(manageStage, 'Stop') } - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.takeProfitPhase = takeProfitPhase; - yesterday.takeProfitStage = takeProfitStage; - yesterday.strategyStage = strategyStage; - } - } - checkAnnouncements(nextPhaseEvent) return; } @@ -1788,14 +1580,6 @@ checkAnnouncements(manageStage, 'Stop') } - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.takeProfitPhase = takeProfitPhase; - yesterday.takeProfitStage = takeProfitStage; - yesterday.strategyStage = strategyStage; - } - } - checkAnnouncements(moveToPhaseEvent) return; } @@ -1835,11 +1619,6 @@ let previousValue = stopLoss takeProfit = formulas.get(key) - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.takeProfit = takeProfit - } - } if (takeProfit !== previousValue) { checkAnnouncements(phase, takeProfit) @@ -1855,31 +1634,14 @@ if (takePositionNow === true) { positionPeriods = 0 - - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.positionPeriods = 0 - } - } } positionPeriods++; positionDays = positionPeriods * timeFrame / ONE_DAY_IN_MILISECONDS; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.positionPeriods = positionPeriods - } - } } else { positionPeriods = 0 positionDays = 0 - - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.positionPeriods = 0 - } - } } /* Keeping Distance Counters Up-to-date */ @@ -1887,48 +1649,24 @@ distanceToLast.triggerOn > 0 // with this we avoind counting before the first event happens. ) { distanceToLast.triggerOn++; - - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.distanceToLast.triggerOn = distanceToLast.triggerOn - } - } } if ( distanceToLast.triggerOff > 0 // with this we avoind counting before the first event happens. ) { distanceToLast.triggerOff++; - - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.distanceToLast.triggerOff = distanceToLast.triggerOff - } - } } if ( distanceToLast.takePosition > 0 // with this we avoind counting before the first event happens. ) { distanceToLast.takePosition++; - - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.distanceToLast.takePosition = distanceToLast.takePosition - } - } } if ( distanceToLast.closePosition > 0 // with this we avoind counting before the first event happens. ) { distanceToLast.closePosition++; - - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.distanceToLast.takePosition = distanceToLast.closePosition - } - } } /* Checking if Stop or Take Profit were hit */ @@ -1956,20 +1694,10 @@ if (baseAsset === bot.market.baseAsset) { if (stopLoss < candle.min) { stopLoss = candle.min - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.stopLoss = stopLoss - } - } } } else { if (stopLoss > candle.max) { stopLoss = candle.max - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.stopLoss = stopLoss - } - } } } @@ -1999,18 +1727,6 @@ currentTrade.endRate = closeRate; closePositionNow = true; - - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.strategyStage = strategyStage; - yesterday.stopLossStage = stopLossStage; - yesterday.takeProfitStage = takeProfitStage; - yesterday.currentTrade.end = currentTrade.end; - yesterday.currentTrade.status = currentTrade.status; - yesterday.currentTrade.exitType = currentTrade.exitType; - yesterday.currentTrade.endRate = currentTrade.endRate; - } - } } /* Take Profit condition: Here we verify if the Take Profit was hit or not. */ @@ -2028,20 +1744,10 @@ if (baseAsset === bot.market.baseAsset) { if (takeProfit > candle.max) { takeProfit = candle.max - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.takeProfit = takeProfit - } - } } } else { if (takeProfit < candle.min) { takeProfit = candle.min - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.takeProfit = takeProfit - } - } } } @@ -2072,18 +1778,6 @@ closePositionNow = true; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.strategyStage = strategyStage; - yesterday.stopLossStage = stopLossStage; - yesterday.takeProfitStage = takeProfitStage; - - yesterday.currentTrade.end = currentTrade.end; - yesterday.currentTrade.status = currentTrade.status; - yesterday.currentTrade.exitType = currentTrade.exitType; - yesterday.currentTrade.endRate = currentTrade.endRate; - } - } } } @@ -2097,12 +1791,6 @@ /* Inicializing this counter */ distanceToLast.takePosition = 1; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.distanceToLast.takePosition = distanceToLast.takePosition - } - } - /* Position size and rate */ let strategy = tradingSystem.strategies[currentStrategyIndex]; @@ -2118,31 +1806,17 @@ tradePositionRate = tradePositionRate + slippageAmount } - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.tradePositionSize = tradePositionSize; - yesterday.tradePositionRate = tradePositionRate; - } - } - /* Update the trade record information. */ currentTrade.begin = candle.begin; currentTrade.beginRate = tradePositionRate; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.currentTrade.begin = currentTrade.begin; - yesterday.currentTrade.beginRate = currentTrade.beginRate; - } - } - /* Check if we need to execute. */ if (currentCandleIndex > candles.length - 10) { /* Only at the last candles makes sense to check if we are in live mode or not.*/ /* Check that we are in LIVE MODE */ if (bot.startMode === "Live") { /* We see if we need to put the actual order at the exchange. */ - if (interExecutionMemory.executionContext !== undefined) { - switch (interExecutionMemory.executionContext.status) { + if (variable.executionContext !== undefined) { + switch (variable.executionContext.status) { case "Without a Position": { // We need to put the order because It was not put yet. if (strategy.openStage !== undefined) { if (strategy.openStage.openExecution !== undefined) { @@ -2211,9 +1885,9 @@ } /* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */ - if (interExecutionMemory.executionContext !== undefined) { - if (interExecutionMemory.executionContext.periods !== undefined) { - if (periods <= interExecutionMemory.executionContext.periods) { + if (variable.executionContext !== undefined) { + if (variable.executionContext.periods !== undefined) { + if (periods <= variable.executionContext.periods) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because it was already placed at a previous execution."); } takePositionAtSimulation() return; @@ -2258,7 +1932,7 @@ } - interExecutionMemory.executionContext = { + variable.executionContext = { status: "Taking Position", periods: periods, } @@ -2273,7 +1947,7 @@ switch (err.result) { case global.DEFAULT_OK_RESPONSE.result: { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_OK_RESPONSE "); } - interExecutionMemory.executionContext = { + variable.executionContext = { status: "In a Position", periods: periods, amountA: amountA, @@ -2322,13 +1996,6 @@ previousBalanceBaseAsset = balanceBaseAsset; previousBalanceQuotedAsset = balanceQuotedAsset; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.previousBalanceBaseAsset = previousBalanceBaseAsset; - yesterday.previousBalanceQuotedAsset = previousBalanceQuotedAsset; - } - } - lastTradeProfitLoss = 0; lastTradeROI = 0; @@ -2348,16 +2015,6 @@ balanceQuotedAsset = balanceQuotedAsset - tradePositionSize; } - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.balanceBaseAsset = balanceBaseAsset; - yesterday.balanceQuotedAsset = balanceQuotedAsset; - - yesterday.lastTradeProfitLoss = lastTradeProfitLoss; - yesterday.lastTradeROI = lastTradeROI; - } - } - addRecord(); if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionAtSimulation -> Exiting Loop Body after taking position at simulation."); } controlLoop(); @@ -2374,12 +2031,6 @@ /* Inicializing this counter */ distanceToLast.closePosition = 1; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.distanceToLast.closePosition = distanceToLast.closePosition - } - } - /* Position size and rate */ let strategy = tradingSystem.strategies[currentStrategyIndex]; @@ -2387,8 +2038,8 @@ /* Check that we are in LIVE MODE */ if (bot.startMode === "Live") { /* We see if we need to put the actual order at the exchange. */ - if (interExecutionMemory.executionContext !== undefined) { - switch (interExecutionMemory.executionContext.status) { + if (variable.executionContext !== undefined) { + switch (variable.executionContext.status) { case "Without a Position": { // No way to close anything at the exchange. if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing a Position -> Exiting code block because status is Without a Position."); } break @@ -2431,9 +2082,9 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> Entering function."); } /* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */ - if (interExecutionMemory.executionContext !== undefined) { - if (interExecutionMemory.executionContext.periods !== undefined) { - if (periods <= interExecutionMemory.executionContext.periods) { + if (variable.executionContext !== undefined) { + if (variable.executionContext.periods !== undefined) { + if (periods <= variable.executionContext.periods) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> Exiting function because this closing was already submited at a previous execution."); } closePositionAtSimulation() return; @@ -2464,7 +2115,7 @@ } - interExecutionMemory.executionContext = { + variable.executionContext = { status: "Closing Position", periods: periods, } @@ -2479,7 +2130,7 @@ switch (err.result) { case global.DEFAULT_OK_RESPONSE.result: { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> DEFAULT_OK_RESPONSE "); } - interExecutionMemory.executionContext = { + variable.executionContext = { status: "Position Closed", periods: periods, amountA: amountA, @@ -2520,12 +2171,6 @@ roundtrips++; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.roundtrips = roundtrips - } - } - let feePaid = 0 if (baseAsset === bot.market.baseAsset) { @@ -2546,14 +2191,6 @@ balanceBaseAsset = 0; } - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.balanceBaseAsset = balanceBaseAsset; - yesterday.balanceQuotedAsset = balanceQuotedAsset; - - } - } - if (baseAsset === bot.market.baseAsset) { lastTradeProfitLoss = balanceBaseAsset - previousBalanceBaseAsset; lastTradeROI = lastTradeProfitLoss * 100 / tradePositionSize; @@ -2566,39 +2203,12 @@ profit = balanceQuotedAsset - bot.VALUES_TO_USE.initialBalanceB; } - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.lastTradeProfitLoss = lastTradeProfitLoss; - yesterday.profit = profit; - yesterday.lastTradeROI = lastTradeROI; - } - } - currentTrade.lastTradeROI = lastTradeROI; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.currentTrade.lastTradeROI = currentTrade.lastTradeROI; - } - } - if (lastTradeProfitLoss > 0) { hits++; - - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.hits = hits - } - } - } else { fails++; - - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.fails = fails - } - } } if (baseAsset === bot.market.baseAsset) { @@ -2611,54 +2221,20 @@ anualizedRateOfReturn = ROI / days * 365; } - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.ROI = ROI; - yesterday.hitRatio = hitRatio; - yesterday.anualizedRateOfReturn = anualizedRateOfReturn; - } - } - addRecord(); stopLoss = 0; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.stopLoss = stopLoss - } - } takeProfit = 0; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.takeProfit = takeProfit - } - } tradePositionRate = 0; tradePositionSize = 0; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.tradePositionSize = tradePositionSize; - yesterday.tradePositionRate = tradePositionRate; - } - } - timerToCloseStage = candle.begin stopLossStage = 'No Stage'; takeProfitStage = 'No Stage'; stopLossPhase = -1; takeProfitPhase = -1; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.stopLossStage = stopLossStage; - yesterday.takeProfitStage = takeProfitStage; - yesterday.stopLossPhase = stopLossPhase; - yesterday.takeProfitPhase = takeProfitPhase; - } - } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> closePositionAtSimulation -> Exiting Loop Body after closing position at simulation."); } controlLoop(); return @@ -2674,36 +2250,12 @@ currentStrategy.endRate = candle.min; currentStrategy.status = 1; // This means the strategy is closed, i.e. that has a begin and end. - if (processingDailyFiles) { - if (positionedAtYesterday) { - - yesterday.currentStrategy.number = currentStrategy.number; - yesterday.currentStrategy.end = currentStrategy.end; - yesterday.currentStrategy.endRate = currentStrategy.endRate; - yesterday.currentStrategy.status = currentStrategy.status; - } - } - currentStrategyIndex = -1; strategyStage = 'No Stage'; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.currentStrategyIndex = currentStrategyIndex; - yesterday.strategyStage = strategyStage; - } - } - timerToCloseStage = 0 - distanceToLast.triggerOff = 1; - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.distanceToLast.triggerOff = distanceToLast.triggerOff - } - } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing the Closing Stage -> Exiting Close Stage."); } } else { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing the Closing Stage -> Waiting for timer."); } @@ -2847,20 +2399,6 @@ endRate: 0, triggerOnSituation: '' } - - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.currentStrategy = { - begin: 0, - end: 0, - status: 0, - number: 0, - beginRate: 0, - endRate: 0, - triggerOnSituation: '' - } - } - } } /* @@ -2897,21 +2435,6 @@ endRate: 0, takePositionSituation: '' } - - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.currentTrade = { - begin: 0, - end: 0, - status: 0, - lastTradeROI: 0, - exitType: 0, - beginRate: 0, - endRate: 0, - takePositionSituation: '' - } - } - } } makeAnnoucements() // After everything at the simulation level was done, we will do the annoucements that are pending. @@ -2932,8 +2455,8 @@ let lastPeriodAnnounced = -1 let newAnnouncementRecord = {} - for (let j = 0; j < interExecutionMemory.announcements.length; j++) { - let announcementRecord = interExecutionMemory.announcements[j] + for (let j = 0; j < variable.announcements.length; j++) { + let announcementRecord = variable.announcements[j] if (announcementRecord.key === key) { lastPeriodAnnounced = announcementRecord.periods newAnnouncementRecord = announcementRecord @@ -2977,7 +2500,7 @@ periods: periods, value: value } - interExecutionMemory.announcements.push(newAnnouncementRecord) + variable.announcements.push(newAnnouncementRecord) } } } @@ -3039,79 +2562,10 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> afterLoop -> Entering function."); } /* - Before returning we need to see if we have to record some of our counters at the interExecutionMemory. + Before returning we need to see if we have to record some of our counters at the variable. To do that, the condition to be met is that this execution must include all candles of the current day. */ - if (processingDailyFiles) { - - if (lastCandle.end === lastInstantOfTheDay) { - - interExecutionMemory.stopLoss = yesterday.stopLoss - interExecutionMemory.takeProfit = yesterday.takeProfit - - interExecutionMemory.previousBalanceBaseAsset = yesterday.previousBalanceBaseAsset - interExecutionMemory.previousBalanceQuotedAsset = yesterday.previousBalanceQuotedAsset - - interExecutionMemory.tradePositionRate = yesterday.tradePositionRate - interExecutionMemory.tradePositionSize = yesterday.tradePositionSize - - interExecutionMemory.currentStrategyIndex = yesterday.currentStrategyIndex - interExecutionMemory.strategyStage = yesterday.strategyStage - - interExecutionMemory.stopLossPhase = yesterday.stopLossPhase - interExecutionMemory.stopLossStage = yesterday.stopLossStage - - interExecutionMemory.takeProfitPhase = yesterday.takeProfitPhase - interExecutionMemory.takeProfitStage = yesterday.takeProfitStage - - interExecutionMemory.currentStrategy = { - begin: yesterday.currentStrategy.begin, - end: yesterday.currentStrategy.end, - status: yesterday.currentStrategy.status, - number: yesterday.currentStrategy.number, - beginRate: yesterday.currentStrategy.beginRate, - endRate: yesterday.currentStrategy.endRate, - triggerOnSituation: yesterday.currentStrategy.triggerOnSituation - } - - interExecutionMemory.currentTrade = { - begin: yesterday.currentTrade.begin, - end: yesterday.currentTrade.end, - status: yesterday.currentTrade.status, - profit: yesterday.currentTrade.profit, - exitType: yesterday.currentTrade.exitType, - beginRate: yesterday.currentTrade.beginRate, - endRate: yesterday.currentTrade.endRate, - takePositionSituation: yesterday.currentTrade.takePositionSituation - } - - interExecutionMemory.balanceBaseAsset = yesterday.balanceBaseAsset; - interExecutionMemory.balanceQuotedAsset = yesterday.balanceQuotedAsset; - interExecutionMemory.lastTradeProfitLoss = yesterday.lastTradeProfitLoss; - interExecutionMemory.profit = yesterday.profit; - interExecutionMemory.lastTradeROI = yesterday.lastTradeROI; - - interExecutionMemory.roundtrips = yesterday.roundtrips; - interExecutionMemory.fails = yesterday.fails; - interExecutionMemory.hits = yesterday.hits; - interExecutionMemory.periods = yesterday.periods; - interExecutionMemory.positionPeriods = yesterday.positionPeriods; - - interExecutionMemory.distanceToLast.triggerOn = yesterday.distanceToLast.triggerOn - interExecutionMemory.distanceToLast.triggerOff = yesterday.distanceToLast.triggerOff - interExecutionMemory.distanceToLast.takePosition = yesterday.distanceToLast.takePosition - interExecutionMemory.distanceToLast.closePosition = yesterday.distanceToLast.closePosition - - interExecutionMemory.messageId = interExecutionMemory.messageId + yesterday.messageId; - interExecutionMemory.orderId = interExecutionMemory.orderId + yesterday.orderId; - - interExecutionMemory.hitRatio = yesterday.hitRatio; - interExecutionMemory.ROI = yesterday.ROI; - interExecutionMemory.anualizedRateOfReturn = yesterday.anualizedRateOfReturn; - } - } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> callback -> recordsArray.length = " + recordsArray.length); } callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, tradesArray); From d793ddbe6d40fdc66e2878707e9fe8ee21d91b50 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 19 May 2020 12:20:09 +0200 Subject: [PATCH 13/44] variable refactoring --- MultiPeriod.js | 12 ++++++------ TradingBot.js | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/MultiPeriod.js b/MultiPeriod.js index 217e49077..939d30a50 100644 --- a/MultiPeriod.js +++ b/MultiPeriod.js @@ -86,7 +86,7 @@ let previousDay; // Holds the date of the previous day relative to the processing date. - let interExecutionMemoryArray = []; + let variableArray = []; getContextVariables(); @@ -177,7 +177,7 @@ } contextVariables.lastFile = new Date(thisReport.lastFile); - interExecutionMemoryArray = thisReport.interExecutionMemoryArray; + variableArray = thisReport.variableArray; processSingleFiles(); return; @@ -203,11 +203,11 @@ This data structure has one object per each timeFrame. */ - interExecutionMemoryArray = []; + variableArray = []; for (let i = 0; i < global.dailyFilePeriods.length; i++) { let emptyObject = {}; - interExecutionMemoryArray.push(emptyObject); + variableArray.push(emptyObject); } processSingleFiles(); @@ -942,7 +942,7 @@ currentTimeFrame, currentTimeFrameLabel, bot.multiPeriodProcessDatetime, - interExecutionMemoryArray[n], + variableArray[n], onBotFinished); function onBotFinished(err) { @@ -1135,7 +1135,7 @@ thisReport.file.lastExecution = bot.currentDaytime; thisReport.file.lastFile = lastFileDate; - thisReport.file.interExecutionMemoryArray = interExecutionMemoryArray; + thisReport.file.variableArray = variableArray; thisReport.save(callBack); bot.hasTheBotJustStarted = false; diff --git a/TradingBot.js b/TradingBot.js index 1a2852487..b7e99da99 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -47,7 +47,7 @@ } } - function start(multiPeriodDataFiles, timeFrame, timeFrameLabel, currentDay, interExecutionMemory, callBackFunction) { + function start(multiPeriodDataFiles, timeFrame, timeFrameLabel, currentDay, variable, callBackFunction) { try { @@ -137,7 +137,7 @@ timeFrame, timeFrameLabel, currentDay, - interExecutionMemory, + variable, exchangeAPI, writeFiles, callBackFunction) From 8409b2c9ec13f4abc004e8c173fa5fb39eb9cc60 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 19 May 2020 13:37:46 +0200 Subject: [PATCH 14/44] Cleaning variables not used --- TradingBot.js | 128 +------------------ TradingSimulation.js | 297 ++++++++----------------------------------- 2 files changed, 52 insertions(+), 373 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index b7e99da99..c78342afe 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -158,7 +158,7 @@ } function writeMarketFiles() { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> Entering function."); } writeRecordsFile(); @@ -180,8 +180,6 @@ fileContent = fileContent + separator + '[' + record.begin + "," + record.end + "," + - record.type + "," + - record.marketRate + "," + record.amount + "," + record.balanceA + "," + record.balanceB + "," + @@ -496,127 +494,6 @@ writeRecordsFile(); - /* TODO : NEXT function is a work in progress, not used today */ - function writeFinalResults() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeFinalResults -> Entering function."); } - - if ( // We only write this file if we are at the head of the market. - Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS - !== - Math.trunc((new Date()).valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS - ) { - writeRecordsFile(); - return; - } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < recordsArray.length; i++) { - - let record = recordsArray[i]; - - /* Will only add to the file the records of the current day */ - - if (record.begin < currentDay.valueOf()) { continue; } - - fileContent = fileContent + separator + '[' + - record.begin + "," + - record.end + "," + - record.type + "," + - record.marketRate + "," + - record.amount + "," + - record.balanceA + "," + - record.balanceB + "," + - record.profit + "," + - record.lastTradeProfitLoss + "," + - record.stopLoss + "," + - record.roundtrips + "," + - record.hits + "," + - record.fails + "," + - record.hitRatio + "," + - record.ROI + "," + - record.periods + "," + - record.days + "," + - record.anualizedRateOfReturn + "," + - record.positionRate + "," + - record.lastTradeROI + "," + - record.strategy + "," + - record.strategyStageNumber + "," + - record.takeProfit + "," + - record.stopLossPhase + "," + - record.takeProfitPhase + "," + - JSON.stringify(record.executionRecord) + "," + - record.positionSize + "," + - record.initialBalanceA + "," + - record.minimumBalanceA + "," + - record.maximumBalanceA + "," + - record.initialBalanceB + "," + - record.minimumBalanceB + "," + - record.maximumBalanceB + "," + - record.baseAsset + "," + - record.quotedAsset + "," + - record.marketBaseAsset + "," + - record.marketQuotedAsset + "," + - record.positionPeriods + "," + - record.positionDays + "," + - record.distanceToLastTriggerOn + "," + - record.distanceToLastTriggerOff + "," + - record.distanceToLastTakePosition + "," + - record.distanceToLastClosePosition + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let fileName = 'Data.json'; - let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timeFrameLabel; - filePath += '/' + fileName - - fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> market = " + market.baseAsset + "_" + market.quotedAsset); - - callBackFunction(err); - return; - - } - - writeRecordsFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - function writeRecordsFile() { try { @@ -639,8 +516,6 @@ fileContent = fileContent + separator + '[' + record.begin + "," + record.end + "," + - record.type + "," + - record.marketRate + "," + record.amount + "," + record.balanceA + "," + record.balanceB + "," + @@ -662,7 +537,6 @@ record.takeProfit + "," + record.stopLossPhase + "," + record.takeProfitPhase + "," + - JSON.stringify(record.executionRecord) + "," + record.positionSize + "," + record.initialBalanceA + "," + record.minimumBalanceA + "," + diff --git a/TradingSimulation.js b/TradingSimulation.js index f17d2e43c..fb32a3123 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -48,157 +48,51 @@ let tradingSystem = bot.TRADING_SYSTEM /* Initial Default Values */ - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> bot.VALUES_TO_USE.timeRange.initialDatetime = " + bot.VALUES_TO_USE.timeRange.initialDatetime); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> bot.VALUES_TO_USE.timeRange.finalDatetime = " + bot.VALUES_TO_USE.timeRange.finalDatetime); } let timerToCloseStage = 0 /* Stop Loss Management */ - const MIN_STOP_LOSS_VALUE = 1 // We can not let the stop be zero to avoid division by 0 error or infinity numbers as a result. const MAX_STOP_LOSS_VALUE = Number.MAX_SAFE_INTEGER - let stopLoss = 0; /* Take Profit Management */ - const MIN_TAKE_PROFIT_VALUE = 1 // We can not let the buy order be zero to avoid division by 0 error or infinity numbers as a result. const MAX_TAKE_PROFIT_VALUE = Number.MAX_SAFE_INTEGER - let takeProfit = 0; - /* Simulation Records */ - - let hitRatio = 0; - let ROI = 0; - let days = 0; - let positionDays = 0; - let anualizedRateOfReturn = 0; - let type = '""'; - let marketRate = 0; + /* Variables for this executioin only */ let takePositionNow = false let closePositionNow = false /* In some cases we need to know if we are positioned at the last candle of the calendar day, for that we need these variables. */ - let lastInstantOfTheDay = 0 if (currentDay) { lastInstantOfTheDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1; } - /* - The following counters need to survive multiple executions of the similator and keep themselves reliable. - This is challenging when the simulation is executed using Daily Files, since each execution means a new - day and these counters are meant to be kept along the whole market. + if (variable.isInitialized !== true) { - To overcome this problem, we use the variable to record the values of the current execution - when finish. But there are a few details: - - 1. When the process is at the head of the market, it executes multple times at the same day. - 2. The same code serves execution from Market Files. - 3. In Daily Files we are receiving candles from the current day and previous day, so we need to take care of - not adding to the counters duplicate info when processing the day before candles. - - To overcome these challenges we record the values of the counters and variables on the variable only when - the day is complete and if we have a current Day. That menas that for Market Files we will never use - variable. - */ - - /*Needed for statistics */ - let previousBalanceBaseAsset = 0; - let previousBalanceQuotedAsset = 0; - - /* Position Management */ - let tradePositionRate = 0; - let tradePositionSize = 0; - - /* Strategy and Phase Management */ - let currentStrategyIndex = -1; - let strategyStage = 'No Stage'; - - let stopLossPhase = -1; - let stopLossStage = 'No Stage'; - - let takeProfitPhase = -1; - let takeProfitStage = 'No Stage'; - - /* These 2 objects will allow us to create separate files for each one of them. */ - - let currentStrategy = { - begin: 0, - end: 0, - status: 0, - number: 0, - beginRate: 0, - endRate: 0, - triggerOnSituation: '' - } - - let currentTrade = { - begin: 0, - end: 0, - status: 0, - profit: 0, - exitType: 0, - beginRate: 0, - endRate: 0, - takePositionSituation: '' - } - - let balanceBaseAsset = bot.VALUES_TO_USE.initialBalanceA; - let balanceQuotedAsset = bot.VALUES_TO_USE.initialBalanceB; - - let lastTradeProfitLoss = 0; - let profit = 0; - let lastTradeROI = 0; - - let roundtrips = 0; - let fails = 0; - let hits = 0; - let periods = 0; - let positionPeriods = 0; - - let closeRate - - /* Usefull counters for conditions and formulas */ - - let distanceToLast = { - triggerOn: 0, - triggerOff: 0, - takePosition: 0, - closePosition: 0 - } - - /* Message to the Simulation Executor */ - - let orderId = 0; - let messageId = 0; - - /* Allowing these to be accesible at formulas */ - baseAsset = bot.VALUES_TO_USE.baseAsset - quotedAsset = bot.VALUES_TO_USE.quotedAsset - - - if (variable.roundtrips === undefined) { // This just means that the inter execution memory was never used before. - - /* Initialize the data structure we will use inter execution. */ + variable.isInitialized = true variable.stopLoss = 0 variable.takeProfit = 0 - variable.previousBalanceBaseAsset = previousBalanceBaseAsset - variable.previousBalanceQuotedAsset = previousBalanceQuotedAsset + /*Needed for statistics */ + variable.previousBalanceBaseAsset = 0 + variable.previousBalanceQuotedAsset = 0 - variable.tradePositionRate = tradePositionRate - variable.tradePositionSize = tradePositionSize + /* Position Management */ + variable.tradePositionRate = 0 + variable.tradePositionSize = 0 - variable.currentStrategyIndex = currentStrategyIndex - variable.strategyStage = strategyStage - - variable.stopLossPhase = stopLossPhase - variable.stopLossStage = stopLossStage - - variable.takeProfitPhase = takeProfitPhase - variable.takeProfitStage = takeProfitStage + /* Strategy and Phase Management */ + variable.strategyIndex = -1 + variable.strategyStage = 'No Stage' + variable.stopLossPhase = -1 + variable.stopLossStage = 'No Stage' + variable.takeProfitPhase = -1 + variable.takeProfitStage = 'No Stage' variable.currentStrategy = { begin: 0, @@ -221,12 +115,12 @@ takePositionSituation: '' } - variable.balanceBaseAsset = balanceBaseAsset; - variable.balanceQuotedAsset = balanceQuotedAsset; + variable.balanceBaseAsset = bot.VALUES_TO_USE.initialBalanceA + variable.balanceQuotedAsset = bot.VALUES_TO_USE.initialBalanceB - variable.lastTradeProfitLoss = lastTradeProfitLoss; - variable.profit = profit; - variable.lastTradeROI = lastTradeROI; + variable.lastTradeProfitLoss = 0 + variable.profit = 0 + variable.lastTradeROI = 0 variable.roundtrips = 0; variable.fails = 0; @@ -234,6 +128,7 @@ variable.periods = 0; variable.positionPeriods = 0; + /* Usefull counters for conditions and formulas */ variable.distanceToLast = { triggerOn: 0, triggerOff: 0, @@ -241,93 +136,18 @@ closePosition: 0 } - variable.orderId = 0; - variable.messageId = 0; - variable.hitRatio = 0; variable.ROI = 0; variable.anualizedRateOfReturn = 0; variable.announcements = [] - } else { - - /* We get the initial values from the day previous to the candles we receive at the current execution */ - - stopLoss = variable.stopLoss - takeProfit = variable.takeProfit - - previousBalanceBaseAsset = variable.previousBalanceBaseAsset - previousBalanceQuotedAsset = variable.previousBalanceQuotedAsset - - tradePositionRate = variable.tradePositionRate - tradePositionSize = variable.tradePositionSize - - currentStrategyIndex = variable.currentStrategyIndex - strategyStage = variable.strategyStage - - stopLossPhase = variable.stopLossPhase - stopLossStage = variable.stopLossStage - - takeProfitPhase = variable.takeProfitPhase - takeProfitStage = variable.takeProfitStage - - currentStrategy = { - begin: variable.currentStrategy.begin, - end: variable.currentStrategy.end, - status: variable.currentStrategy.status, - number: variable.currentStrategy.number, - beginRate: variable.currentStrategy.beginRate, - endRate: variable.currentStrategy.endRate, - triggerOnSituation: variable.currentStrategy.triggerOnSituation - } - - currentTrade = { - begin: variable.currentTrade.begin, - end: variable.currentTrade.end, - status: variable.currentTrade.status, - profit: variable.currentTrade.profit, - exitType: variable.currentTrade.exitType, - beginRate: variable.currentTrade.beginRate, - endRate: variable.currentTrade.endRate, - takePositionSituation: variable.currentTrade.takePositionSituation - } - - if (currentDay) { - if (currentDay.valueOf() >= bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf() + ONE_DAY_IN_MILISECONDS) { // Only after the first day we start grabbing the balance from this memory. - - balanceBaseAsset = variable.balanceBaseAsset; - balanceQuotedAsset = variable.balanceQuotedAsset; - - } - } - - lastTradeProfitLoss = variable.lastTradeProfitLoss; - profit = variable.profit; - lastTradeROI = variable.lastTradeROI; - - roundtrips = variable.roundtrips; - fails = variable.fails; - hits = variable.hits; - periods = variable.periods; - positionPeriods = variable.positionPeriods; - - distanceToLast.triggerOn = variable.distanceToLast.triggerOn - distanceToLast.triggerOff = variable.distanceToLast.triggerOff - distanceToLast.takePosition = variable.distanceToLast.takePosition - distanceToLast.closePosition = variable.distanceToLast.closePosition - - orderId = variable.orderId; // to be deprecated - messageId = variable.messageId; // to be deprecated - - hitRatio = variable.hitRatio; - ROI = variable.ROI; - anualizedRateOfReturn = variable.anualizedRateOfReturn; - - } + /* Allowing these to be accesible at formulas */ + variable.baseAsset = bot.VALUES_TO_USE.baseAsset + variable.quotedAsset = bot.VALUES_TO_USE.quotedAsset + } /* Main Array and Maps */ - let propertyName = 'at' + timeFrameLabel.replace('-', ''); let candles = chart[propertyName].candles let currentChart = chart[propertyName] @@ -1084,7 +904,7 @@ /* Trigger On Conditions */ if ( strategyStage === 'No Stage' && - currentStrategyIndex === -1 + strategyIndex === -1 ) { let minimumBalance let maximumBalance @@ -1159,7 +979,7 @@ strategyStage = 'Trigger Stage'; checkAnnouncements(triggerStage) - currentStrategyIndex = j; + strategyIndex = j; currentStrategy.begin = candle.begin; currentStrategy.beginRate = candle.min; currentStrategy.endRate = candle.min; // In case the strategy does not get exited @@ -1182,7 +1002,7 @@ /* Trigger Off Condition */ if (strategyStage === 'Trigger Stage') { - let strategy = tradingSystem.strategies[currentStrategyIndex]; + let strategy = tradingSystem.strategies[strategyIndex]; let triggerStage = strategy.triggerStage @@ -1198,7 +1018,7 @@ for (let m = 0; m < situation.conditions.length; m++) { let condition = situation.conditions[m]; - let key = currentStrategyIndex + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; + let key = strategyIndex + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; let value = false if (conditions.get(key) !== undefined) { @@ -1210,12 +1030,12 @@ if (passed) { - currentStrategy.number = currentStrategyIndex + currentStrategy.number = strategyIndex currentStrategy.end = candle.end; currentStrategy.endRate = candle.min; currentStrategy.status = 1; // This means the strategy is closed, i.e. that has a begin and end. strategyStage = 'No Stage'; - currentStrategyIndex = -1; + strategyIndex = -1; distanceToLast.triggerOff = 1; @@ -1232,7 +1052,7 @@ /* Take Position Condition */ if (strategyStage === 'Trigger Stage') { - let strategy = tradingSystem.strategies[currentStrategyIndex]; + let strategy = tradingSystem.strategies[strategyIndex]; let triggerStage = strategy.triggerStage @@ -1248,7 +1068,7 @@ for (let m = 0; m < situation.conditions.length; m++) { let condition = situation.conditions[m]; - let key = currentStrategyIndex + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; + let key = strategyIndex + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; let value = false if (conditions.get(key) !== undefined) { @@ -1260,8 +1080,6 @@ if (passed) { - type = '"Take Position"'; - strategyStage = 'Open Stage'; checkAnnouncements(strategy.openStage) @@ -1296,12 +1114,12 @@ function checkStopPhases() { - let strategy = tradingSystem.strategies[currentStrategyIndex]; + let strategy = tradingSystem.strategies[strategyIndex]; let openStage = strategy.openStage let manageStage = strategy.manageStage let parentNode - let j = currentStrategyIndex + let j = strategyIndex let stageKey let initialDefinitionKey = '' let p @@ -1419,7 +1237,7 @@ function calculateStopLoss() { - let strategy = tradingSystem.strategies[currentStrategyIndex]; + let strategy = tradingSystem.strategies[strategyIndex]; let openStage = strategy.openStage let manageStage = strategy.manageStage let phase @@ -1429,7 +1247,7 @@ if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.stopLoss !== undefined) { phase = openStage.initialDefinition.stopLoss.phases[stopLossPhase]; - key = currentStrategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + (stopLossPhase); + key = strategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + (stopLossPhase); } } } @@ -1437,7 +1255,7 @@ if (stopLossStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.stopLoss !== undefined) { phase = manageStage.stopLoss.phases[stopLossPhase - 1]; - key = currentStrategyIndex + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + (stopLossPhase - 1); + key = strategyIndex + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + (stopLossPhase - 1); } } @@ -1467,12 +1285,12 @@ function checkTakeProfitPhases() { - let strategy = tradingSystem.strategies[currentStrategyIndex]; + let strategy = tradingSystem.strategies[strategyIndex]; let openStage = strategy.openStage let manageStage = strategy.manageStage let parentNode - let j = currentStrategyIndex + let j = strategyIndex let stageKey let initialDefinitionKey = '' let p @@ -1591,7 +1409,7 @@ function calculateTakeProfit() { - let strategy = tradingSystem.strategies[currentStrategyIndex]; + let strategy = tradingSystem.strategies[strategyIndex]; let openStage = strategy.openStage let manageStage = strategy.manageStage let phase @@ -1601,7 +1419,7 @@ if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.takeProfit !== undefined) { phase = openStage.initialDefinition.takeProfit.phases[takeProfitPhase]; - key = currentStrategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + (takeProfitPhase); + key = strategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + (takeProfitPhase); } } } @@ -1609,7 +1427,7 @@ if (takeProfitStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.takeProfit !== undefined) { phase = manageStage.takeProfit.phases[takeProfitPhase - 1]; - key = currentStrategyIndex + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 1); + key = strategyIndex + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 1); } } @@ -1674,7 +1492,7 @@ (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') && takePositionNow !== true ) { - let strategy = tradingSystem.strategies[currentStrategyIndex]; + let strategy = tradingSystem.strategies[strategyIndex]; /* Checking what happened since the last execution. We need to know if the Stop Loss or our Take Profit were hit. */ @@ -1714,8 +1532,6 @@ closeRate = slippedStopLoss; - marketRate = closeRate; - type = '"Close@StopLoss"'; strategyStage = 'Close Stage'; checkAnnouncements(strategy.closeStage, 'Stop') @@ -1763,8 +1579,6 @@ closeRate = slippedTakeProfit; - marketRate = closeRate; - type = '"Close@TakeProfit"'; strategyStage = 'Close Stage'; checkAnnouncements(strategy.closeStage, 'Take Profit') @@ -1792,7 +1606,7 @@ distanceToLast.takePosition = 1; /* Position size and rate */ - let strategy = tradingSystem.strategies[currentStrategyIndex]; + let strategy = tradingSystem.strategies[strategyIndex]; tradePositionSize = strategy.positionSize; tradePositionRate = strategy.positionRate; @@ -1991,8 +1805,6 @@ calculateTakeProfit(); calculateStopLoss(); - marketRate = candle.close; - previousBalanceBaseAsset = balanceBaseAsset; previousBalanceQuotedAsset = balanceQuotedAsset; @@ -2032,7 +1844,7 @@ distanceToLast.closePosition = 1; /* Position size and rate */ - let strategy = tradingSystem.strategies[currentStrategyIndex]; + let strategy = tradingSystem.strategies[strategyIndex]; if (currentCandleIndex > candles.length - 10) { /* Only at the last candles makes sense to check if we are in live mode or not.*/ /* Check that we are in LIVE MODE */ @@ -2245,12 +2057,12 @@ if (strategyStage === 'Close Stage') { if (candle.begin - 5 * 60 * 1000 > timerToCloseStage) { - currentStrategy.number = currentStrategyIndex + currentStrategy.number = strategyIndex currentStrategy.end = candle.end; currentStrategy.endRate = candle.min; currentStrategy.status = 1; // This means the strategy is closed, i.e. that has a begin and end. - currentStrategyIndex = -1; + strategyIndex = -1; strategyStage = 'No Stage'; timerToCloseStage = 0 @@ -2264,7 +2076,6 @@ /* Not a buy or sell condition */ - marketRate = candle.close; addRecord(); if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Exiting Loop Body after adding a record."); } controlLoop(); @@ -2277,7 +2088,6 @@ let messageType; let message; let simulationRecord; - let executionRecord; let strategyStageNumber switch (strategyStage) { @@ -2317,8 +2127,6 @@ simulationRecord = { begin: candle.begin, end: candle.end, - type: type, - marketRate: marketRate, amount: 1, balanceA: balanceBaseAsset, balanceB: balanceQuotedAsset, @@ -2335,12 +2143,11 @@ anualizedRateOfReturn: anualizedRateOfReturn, positionRate: tradePositionRate, lastTradeROI: lastTradeROI, - strategy: currentStrategyIndex, + strategy: strategyIndex, strategyStageNumber: strategyStageNumber, takeProfit: takeProfit, stopLossPhase: stopLossPhase, takeProfitPhase: takeProfitPhase, - executionRecord: '', positionSize: tradePositionSize, initialBalanceA: bot.VALUES_TO_USE.initialBalanceA, minimumBalanceA: bot.VALUES_TO_USE.minimumBalanceA, @@ -2362,11 +2169,9 @@ recordsArray.push(simulationRecord); - type = '""'; - /* Prepare the information for the Conditions File */ - conditionsArrayRecord.push(currentStrategyIndex); + conditionsArrayRecord.push(strategyIndex); conditionsArrayRecord.push(strategyStageNumber); conditionsArrayRecord.push(stopLossPhase); conditionsArrayRecord.push(takeProfitPhase); From 2153b0dbc7ff98796f22b9d74fe062d1a4ee37b5 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 19 May 2020 13:45:40 +0200 Subject: [PATCH 15/44] adding .variable --- TradingSimulation.js | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index fb32a3123..db8a57863 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -73,7 +73,7 @@ if (variable.isInitialized !== true) { - variable.isInitialized = true + variable.isInitialized = true variable.stopLoss = 0 variable.takeProfit = 0 @@ -1261,12 +1261,12 @@ if (phase !== undefined) { if (phase.formula !== undefined) { - let previousValue = stopLoss + let previousValue = variable.stopLoss - stopLoss = formulas.get(key) + variable.stopLoss = formulas.get(key) if (stopLoss !== previousValue) { - checkAnnouncements(phase, stopLoss) + checkAnnouncements(phase, variable.stopLoss) } } } @@ -1434,12 +1434,12 @@ if (phase !== undefined) { if (phase.formula !== undefined) { - let previousValue = stopLoss + let previousValue = variable.stopLoss - takeProfit = formulas.get(key) + variable.takeProfit = formulas.get(key) if (takeProfit !== previousValue) { - checkAnnouncements(phase, takeProfit) + checkAnnouncements(phase, variable.takeProfit) } } } @@ -1499,7 +1499,7 @@ /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - if ((baseAsset === bot.market.baseAsset && candle.max >= stopLoss) || (baseAsset !== bot.market.baseAsset && candle.min <= stopLoss)) { + if ((baseAsset === bot.market.baseAsset && candle.max >= variable.stopLoss) || (baseAsset !== bot.market.baseAsset && candle.min <= variable.stopLoss)) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Stop Loss was hit."); } /* @@ -1511,15 +1511,15 @@ if (baseAsset === bot.market.baseAsset) { if (stopLoss < candle.min) { - stopLoss = candle.min + variable.stopLoss = candle.min } } else { if (stopLoss > candle.max) { - stopLoss = candle.max + variable.stopLoss = candle.max } } - let slippedStopLoss = stopLoss + let slippedStopLoss = variable.stopLoss /* Apply the Slippage */ let slippageAmount = slippedStopLoss * bot.VALUES_TO_USE.slippage.stopLoss / 100 @@ -1547,7 +1547,7 @@ /* Take Profit condition: Here we verify if the Take Profit was hit or not. */ - if ((baseAsset === bot.market.baseAsset && candle.min <= takeProfit) || (baseAsset !== bot.market.baseAsset && candle.max >= takeProfit)) { + if ((baseAsset === bot.market.baseAsset && candle.min <= variable.takeProfit) || (baseAsset !== bot.market.baseAsset && candle.max >= variable.takeProfit)) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Take Profit was hit."); } /* @@ -1559,15 +1559,15 @@ if (baseAsset === bot.market.baseAsset) { if (takeProfit > candle.max) { - takeProfit = candle.max + variable.takeProfit = candle.max } } else { if (takeProfit < candle.min) { - takeProfit = candle.min + variable.takeProfit = candle.min } } - let slippedTakeProfit = takeProfit + let slippedTakeProfit = variable.takeProfit /* Apply the Slippage */ let slippageAmount = slippedTakeProfit * bot.VALUES_TO_USE.slippage.takeProfit / 100 @@ -2035,8 +2035,8 @@ addRecord(); - stopLoss = 0; - takeProfit = 0; + variable.stopLoss = 0; + variable.takeProfit = 0; tradePositionRate = 0; tradePositionSize = 0; @@ -2132,7 +2132,7 @@ balanceB: balanceQuotedAsset, profit: profit, lastTradeProfitLoss: lastTradeProfitLoss, - stopLoss: stopLoss, + stopLoss: variable.stopLoss, roundtrips: roundtrips, hits: hits, fails: fails, @@ -2145,7 +2145,7 @@ lastTradeROI: lastTradeROI, strategy: strategyIndex, strategyStageNumber: strategyStageNumber, - takeProfit: takeProfit, + takeProfit: variable.takeProfit, stopLossPhase: stopLossPhase, takeProfitPhase: takeProfitPhase, positionSize: tradePositionSize, From ba86ad360c3544d2c84f973b9c3ba8b277cea58f Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 19 May 2020 13:56:37 +0200 Subject: [PATCH 16/44] adding more variable. --- TradingSimulation.js | 176 +++++++++++++++++++++---------------------- 1 file changed, 88 insertions(+), 88 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index db8a57863..4a975b7c8 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -448,7 +448,7 @@ if (initialDefinition !== undefined) { if (tradePositionSize !== 0) { - positionSize = tradePositionSize + positionSize = variable.tradePositionSize } else { if (initialDefinition.positionSize !== undefined) { if (initialDefinition.positionSize.formula !== undefined) { @@ -475,7 +475,7 @@ } if (tradePositionRate !== 0) { - positionRate = tradePositionRate + positionRate = variable.tradePositionRate } else { if (initialDefinition.positionRate !== undefined) { if (initialDefinition.positionRate.formula !== undefined) { @@ -903,8 +903,8 @@ /* Trigger On Conditions */ if ( - strategyStage === 'No Stage' && - strategyIndex === -1 + variable.strategyStage === 'No Stage' && + variable.strategyIndex === -1 ) { let minimumBalance let maximumBalance @@ -976,10 +976,10 @@ if (passed) { - strategyStage = 'Trigger Stage'; + variable.strategyStage = 'Trigger Stage'; checkAnnouncements(triggerStage) - strategyIndex = j; + variable.strategyIndex = j; currentStrategy.begin = candle.begin; currentStrategy.beginRate = candle.min; currentStrategy.endRate = candle.min; // In case the strategy does not get exited @@ -1018,7 +1018,7 @@ for (let m = 0; m < situation.conditions.length; m++) { let condition = situation.conditions[m]; - let key = strategyIndex + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; + let key = variable.strategyIndex + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; let value = false if (conditions.get(key) !== undefined) { @@ -1030,12 +1030,12 @@ if (passed) { - currentStrategy.number = strategyIndex + currentStrategy.number = variable.strategyIndex currentStrategy.end = candle.end; currentStrategy.endRate = candle.min; currentStrategy.status = 1; // This means the strategy is closed, i.e. that has a begin and end. - strategyStage = 'No Stage'; - strategyIndex = -1; + variable.strategyStage = 'No Stage'; + variable.strategyIndex = -1; distanceToLast.triggerOff = 1; @@ -1068,7 +1068,7 @@ for (let m = 0; m < situation.conditions.length; m++) { let condition = situation.conditions[m]; - let key = strategyIndex + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; + let key = variable.strategyIndex + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; let value = false if (conditions.get(key) !== undefined) { @@ -1080,13 +1080,13 @@ if (passed) { - strategyStage = 'Open Stage'; + variable.strategyStage = 'Open Stage'; checkAnnouncements(strategy.openStage) - stopLossStage = 'Open Stage'; - takeProfitStage = 'Open Stage'; - stopLossPhase = 0; - takeProfitPhase = 0; + variable.stopLossStage = 'Open Stage'; + variable.takeProfitStage = 'Open Stage'; + variable.stopLossPhase = 0; + variable.takeProfitPhase = 0; takePositionNow = true currentTrade.takePositionSituation = situation.name @@ -1103,7 +1103,7 @@ /* Stop Loss Management */ if ( - (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') && + (strategyStage === 'Open Stage' || variable.strategyStage === 'Manage Stage') && takePositionNow !== true ) { @@ -1119,7 +1119,7 @@ let openStage = strategy.openStage let manageStage = strategy.manageStage let parentNode - let j = strategyIndex + let j = variable.strategyIndex let stageKey let initialDefinitionKey = '' let p @@ -1130,7 +1130,7 @@ parentNode = openStage.initialDefinition initialDefinitionKey = '-' + 'initialDefinition' stageKey = 'openStage' - p = stopLossPhase + p = variable.stopLossPhase } } } @@ -1139,7 +1139,7 @@ if (manageStage.stopLoss !== undefined) { parentNode = manageStage stageKey = 'manageStage' - p = stopLossPhase - 1 + p = variable.stopLossPhase - 1 } } @@ -1170,10 +1170,10 @@ if (passed) { - stopLossPhase++; - stopLossStage = 'Manage Stage' + variable.stopLossPhase++; + variable.stopLossStage = 'Manage Stage' if (takeProfitPhase > 0) { - strategyStage = 'Manage Stage' + variable.strategyStage = 'Manage Stage' checkAnnouncements(manageStage, 'Take Profit') } @@ -1212,7 +1212,7 @@ if (moveToPhase !== undefined) { for (let q = 0; q < parentNode.stopLoss.phases.length; q++) { if (parentNode.stopLoss.phases[q].id === moveToPhase.id) { - stopLossPhase = q + 1 + variable.stopLossPhase = q + 1 } } } else { @@ -1220,9 +1220,9 @@ continue } - stopLossStage = 'Manage Stage' + variable.stopLossStage = 'Manage Stage' if (takeProfitPhase > 0) { - strategyStage = 'Manage Stage' + variable.strategyStage = 'Manage Stage' checkAnnouncements(manageStage, 'Take Profit') } @@ -1247,7 +1247,7 @@ if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.stopLoss !== undefined) { phase = openStage.initialDefinition.stopLoss.phases[stopLossPhase]; - key = strategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + (stopLossPhase); + key = variable.strategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + (stopLossPhase); } } } @@ -1255,7 +1255,7 @@ if (stopLossStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.stopLoss !== undefined) { phase = manageStage.stopLoss.phases[stopLossPhase - 1]; - key = strategyIndex + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + (stopLossPhase - 1); + key = variable.strategyIndex + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + (stopLossPhase - 1); } } @@ -1274,7 +1274,7 @@ /* Take Profit Management */ if ( - (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') && + (strategyStage === 'Open Stage' || variable.strategyStage === 'Manage Stage') && takePositionNow !== true ) { @@ -1290,7 +1290,7 @@ let openStage = strategy.openStage let manageStage = strategy.manageStage let parentNode - let j = strategyIndex + let j = variable.strategyIndex let stageKey let initialDefinitionKey = '' let p @@ -1301,7 +1301,7 @@ parentNode = openStage.initialDefinition initialDefinitionKey = '-' + 'initialDefinition' stageKey = 'openStage' - p = takeProfitPhase + p = variable.takeProfitPhase } } } @@ -1310,7 +1310,7 @@ if (manageStage.takeProfit !== undefined) { parentNode = manageStage stageKey = 'manageStage' - p = takeProfitPhase - 1 + p = variable.takeProfitPhase - 1 } } @@ -1342,10 +1342,10 @@ if (passed) { - takeProfitPhase++; - takeProfitStage = 'Manage Stage' + variable.takeProfitPhase++; + variable.takeProfitStage = 'Manage Stage' if (stopLossPhase > 0) { - strategyStage = 'Manage Stage' + variable.strategyStage = 'Manage Stage' checkAnnouncements(manageStage, 'Stop') } @@ -1384,7 +1384,7 @@ if (moveToPhase !== undefined) { for (let q = 0; q < parentNode.takeProfit.phases.length; q++) { if (parentNode.takeProfit.phases[q].id === moveToPhase.id) { - takeProfitPhase = q + 1 + variable.takeProfitPhase = q + 1 } } } else { @@ -1392,9 +1392,9 @@ continue } - takeProfitStage = 'Manage Stage' + variable.takeProfitStage = 'Manage Stage' if (stopLossPhase > 0) { - strategyStage = 'Manage Stage' + variable.strategyStage = 'Manage Stage' checkAnnouncements(manageStage, 'Stop') } @@ -1419,7 +1419,7 @@ if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.takeProfit !== undefined) { phase = openStage.initialDefinition.takeProfit.phases[takeProfitPhase]; - key = strategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + (takeProfitPhase); + key = variable.strategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + (takeProfitPhase); } } } @@ -1427,7 +1427,7 @@ if (takeProfitStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.takeProfit !== undefined) { phase = manageStage.takeProfit.phases[takeProfitPhase - 1]; - key = strategyIndex + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 1); + key = variable.strategyIndex + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 1); } } @@ -1447,7 +1447,7 @@ /* Keeping Position Counters Up-to-date */ if ( - (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') + (strategyStage === 'Open Stage' || variable.strategyStage === 'Manage Stage') ) { if (takePositionNow === true) { @@ -1489,7 +1489,7 @@ /* Checking if Stop or Take Profit were hit */ if ( - (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') && + (strategyStage === 'Open Stage' || variable.strategyStage === 'Manage Stage') && takePositionNow !== true ) { let strategy = tradingSystem.strategies[strategyIndex]; @@ -1532,11 +1532,11 @@ closeRate = slippedStopLoss; - strategyStage = 'Close Stage'; + variable.strategyStage = 'Close Stage'; checkAnnouncements(strategy.closeStage, 'Stop') - stopLossStage = 'No Stage'; - takeProfitStage = 'No Stage'; + variable.stopLossStage = 'No Stage'; + variable.takeProfitStage = 'No Stage'; currentTrade.end = candle.end; currentTrade.status = 1; currentTrade.exitType = 1; @@ -1579,11 +1579,11 @@ closeRate = slippedTakeProfit; - strategyStage = 'Close Stage'; + variable.strategyStage = 'Close Stage'; checkAnnouncements(strategy.closeStage, 'Take Profit') - stopLossStage = 'No Stage'; - takeProfitStage = 'No Stage'; + variable.stopLossStage = 'No Stage'; + variable.takeProfitStage = 'No Stage'; currentTrade.end = candle.end; currentTrade.status = 1; @@ -1608,21 +1608,21 @@ /* Position size and rate */ let strategy = tradingSystem.strategies[strategyIndex]; - tradePositionSize = strategy.positionSize; - tradePositionRate = strategy.positionRate; + variable.tradePositionSize = strategy.positionSize; + variable.tradePositionRate = strategy.positionRate; /* We take what was calculated at the formula and apply the slippage. */ - let slippageAmount = tradePositionRate * bot.VALUES_TO_USE.slippage.positionRate / 100 + let slippageAmount = variable.tradePositionRate * bot.VALUES_TO_USE.slippage.positionRate / 100 if (baseAsset === bot.market.baseAsset) { - tradePositionRate = tradePositionRate - slippageAmount + variable.tradePositionRate = variable.tradePositionRate - slippageAmount } else { - tradePositionRate = tradePositionRate + slippageAmount + variable.tradePositionRate = variable.tradePositionRate + slippageAmount } /* Update the trade record information. */ currentTrade.begin = candle.begin; - currentTrade.beginRate = tradePositionRate; + currentTrade.beginRate = variable.tradePositionRate; /* Check if we need to execute. */ if (currentCandleIndex > candles.length - 10) { /* Only at the last candles makes sense to check if we are in live mode or not.*/ @@ -1731,18 +1731,18 @@ if (baseAsset === bot.market.baseAsset) { orderSide = "sell" - orderPrice = tradePositionRate - 100 // This is going to be ingnored at the Exchange API for now since we only put market orders. + orderPrice = variable.tradePositionRate - 100 // This is going to be ingnored at the Exchange API for now since we only put market orders. - amountA = tradePositionSize * orderPrice - amountB = tradePositionSize + amountA = variable.tradePositionSize * orderPrice + amountB = variable.tradePositionSize } else { orderSide = "buy" - orderPrice = tradePositionRate // This is going to be ingnored at the Exchange API for now since we only put market orders. + orderPrice = variable.tradePositionRate // This is going to be ingnored at the Exchange API for now since we only put market orders. - amountA = tradePositionSize - amountB = tradePositionSize / orderPrice + amountA = variable.tradePositionSize + amountB = variable.tradePositionSize / orderPrice } @@ -1805,8 +1805,8 @@ calculateTakeProfit(); calculateStopLoss(); - previousBalanceBaseAsset = balanceBaseAsset; - previousBalanceQuotedAsset = balanceQuotedAsset; + variable.previousBalanceBaseAsset = balanceBaseAsset; + variable.previousBalanceQuotedAsset = balanceQuotedAsset; lastTradeProfitLoss = 0; lastTradeROI = 0; @@ -1815,16 +1815,16 @@ if (baseAsset === bot.market.baseAsset) { - feePaid = tradePositionSize * tradePositionRate * bot.VALUES_TO_USE.feeStructure.taker / 100 + feePaid = variable.tradePositionSize * variable.tradePositionRate * bot.VALUES_TO_USE.feeStructure.taker / 100 - balanceQuotedAsset = balanceQuotedAsset + tradePositionSize * tradePositionRate - feePaid; - balanceBaseAsset = balanceBaseAsset - tradePositionSize; + balanceQuotedAsset = balanceQuotedAsset + variable.tradePositionSize * variable.tradePositionRate - feePaid; + balanceBaseAsset = balanceBaseAsset - variable.tradePositionSize; } else { - feePaid = tradePositionSize / tradePositionRate * bot.VALUES_TO_USE.feeStructure.taker / 100 + feePaid = variable.tradePositionSize / variable.tradePositionRate * bot.VALUES_TO_USE.feeStructure.taker / 100 - balanceBaseAsset = balanceBaseAsset + tradePositionSize / tradePositionRate - feePaid; - balanceQuotedAsset = balanceQuotedAsset - tradePositionSize; + balanceBaseAsset = balanceBaseAsset + variable.tradePositionSize / variable.tradePositionRate - feePaid; + balanceQuotedAsset = balanceQuotedAsset - variable.tradePositionSize; } addRecord(); @@ -2004,13 +2004,13 @@ } if (baseAsset === bot.market.baseAsset) { - lastTradeProfitLoss = balanceBaseAsset - previousBalanceBaseAsset; - lastTradeROI = lastTradeProfitLoss * 100 / tradePositionSize; + lastTradeProfitLoss = balanceBaseAsset - variable.previousBalanceBaseAsset; + lastTradeROI = lastTradeProfitLoss * 100 / variable.tradePositionSize; if (isNaN(lastTradeROI)) { lastTradeROI = 0; } profit = balanceBaseAsset - bot.VALUES_TO_USE.initialBalanceA; } else { - lastTradeProfitLoss = balanceQuotedAsset - previousBalanceQuotedAsset; - lastTradeROI = lastTradeProfitLoss * 100 / tradePositionSize; + lastTradeProfitLoss = balanceQuotedAsset - variable.previousBalanceQuotedAsset; + lastTradeROI = lastTradeProfitLoss * 100 / variable.tradePositionSize; if (isNaN(lastTradeROI)) { lastTradeROI = 0; } profit = balanceQuotedAsset - bot.VALUES_TO_USE.initialBalanceB; } @@ -2038,14 +2038,14 @@ variable.stopLoss = 0; variable.takeProfit = 0; - tradePositionRate = 0; - tradePositionSize = 0; + variable.tradePositionRate = 0; + variable.tradePositionSize = 0; timerToCloseStage = candle.begin - stopLossStage = 'No Stage'; - takeProfitStage = 'No Stage'; - stopLossPhase = -1; - takeProfitPhase = -1; + variable.stopLossStage = 'No Stage'; + variable.takeProfitStage = 'No Stage'; + variable.stopLossPhase = -1; + variable.takeProfitPhase = -1; if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> closePositionAtSimulation -> Exiting Loop Body after closing position at simulation."); } controlLoop(); @@ -2057,13 +2057,13 @@ if (strategyStage === 'Close Stage') { if (candle.begin - 5 * 60 * 1000 > timerToCloseStage) { - currentStrategy.number = strategyIndex + currentStrategy.number = variable.strategyIndex currentStrategy.end = candle.end; currentStrategy.endRate = candle.min; currentStrategy.status = 1; // This means the strategy is closed, i.e. that has a begin and end. - strategyIndex = -1; - strategyStage = 'No Stage'; + variable.strategyIndex = -1; + variable.strategyStage = 'No Stage'; timerToCloseStage = 0 distanceToLast.triggerOff = 1; @@ -2141,14 +2141,14 @@ periods: periods, days: days, anualizedRateOfReturn: anualizedRateOfReturn, - positionRate: tradePositionRate, + positionRate: variable.tradePositionRate, lastTradeROI: lastTradeROI, - strategy: strategyIndex, + strategy: variable.strategyIndex, strategyStageNumber: strategyStageNumber, takeProfit: variable.takeProfit, - stopLossPhase: stopLossPhase, - takeProfitPhase: takeProfitPhase, - positionSize: tradePositionSize, + stopLossPhase: variable.stopLossPhase, + takeProfitPhase: variable.takeProfitPhase, + positionSize: variable.tradePositionSize, initialBalanceA: bot.VALUES_TO_USE.initialBalanceA, minimumBalanceA: bot.VALUES_TO_USE.minimumBalanceA, maximumBalanceA: bot.VALUES_TO_USE.maximumBalanceA, @@ -2217,9 +2217,9 @@ /* Here we will calculate the ongoing ROI */ if (baseAsset === bot.market.baseAsset) { - currentTrade.lastTradeROI = (tradePositionRate - candle.close) / tradePositionRate * 100 + currentTrade.lastTradeROI = (tradePositionRate - candle.close) / variable.tradePositionRate * 100 } else { - currentTrade.lastTradeROI = (candle.close - tradePositionRate) / tradePositionRate * 100 + currentTrade.lastTradeROI = (candle.close - variable.tradePositionRate) / variable.tradePositionRate * 100 } } From 86c85dabc09ba6dbf3fa18a7b840fa60e1b20211 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 19 May 2020 14:10:39 +0200 Subject: [PATCH 17/44] Update TradingSimulation.js --- TradingSimulation.js | 168 +++++++++++++++++++++---------------------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index 4a975b7c8..2fce96b2c 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -119,7 +119,7 @@ variable.balanceQuotedAsset = bot.VALUES_TO_USE.initialBalanceB variable.lastTradeProfitLoss = 0 - variable.profit = 0 + variable.lastTradeProfit = 0 variable.lastTradeROI = 0 variable.roundtrips = 0; @@ -436,10 +436,10 @@ /* Default Values*/ if (baseAsset === bot.market.baseAsset) { - positionSize = balanceBaseAsset; + positionSize = variable.balanceBaseAsset; positionRate = candle.close; } else { - positionSize = balanceQuotedAsset; + positionSize = variable.balanceQuotedAsset; positionRate = candle.close; } @@ -459,15 +459,15 @@ } if (isNaN(positionSize)) { if (baseAsset === bot.market.baseAsset) { - positionSize = balanceBaseAsset; + positionSize = variable.balanceBaseAsset; } else { - positionSize = balanceQuotedAsset; + positionSize = variable.balanceQuotedAsset; } } else { if (baseAsset === bot.market.baseAsset) { - if (positionSize > balanceBaseAsset) { positionSize = balanceBaseAsset } + if (positionSize > variable.balanceBaseAsset) { positionSize = variable.balanceBaseAsset } } else { - if (positionSize > balanceQuotedAsset) { positionSize = balanceQuotedAsset } + if (positionSize > variable.balanceQuotedAsset) { positionSize = variable.balanceQuotedAsset } } } } @@ -911,11 +911,11 @@ let balance if (baseAsset === bot.market.baseAsset) { - balance = balanceBaseAsset + balance = variable.balanceBaseAsset minimumBalance = bot.VALUES_TO_USE.minimumBalanceA maximumBalance = bot.VALUES_TO_USE.maximumBalanceA } else { - balance = balanceQuotedAsset + balance = variable.balanceQuotedAsset minimumBalance = bot.VALUES_TO_USE.minimumBalanceB maximumBalance = bot.VALUES_TO_USE.maximumBalanceB } @@ -980,10 +980,10 @@ checkAnnouncements(triggerStage) variable.strategyIndex = j; - currentStrategy.begin = candle.begin; - currentStrategy.beginRate = candle.min; - currentStrategy.endRate = candle.min; // In case the strategy does not get exited - currentStrategy.triggerOnSituation = situation.name + variable.currentStrategy.begin = candle.begin; + variable.currentStrategy.beginRate = candle.min; + variable.currentStrategy.endRate = candle.min; // In case the strategy does not get exited + variable.currentStrategy.triggerOnSituation = situation.name distanceToLast.triggerOn = 1; @@ -1030,10 +1030,10 @@ if (passed) { - currentStrategy.number = variable.strategyIndex - currentStrategy.end = candle.end; - currentStrategy.endRate = candle.min; - currentStrategy.status = 1; // This means the strategy is closed, i.e. that has a begin and end. + variable.currentStrategy.number = variable.strategyIndex + variable.currentStrategy.end = candle.end; + variable.currentStrategy.endRate = candle.min; + variable.currentStrategy.status = 1; // This means the strategy is closed, i.e. that has a begin and end. variable.strategyStage = 'No Stage'; variable.strategyIndex = -1; @@ -1089,7 +1089,7 @@ variable.takeProfitPhase = 0; takePositionNow = true - currentTrade.takePositionSituation = situation.name + variable.currentTrade.takePositionSituation = situation.name checkAnnouncements(triggerStage.takePosition) @@ -1537,10 +1537,10 @@ variable.stopLossStage = 'No Stage'; variable.takeProfitStage = 'No Stage'; - currentTrade.end = candle.end; - currentTrade.status = 1; - currentTrade.exitType = 1; - currentTrade.endRate = closeRate; + variable.currentTrade.end = candle.end; + variable.currentTrade.status = 1; + variable.currentTrade.exitType = 1; + variable.currentTrade.endRate = closeRate; closePositionNow = true; } @@ -1585,10 +1585,10 @@ variable.stopLossStage = 'No Stage'; variable.takeProfitStage = 'No Stage'; - currentTrade.end = candle.end; - currentTrade.status = 1; - currentTrade.exitType = 2; - currentTrade.endRate = closeRate; + variable.currentTrade.end = candle.end; + variable.currentTrade.status = 1; + variable.currentTrade.exitType = 2; + variable.currentTrade.endRate = closeRate; closePositionNow = true; @@ -1621,8 +1621,8 @@ } /* Update the trade record information. */ - currentTrade.begin = candle.begin; - currentTrade.beginRate = variable.tradePositionRate; + variable.currentTrade.begin = candle.begin; + variable.currentTrade.beginRate = variable.tradePositionRate; /* Check if we need to execute. */ if (currentCandleIndex > candles.length - 10) { /* Only at the last candles makes sense to check if we are in live mode or not.*/ @@ -1805,11 +1805,11 @@ calculateTakeProfit(); calculateStopLoss(); - variable.previousBalanceBaseAsset = balanceBaseAsset; - variable.previousBalanceQuotedAsset = balanceQuotedAsset; + variable.previousBalanceBaseAsset = variable.balanceBaseAsset; + variable.previousBalanceQuotedAsset = variable.balanceQuotedAsset; - lastTradeProfitLoss = 0; - lastTradeROI = 0; + variable.lastTradeProfitLoss = 0; + variable.lastTradeROI = 0; let feePaid = 0 @@ -1817,14 +1817,14 @@ feePaid = variable.tradePositionSize * variable.tradePositionRate * bot.VALUES_TO_USE.feeStructure.taker / 100 - balanceQuotedAsset = balanceQuotedAsset + variable.tradePositionSize * variable.tradePositionRate - feePaid; - balanceBaseAsset = balanceBaseAsset - variable.tradePositionSize; + variable.balanceQuotedAsset = variable.balanceQuotedAsset + variable.tradePositionSize * variable.tradePositionRate - feePaid; + variable.balanceBaseAsset = variable.balanceBaseAsset - variable.tradePositionSize; } else { feePaid = variable.tradePositionSize / variable.tradePositionRate * bot.VALUES_TO_USE.feeStructure.taker / 100 - balanceBaseAsset = balanceBaseAsset + variable.tradePositionSize / variable.tradePositionRate - feePaid; - balanceQuotedAsset = balanceQuotedAsset - variable.tradePositionSize; + variable.balanceBaseAsset = variable.balanceBaseAsset + variable.tradePositionSize / variable.tradePositionRate - feePaid; + variable.balanceQuotedAsset = variable.balanceQuotedAsset - variable.tradePositionSize; } addRecord(); @@ -1914,16 +1914,16 @@ orderPrice = ticker.last + 100; // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. - amountA = balanceQuotedAsset - amountB = balanceQuotedAsset / orderPrice + amountA = variable.balanceQuotedAsset + amountB = variable.balanceQuotedAsset / orderPrice } else { orderSide = "sell" orderPrice = ticker.last - 100; // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. - amountA = balanceBaseAsset * orderPrice - amountB = balanceBaseAsset + amountA = variable.balanceBaseAsset * orderPrice + amountB = variable.balanceBaseAsset } @@ -1986,36 +1986,36 @@ let feePaid = 0 if (baseAsset === bot.market.baseAsset) { - strategy.positionSize = balanceQuotedAsset / closeRate; + strategy.positionSize = variable.balanceQuotedAsset / closeRate; strategy.positionRate = closeRate; - feePaid = balanceQuotedAsset / closeRate * bot.VALUES_TO_USE.feeStructure.taker / 100 + feePaid = variable.balanceQuotedAsset / closeRate * bot.VALUES_TO_USE.feeStructure.taker / 100 - balanceBaseAsset = balanceBaseAsset + balanceQuotedAsset / closeRate - feePaid; - balanceQuotedAsset = 0; + variable.balanceBaseAsset = variable.balanceBaseAsset + variable.balanceQuotedAsset / closeRate - feePaid; + variable.balanceQuotedAsset = 0; } else { - strategy.positionSize = balanceBaseAsset * closeRate; + strategy.positionSize = variable.balanceBaseAsset * closeRate; strategy.positionRate = closeRate; - feePaid = balanceBaseAsset * closeRate * bot.VALUES_TO_USE.feeStructure.taker / 100 + feePaid = variable.balanceBaseAsset * closeRate * bot.VALUES_TO_USE.feeStructure.taker / 100 - balanceQuotedAsset = balanceQuotedAsset + balanceBaseAsset * closeRate - feePaid; - balanceBaseAsset = 0; + variable.balanceQuotedAsset = variable.balanceQuotedAsset + variable.balanceBaseAsset * closeRate - feePaid; + variable.balanceBaseAsset = 0; } if (baseAsset === bot.market.baseAsset) { - lastTradeProfitLoss = balanceBaseAsset - variable.previousBalanceBaseAsset; - lastTradeROI = lastTradeProfitLoss * 100 / variable.tradePositionSize; - if (isNaN(lastTradeROI)) { lastTradeROI = 0; } - profit = balanceBaseAsset - bot.VALUES_TO_USE.initialBalanceA; + variable.lastTradeProfitLoss = variable.balanceBaseAsset - variable.previousBalanceBaseAsset; + variable.lastTradeROI = variable.lastTradeProfitLoss * 100 / variable.tradePositionSize; + if (isNaN(lastTradeROI)) { variable.lastTradeROI = 0; } + variable.lastTradeProfit = variable.balanceBaseAsset - bot.VALUES_TO_USE.initialBalanceA; } else { - lastTradeProfitLoss = balanceQuotedAsset - variable.previousBalanceQuotedAsset; - lastTradeROI = lastTradeProfitLoss * 100 / variable.tradePositionSize; - if (isNaN(lastTradeROI)) { lastTradeROI = 0; } - profit = balanceQuotedAsset - bot.VALUES_TO_USE.initialBalanceB; + variable.lastTradeProfitLoss = variable.balanceQuotedAsset - variable.previousBalanceQuotedAsset; + variable.lastTradeROI = variable.lastTradeProfitLoss * 100 / variable.tradePositionSize; + if (isNaN(lastTradeROI)) { variable.lastTradeROI = 0; } + variable.lastTradeProfit = variable.balanceQuotedAsset - bot.VALUES_TO_USE.initialBalanceB; } - currentTrade.lastTradeROI = lastTradeROI; + variable.currentTrade.lastTradeROI = variable.lastTradeROI; if (lastTradeProfitLoss > 0) { hits++; @@ -2024,11 +2024,11 @@ } if (baseAsset === bot.market.baseAsset) { - ROI = (bot.VALUES_TO_USE.initialBalanceA + profit) / bot.VALUES_TO_USE.initialBalanceA - 1; + ROI = (bot.VALUES_TO_USE.initialBalanceA + variable.lastTradeProfit) / bot.VALUES_TO_USE.initialBalanceA - 1; hitRatio = hits / roundtrips; anualizedRateOfReturn = ROI / days * 365; } else { - ROI = (bot.VALUES_TO_USE.initialBalanceB + profit) / bot.VALUES_TO_USE.initialBalanceB - 1; + ROI = (bot.VALUES_TO_USE.initialBalanceB + variable.lastTradeProfit) / bot.VALUES_TO_USE.initialBalanceB - 1; hitRatio = hits / roundtrips; anualizedRateOfReturn = ROI / days * 365; } @@ -2057,10 +2057,10 @@ if (strategyStage === 'Close Stage') { if (candle.begin - 5 * 60 * 1000 > timerToCloseStage) { - currentStrategy.number = variable.strategyIndex - currentStrategy.end = candle.end; - currentStrategy.endRate = candle.min; - currentStrategy.status = 1; // This means the strategy is closed, i.e. that has a begin and end. + variable.currentStrategy.number = variable.strategyIndex + variable.currentStrategy.end = candle.end; + variable.currentStrategy.endRate = candle.min; + variable.currentStrategy.status = 1; // This means the strategy is closed, i.e. that has a begin and end. variable.strategyIndex = -1; variable.strategyStage = 'No Stage'; @@ -2114,11 +2114,11 @@ } if (balanceBaseAsset === Infinity) { - balanceBaseAsset = Number.MAX_SAFE_INTEGER + variable.balanceBaseAsset = Number.MAX_SAFE_INTEGER } if (balanceQuotedAsset === Infinity) { - balanceQuotedAsset = Number.MAX_SAFE_INTEGER + variable.balanceQuotedAsset = Number.MAX_SAFE_INTEGER } let quotedBaseAsset = '"' + baseAsset + '"' @@ -2128,10 +2128,10 @@ begin: candle.begin, end: candle.end, amount: 1, - balanceA: balanceBaseAsset, - balanceB: balanceQuotedAsset, - profit: profit, - lastTradeProfitLoss: lastTradeProfitLoss, + balanceA: variable.balanceBaseAsset, + balanceB: variable.balanceQuotedAsset, + profit: variable.lastTradeProfit, + lastTradeProfitLoss: variable.lastTradeProfitLoss, stopLoss: variable.stopLoss, roundtrips: roundtrips, hits: hits, @@ -2142,7 +2142,7 @@ days: days, anualizedRateOfReturn: anualizedRateOfReturn, positionRate: variable.tradePositionRate, - lastTradeROI: lastTradeROI, + lastTradeROI: variable.lastTradeROI, strategy: variable.strategyIndex, strategyStageNumber: strategyStageNumber, takeProfit: variable.takeProfit, @@ -2185,17 +2185,17 @@ Lets see if there will be an open strategy ... Except if we are at the head of the market (remember we skipped the last candle for not being closed.) */ - if (currentStrategy.begin !== 0 && currentStrategy.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { - currentStrategy.status = 2; // This means the strategy is open, i.e. that has a begin but no end. - currentStrategy.end = candle.end + if (currentStrategy.begin !== 0 && variable.currentStrategy.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { + variable.currentStrategy.status = 2; // This means the strategy is open, i.e. that has a begin but no end. + variable.currentStrategy.end = candle.end } /* Prepare the information for the Strategies File*/ - if (currentStrategy.begin !== 0 && currentStrategy.end !== 0) + if (currentStrategy.begin !== 0 && variable.currentStrategy.end !== 0) { strategiesArray.push(currentStrategy); - currentStrategy = { + variable.currentStrategy = { begin: 0, end: 0, status: 0, @@ -2210,27 +2210,27 @@ Lets see if there will be an open trade ... Except if we are at the head of the market (remember we skipped the last candle for not being closed.) */ - if (currentTrade.begin !== 0 && currentTrade.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { - currentTrade.status = 2; // This means the trade is open - currentTrade.end = candle.end - currentTrade.endRate = candle.close + if (currentTrade.begin !== 0 && variable.currentTrade.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { + variable.currentTrade.status = 2; // This means the trade is open + variable.currentTrade.end = candle.end + variable.currentTrade.endRate = candle.close /* Here we will calculate the ongoing ROI */ if (baseAsset === bot.market.baseAsset) { - currentTrade.lastTradeROI = (tradePositionRate - candle.close) / variable.tradePositionRate * 100 + variable.currentTrade.lastTradeROI = (tradePositionRate - candle.close) / variable.tradePositionRate * 100 } else { - currentTrade.lastTradeROI = (candle.close - variable.tradePositionRate) / variable.tradePositionRate * 100 + variable.currentTrade.lastTradeROI = (candle.close - variable.tradePositionRate) / variable.tradePositionRate * 100 } } /* Prepare the information for the Trades File */ - if (currentTrade.begin !== 0 && currentTrade.end !== 0) { + if (currentTrade.begin !== 0 && variable.currentTrade.end !== 0) { - currentTrade.profit = lastTradeProfitLoss; + variable.currentTrade.profit = variable.lastTradeProfitLoss; tradesArray.push(currentTrade); - currentTrade = { + variable.currentTrade = { begin: 0, end: 0, status: 0, From 571b85bebe9c596e94bb7b940190a951fe886b09 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 19 May 2020 15:05:25 +0200 Subject: [PATCH 18/44] more variable. --- TradingBot.js | 10 ++--- TradingSimulation.js | 99 +++++++++++++++++--------------------------- 2 files changed, 41 insertions(+), 68 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index c78342afe..34f06c9aa 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -183,10 +183,10 @@ record.amount + "," + record.balanceA + "," + record.balanceB + "," + - record.profit + "," + + record.accumulatedProfitLoss + "," + record.lastTradeProfitLoss + "," + record.stopLoss + "," + - record.roundtrips + "," + + record.tradesCount + "," + record.hits + "," + record.fails + "," + record.hitRatio + "," + @@ -197,7 +197,6 @@ record.positionRate + "," + record.lastTradeROI + "," + record.strategy + "," + - record.strategyStageNumber + "," + record.takeProfit + "," + record.stopLossPhase + "," + record.takeProfitPhase + "," + @@ -519,10 +518,10 @@ record.amount + "," + record.balanceA + "," + record.balanceB + "," + - record.profit + "," + + record.accumulatedProfitLoss + "," + record.lastTradeProfitLoss + "," + record.stopLoss + "," + - record.roundtrips + "," + + record.tradesCount + "," + record.hits + "," + record.fails + "," + record.hitRatio + "," + @@ -533,7 +532,6 @@ record.positionRate + "," + record.lastTradeROI + "," + record.strategy + "," + - record.strategyStageNumber + "," + record.takeProfit + "," + record.stopLossPhase + "," + record.takeProfitPhase + "," + diff --git a/TradingSimulation.js b/TradingSimulation.js index 2fce96b2c..379fea00c 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -119,14 +119,15 @@ variable.balanceQuotedAsset = bot.VALUES_TO_USE.initialBalanceB variable.lastTradeProfitLoss = 0 - variable.lastTradeProfit = 0 + variable.accumulatedProfitLoss = 0 variable.lastTradeROI = 0 - variable.roundtrips = 0; - variable.fails = 0; - variable.hits = 0; - variable.periods = 0; - variable.positionPeriods = 0; + variable.tradesCount = 0 + variable.fails = 0 + variable.hits = 0 + variable.periods = 0 + variable.positionPeriods = 0 + variable.days = 0 /* Usefull counters for conditions and formulas */ variable.distanceToLast = { @@ -324,8 +325,8 @@ } */ - periods++; - days = periods * timeFrame / ONE_DAY_IN_MILISECONDS; + variable.periods++; + variable.days = variable.periods * timeFrame / ONE_DAY_IN_MILISECONDS; if (processingDailyFiles) { @@ -338,7 +339,7 @@ controlLoop(); return /* Note here that in the last candle of the first day or the second day it will use an incomplete candle and partially calculated indicators. - if we skip these two periods, then there will be a hole in the file since the last period will be missing. */ + if we skip these two variable.periods, then there will be a hole in the file since the last period will be missing. */ } } @@ -1748,7 +1749,7 @@ variable.executionContext = { status: "Taking Position", - periods: periods, + variable.periods: variable.periods, } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Ready to create order."); } @@ -1763,7 +1764,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_OK_RESPONSE "); } variable.executionContext = { status: "In a Position", - periods: periods, + variable.periods: variable.periods, amountA: amountA, amountB: amountB, orderId: order.id @@ -1929,7 +1930,7 @@ variable.executionContext = { status: "Closing Position", - periods: periods, + variable.periods: variable.periods, } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> About to close position at the exchange."); } @@ -1944,7 +1945,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> DEFAULT_OK_RESPONSE "); } variable.executionContext = { status: "Position Closed", - periods: periods, + variable.periods: variable.periods, amountA: amountA, amountB: amountB, orderId: order.id @@ -1981,7 +1982,7 @@ function closePositionAtSimulation() { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> closePositionAtSimulation -> Entering function."); } - roundtrips++; + variable.tradesCount++; let feePaid = 0 @@ -2007,30 +2008,30 @@ variable.lastTradeProfitLoss = variable.balanceBaseAsset - variable.previousBalanceBaseAsset; variable.lastTradeROI = variable.lastTradeProfitLoss * 100 / variable.tradePositionSize; if (isNaN(lastTradeROI)) { variable.lastTradeROI = 0; } - variable.lastTradeProfit = variable.balanceBaseAsset - bot.VALUES_TO_USE.initialBalanceA; + variable.accumulatedProfitLoss = variable.balanceBaseAsset - bot.VALUES_TO_USE.initialBalanceA; } else { variable.lastTradeProfitLoss = variable.balanceQuotedAsset - variable.previousBalanceQuotedAsset; variable.lastTradeROI = variable.lastTradeProfitLoss * 100 / variable.tradePositionSize; if (isNaN(lastTradeROI)) { variable.lastTradeROI = 0; } - variable.lastTradeProfit = variable.balanceQuotedAsset - bot.VALUES_TO_USE.initialBalanceB; + variable.accumulatedProfitLoss = variable.balanceQuotedAsset - bot.VALUES_TO_USE.initialBalanceB; } variable.currentTrade.lastTradeROI = variable.lastTradeROI; if (lastTradeProfitLoss > 0) { - hits++; + variable.hits++; } else { - fails++; + variable.fails++; } if (baseAsset === bot.market.baseAsset) { - ROI = (bot.VALUES_TO_USE.initialBalanceA + variable.lastTradeProfit) / bot.VALUES_TO_USE.initialBalanceA - 1; - hitRatio = hits / roundtrips; - anualizedRateOfReturn = ROI / days * 365; + variable.ROI = (bot.VALUES_TO_USE.initialBalanceA + variable.accumulatedProfitLoss) / bot.VALUES_TO_USE.initialBalanceA - 1; + variable.hitRatio = variable.hits / variable.tradesCount; + variable.anualizedRateOfReturn = variable.ROI / variable.days * 365; } else { - ROI = (bot.VALUES_TO_USE.initialBalanceB + variable.lastTradeProfit) / bot.VALUES_TO_USE.initialBalanceB - 1; - hitRatio = hits / roundtrips; - anualizedRateOfReturn = ROI / days * 365; + variable.ROI = (bot.VALUES_TO_USE.initialBalanceB + variable.accumulatedProfitLoss) / bot.VALUES_TO_USE.initialBalanceB - 1; + variable.hitRatio = variable.hits / variable.tradesCount; + variable.anualizedRateOfReturn = variable.ROI / variable.days * 365; } addRecord(); @@ -2089,30 +2090,6 @@ let message; let simulationRecord; - let strategyStageNumber - switch (strategyStage) { - case 'No Stage': { - strategyStageNumber = 0 - break - } - case 'Trigger Stage': { - strategyStageNumber = 1 - break - } - case 'Open Stage': { - strategyStageNumber = 2 - break - } - case 'Manage Stage': { - strategyStageNumber = 3 - break - } - case 'Close Stage': { - strategyStageNumber = 4 - break - } - } - if (balanceBaseAsset === Infinity) { variable.balanceBaseAsset = Number.MAX_SAFE_INTEGER } @@ -2130,21 +2107,20 @@ amount: 1, balanceA: variable.balanceBaseAsset, balanceB: variable.balanceQuotedAsset, - profit: variable.lastTradeProfit, + accumulatedProfitLoss: variable.accumulatedProfitLoss, lastTradeProfitLoss: variable.lastTradeProfitLoss, stopLoss: variable.stopLoss, - roundtrips: roundtrips, - hits: hits, - fails: fails, - hitRatio: hitRatio, - ROI: ROI, - periods: periods, - days: days, - anualizedRateOfReturn: anualizedRateOfReturn, + tradesCount: variable.tradesCount, + hits: variable.hits, + fails: variable.fails, + hitRatio: variable.hitRatio, + ROI: variable.ROI, + periods: variable.periods, + days: variable.days, + anualizedRateOfReturn: variable.anualizedRateOfReturn, positionRate: variable.tradePositionRate, lastTradeROI: variable.lastTradeROI, strategy: variable.strategyIndex, - strategyStageNumber: strategyStageNumber, takeProfit: variable.takeProfit, stopLossPhase: variable.stopLossPhase, takeProfitPhase: variable.takeProfitPhase, @@ -2172,7 +2148,6 @@ /* Prepare the information for the Conditions File */ conditionsArrayRecord.push(strategyIndex); - conditionsArrayRecord.push(strategyStageNumber); conditionsArrayRecord.push(stopLossPhase); conditionsArrayRecord.push(takeProfitPhase); conditionsArrayRecord.push(conditionsArrayValues); @@ -2215,7 +2190,7 @@ variable.currentTrade.end = candle.end variable.currentTrade.endRate = candle.close - /* Here we will calculate the ongoing ROI */ + /* Here we will calculate the ongoing variable.ROI */ if (baseAsset === bot.market.baseAsset) { variable.currentTrade.lastTradeROI = (tradePositionRate - candle.close) / variable.tradePositionRate * 100 } else { @@ -2297,12 +2272,12 @@ /* Next, we will remmeber this announcement was already done, so that it is not announced again in further processing of the same day. */ if (newAnnouncementRecord.periods !== undefined) { - newAnnouncementRecord.periods = periods + newAnnouncementRecord.periods = variable.periods newAnnouncementRecord.value = value } else { newAnnouncementRecord = { key: key, - periods: periods, + variable.periods: variable.periods, value: value } variable.announcements.push(newAnnouncementRecord) From 670a66858d369f7442fb07b52ff54871fdd2ce3e Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 19 May 2020 16:31:14 +0200 Subject: [PATCH 19/44] variable first round set --- TradingBot.js | 1 - TradingSimulation.js | 141 +++++++++++++++++++++++-------------------- 2 files changed, 74 insertions(+), 68 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index 34f06c9aa..85d97eb24 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -200,7 +200,6 @@ record.takeProfit + "," + record.stopLossPhase + "," + record.takeProfitPhase + "," + - JSON.stringify(record.executionRecord) + "," + record.positionSize + "," + record.initialBalanceA + "," + record.minimumBalanceA + "," + diff --git a/TradingSimulation.js b/TradingSimulation.js index 379fea00c..44d26b0be 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -118,6 +118,14 @@ variable.balanceBaseAsset = bot.VALUES_TO_USE.initialBalanceA variable.balanceQuotedAsset = bot.VALUES_TO_USE.initialBalanceB + variable.initialBalanceBaseAsset = bot.VALUES_TO_USE.initialBalanceA + variable.minimumBalanceBaseAsset = bot.VALUES_TO_USE.minimumBalanceA + variable.maximumBalanceBaseAsset = bot.VALUES_TO_USE.maximumBalanceA + + variable.initialBalanceQuotedAsset = bot.VALUES_TO_USE.initialBalanceB + variable.minimumBalanceQuotedAsset = bot.VALUES_TO_USE.minimumBalanceB + variable.maximumBalanceQuotedAsset = bot.VALUES_TO_USE.maximumBalanceB + variable.lastTradeProfitLoss = 0 variable.accumulatedProfitLoss = 0 variable.lastTradeROI = 0 @@ -146,6 +154,8 @@ /* Allowing these to be accesible at formulas */ variable.baseAsset = bot.VALUES_TO_USE.baseAsset variable.quotedAsset = bot.VALUES_TO_USE.quotedAsset + variable.marketBaseAsset = bot.market.baseAsset + variable.marketQuotedAsset = bot.market.quotedAsset } /* Main Array and Maps */ @@ -436,7 +446,7 @@ if (openStage !== undefined) { /* Default Values*/ - if (baseAsset === bot.market.baseAsset) { + if (baseAsset === variable.marketBaseAsset) { positionSize = variable.balanceBaseAsset; positionRate = candle.close; } else { @@ -459,13 +469,13 @@ initialDefinition.positionSize.formula.error = err.message } if (isNaN(positionSize)) { - if (baseAsset === bot.market.baseAsset) { + if (baseAsset === variable.marketBaseAsset) { positionSize = variable.balanceBaseAsset; } else { positionSize = variable.balanceQuotedAsset; } } else { - if (baseAsset === bot.market.baseAsset) { + if (baseAsset === variable.marketBaseAsset) { if (positionSize > variable.balanceBaseAsset) { positionSize = variable.balanceBaseAsset } } else { if (positionSize > variable.balanceQuotedAsset) { positionSize = variable.balanceQuotedAsset } @@ -486,7 +496,7 @@ initialDefinition.positionRate.formula.error = err.message } if (isNaN(positionRate)) { - if (baseAsset === bot.market.baseAsset) { + if (baseAsset === variable.marketBaseAsset) { positionRate = candle.close; } else { positionRate = candle.close; @@ -911,14 +921,14 @@ let maximumBalance let balance - if (baseAsset === bot.market.baseAsset) { + if (baseAsset === variable.marketBaseAsset) { balance = variable.balanceBaseAsset - minimumBalance = bot.VALUES_TO_USE.minimumBalanceA - maximumBalance = bot.VALUES_TO_USE.maximumBalanceA + minimumBalance = variable.minimumBalanceBaseAsset + maximumBalance = variable.maximumBalanceBaseAsset } else { balance = variable.balanceQuotedAsset - minimumBalance = bot.VALUES_TO_USE.minimumBalanceB - maximumBalance = bot.VALUES_TO_USE.maximumBalanceB + minimumBalance = variable.minimumBalanceQuotedAsset + maximumBalance = variable.maximumBalanceQuotedAsset } let stopRunningDate = new Date(candle.begin) @@ -986,7 +996,7 @@ variable.currentStrategy.endRate = candle.min; // In case the strategy does not get exited variable.currentStrategy.triggerOnSituation = situation.name - distanceToLast.triggerOn = 1; + variable.distanceToLast.triggerOn = 1; checkAnnouncements(triggerStage.triggerOn) @@ -1038,7 +1048,7 @@ variable.strategyStage = 'No Stage'; variable.strategyIndex = -1; - distanceToLast.triggerOff = 1; + variable.distanceToLast.triggerOff = 1; checkAnnouncements(triggerStage.triggerOff) @@ -1452,40 +1462,40 @@ ) { if (takePositionNow === true) { - positionPeriods = 0 + variable.positionPeriods = 0 } - positionPeriods++; - positionDays = positionPeriods * timeFrame / ONE_DAY_IN_MILISECONDS; + variable.positionPeriods++; + variable.positionDays = variable.positionPeriods * timeFrame / ONE_DAY_IN_MILISECONDS; } else { - positionPeriods = 0 - positionDays = 0 + variable.positionPeriods = 0 + variable.positionDays = 0 } /* Keeping Distance Counters Up-to-date */ if ( - distanceToLast.triggerOn > 0 // with this we avoind counting before the first event happens. + variable.distanceToLast.triggerOn > 0 // with this we avoind counting before the first event happens. ) { - distanceToLast.triggerOn++; + variable.distanceToLast.triggerOn++; } if ( - distanceToLast.triggerOff > 0 // with this we avoind counting before the first event happens. + variable.distanceToLast.triggerOff > 0 // with this we avoind counting before the first event happens. ) { - distanceToLast.triggerOff++; + variable.distanceToLast.triggerOff++; } if ( - distanceToLast.takePosition > 0 // with this we avoind counting before the first event happens. + variable.distanceToLast.takePosition > 0 // with this we avoind counting before the first event happens. ) { - distanceToLast.takePosition++; + variable.distanceToLast.takePosition++; } if ( - distanceToLast.closePosition > 0 // with this we avoind counting before the first event happens. + variable.distanceToLast.closePosition > 0 // with this we avoind counting before the first event happens. ) { - distanceToLast.closePosition++; + variable.distanceToLast.closePosition++; } /* Checking if Stop or Take Profit were hit */ @@ -1500,7 +1510,7 @@ /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - if ((baseAsset === bot.market.baseAsset && candle.max >= variable.stopLoss) || (baseAsset !== bot.market.baseAsset && candle.min <= variable.stopLoss)) { + if ((baseAsset === variable.marketBaseAsset && candle.max >= variable.stopLoss) || (baseAsset !== variable.marketBaseAsset && candle.min <= variable.stopLoss)) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Stop Loss was hit."); } /* @@ -1510,7 +1520,7 @@ If we take the stop loss value at those situation would be a huge distortion of facts. */ - if (baseAsset === bot.market.baseAsset) { + if (baseAsset === variable.marketBaseAsset) { if (stopLoss < candle.min) { variable.stopLoss = candle.min } @@ -1525,7 +1535,7 @@ /* Apply the Slippage */ let slippageAmount = slippedStopLoss * bot.VALUES_TO_USE.slippage.stopLoss / 100 - if (baseAsset === bot.market.baseAsset) { + if (baseAsset === variable.marketBaseAsset) { slippedStopLoss = slippedStopLoss + slippageAmount } else { slippedStopLoss = slippedStopLoss - slippageAmount @@ -1548,7 +1558,7 @@ /* Take Profit condition: Here we verify if the Take Profit was hit or not. */ - if ((baseAsset === bot.market.baseAsset && candle.min <= variable.takeProfit) || (baseAsset !== bot.market.baseAsset && candle.max >= variable.takeProfit)) { + if ((baseAsset === variable.marketBaseAsset && candle.min <= variable.takeProfit) || (baseAsset !== variable.marketBaseAsset && candle.max >= variable.takeProfit)) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Take Profit was hit."); } /* @@ -1558,7 +1568,7 @@ If we take the stop loss value at those situation would be a huge distortion of facts. */ - if (baseAsset === bot.market.baseAsset) { + if (baseAsset === variable.marketBaseAsset) { if (takeProfit > candle.max) { variable.takeProfit = candle.max } @@ -1572,7 +1582,7 @@ /* Apply the Slippage */ let slippageAmount = slippedTakeProfit * bot.VALUES_TO_USE.slippage.takeProfit / 100 - if (baseAsset === bot.market.baseAsset) { + if (baseAsset === variable.marketBaseAsset) { slippedTakeProfit = slippedTakeProfit + slippageAmount } else { slippedTakeProfit = slippedTakeProfit - slippageAmount @@ -1604,7 +1614,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionNow -> Entering code block."); } /* Inicializing this counter */ - distanceToLast.takePosition = 1; + variable.distanceToLast.takePosition = 1; /* Position size and rate */ let strategy = tradingSystem.strategies[strategyIndex]; @@ -1615,7 +1625,7 @@ /* We take what was calculated at the formula and apply the slippage. */ let slippageAmount = variable.tradePositionRate * bot.VALUES_TO_USE.slippage.positionRate / 100 - if (baseAsset === bot.market.baseAsset) { + if (baseAsset === variable.marketBaseAsset) { variable.tradePositionRate = variable.tradePositionRate - slippageAmount } else { variable.tradePositionRate = variable.tradePositionRate + slippageAmount @@ -1729,7 +1739,7 @@ let orderSide - if (baseAsset === bot.market.baseAsset) { + if (baseAsset === variable.marketBaseAsset) { orderSide = "sell" orderPrice = variable.tradePositionRate - 100 // This is going to be ingnored at the Exchange API for now since we only put market orders. @@ -1814,7 +1824,7 @@ let feePaid = 0 - if (baseAsset === bot.market.baseAsset) { + if (baseAsset === variable.marketBaseAsset) { feePaid = variable.tradePositionSize * variable.tradePositionRate * bot.VALUES_TO_USE.feeStructure.taker / 100 @@ -1842,7 +1852,7 @@ closePositionNow = false /* Inicializing this counter */ - distanceToLast.closePosition = 1; + variable.distanceToLast.closePosition = 1; /* Position size and rate */ let strategy = tradingSystem.strategies[strategyIndex]; @@ -1910,7 +1920,7 @@ let amountB let orderSide - if (baseAsset === bot.market.baseAsset) { + if (baseAsset === variable.marketBaseAsset) { orderSide = "buy" orderPrice = ticker.last + 100; // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. @@ -1986,7 +1996,7 @@ let feePaid = 0 - if (baseAsset === bot.market.baseAsset) { + if (baseAsset === variable.marketBaseAsset) { strategy.positionSize = variable.balanceQuotedAsset / closeRate; strategy.positionRate = closeRate; @@ -2004,16 +2014,16 @@ variable.balanceBaseAsset = 0; } - if (baseAsset === bot.market.baseAsset) { + if (baseAsset === variable.marketBaseAsset) { variable.lastTradeProfitLoss = variable.balanceBaseAsset - variable.previousBalanceBaseAsset; variable.lastTradeROI = variable.lastTradeProfitLoss * 100 / variable.tradePositionSize; if (isNaN(lastTradeROI)) { variable.lastTradeROI = 0; } - variable.accumulatedProfitLoss = variable.balanceBaseAsset - bot.VALUES_TO_USE.initialBalanceA; + variable.accumulatedProfitLoss = variable.balanceBaseAsset - variable.initialBalanceBaseAsset; } else { variable.lastTradeProfitLoss = variable.balanceQuotedAsset - variable.previousBalanceQuotedAsset; variable.lastTradeROI = variable.lastTradeProfitLoss * 100 / variable.tradePositionSize; if (isNaN(lastTradeROI)) { variable.lastTradeROI = 0; } - variable.accumulatedProfitLoss = variable.balanceQuotedAsset - bot.VALUES_TO_USE.initialBalanceB; + variable.accumulatedProfitLoss = variable.balanceQuotedAsset - variable.initialBalanceQuotedAsset; } variable.currentTrade.lastTradeROI = variable.lastTradeROI; @@ -2024,12 +2034,12 @@ variable.fails++; } - if (baseAsset === bot.market.baseAsset) { - variable.ROI = (bot.VALUES_TO_USE.initialBalanceA + variable.accumulatedProfitLoss) / bot.VALUES_TO_USE.initialBalanceA - 1; + if (baseAsset === variable.marketBaseAsset) { + variable.ROI = (variable.initialBalanceBaseAsset + variable.accumulatedProfitLoss) / variable.initialBalanceBaseAsset - 1; variable.hitRatio = variable.hits / variable.tradesCount; variable.anualizedRateOfReturn = variable.ROI / variable.days * 365; } else { - variable.ROI = (bot.VALUES_TO_USE.initialBalanceB + variable.accumulatedProfitLoss) / bot.VALUES_TO_USE.initialBalanceB - 1; + variable.ROI = (variable.initialBalanceQuotedAsset + variable.accumulatedProfitLoss) / variable.initialBalanceQuotedAsset - 1; variable.hitRatio = variable.hits / variable.tradesCount; variable.anualizedRateOfReturn = variable.ROI / variable.days * 365; } @@ -2067,7 +2077,7 @@ variable.strategyStage = 'No Stage'; timerToCloseStage = 0 - distanceToLast.triggerOff = 1; + variable.distanceToLast.triggerOff = 1; if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing the Closing Stage -> Exiting Close Stage."); } } else { @@ -2098,9 +2108,6 @@ variable.balanceQuotedAsset = Number.MAX_SAFE_INTEGER } - let quotedBaseAsset = '"' + baseAsset + '"' - let quotedQuotedAsset = '"' + quotedAsset + '"' - simulationRecord = { begin: candle.begin, end: candle.end, @@ -2125,22 +2132,22 @@ stopLossPhase: variable.stopLossPhase, takeProfitPhase: variable.takeProfitPhase, positionSize: variable.tradePositionSize, - initialBalanceA: bot.VALUES_TO_USE.initialBalanceA, - minimumBalanceA: bot.VALUES_TO_USE.minimumBalanceA, - maximumBalanceA: bot.VALUES_TO_USE.maximumBalanceA, - initialBalanceB: bot.VALUES_TO_USE.initialBalanceB, - minimumBalanceB: bot.VALUES_TO_USE.minimumBalanceB, - maximumBalanceB: bot.VALUES_TO_USE.maximumBalanceB, - baseAsset: quotedBaseAsset, - quotedAsset: quotedQuotedAsset, - marketBaseAsset: '"' + bot.market.baseAsset + '"', - marketQuotedAsset: '"' + bot.market.quotedAsset + '"' , - positionPeriods: positionPeriods, - positionDays: positionDays, - distanceToLastTriggerOn: distanceToLast.triggerOn, - distanceToLastTriggerOff: distanceToLast.triggerOff, - distanceToLastTakePosition: distanceToLast.takePosition, - distanceToLastClosePosition: distanceToLast.closePosition + initialBalanceA: variable.initialBalanceBaseAsset, + minimumBalanceA: variable.minimumBalanceBaseAsset, + maximumBalanceA: variable.maximumBalanceBaseAsset, + initialBalanceB: variable.initialBalanceQuotedAsset, + minimumBalanceB: variable.minimumBalanceQuotedAsset, + maximumBalanceB: variable.maximumBalanceQuotedAsset, + baseAsset: '"' + variable.baseAsset + '"', + quotedAsset: '"' + variable.quotedAsset + '"', + marketBaseAsset: '"' + variable.marketBaseAsset + '"', + marketQuotedAsset: '"' + variable.marketQuotedAsset + '"' , + positionPeriods: variable.positionPeriods, + positionDays: variable.positionDays, + distanceToLastTriggerOn: variable.distanceToLast.triggerOn, + distanceToLastTriggerOff: variable.distanceToLast.triggerOff, + distanceToLastTakePosition: variable.distanceToLast.takePosition, + distanceToLastClosePosition: variable.distanceToLast.closePosition } recordsArray.push(simulationRecord); @@ -2185,13 +2192,13 @@ Lets see if there will be an open trade ... Except if we are at the head of the market (remember we skipped the last candle for not being closed.) */ - if (currentTrade.begin !== 0 && variable.currentTrade.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { + if (variable.currentTrade.begin !== 0 && variable.currentTrade.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { variable.currentTrade.status = 2; // This means the trade is open variable.currentTrade.end = candle.end variable.currentTrade.endRate = candle.close /* Here we will calculate the ongoing variable.ROI */ - if (baseAsset === bot.market.baseAsset) { + if (baseAsset === variable.marketBaseAsset) { variable.currentTrade.lastTradeROI = (tradePositionRate - candle.close) / variable.tradePositionRate * 100 } else { variable.currentTrade.lastTradeROI = (candle.close - variable.tradePositionRate) / variable.tradePositionRate * 100 @@ -2199,11 +2206,11 @@ } /* Prepare the information for the Trades File */ - if (currentTrade.begin !== 0 && variable.currentTrade.end !== 0) { + if (variable.currentTrade.begin !== 0 && variable.currentTrade.end !== 0) { variable.currentTrade.profit = variable.lastTradeProfitLoss; - tradesArray.push(currentTrade); + tradesArray.push(variable.currentTrade); variable.currentTrade = { begin: 0, From 8bad05b1de988a1869c338505f6fd20610ec6fa5 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 19 May 2020 20:15:16 +0200 Subject: [PATCH 20/44] all refactoring done --- TradingBot.js | 10 ++--- TradingSimulation.js | 104 ++++++++++++++++--------------------------- 2 files changed, 43 insertions(+), 71 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index 85d97eb24..72cc5ef03 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -180,9 +180,8 @@ fileContent = fileContent + separator + '[' + record.begin + "," + record.end + "," + - record.amount + "," + - record.balanceA + "," + - record.balanceB + "," + + record.balanceBaseAsset + "," + + record.balanceQuotedAsset + "," + record.accumulatedProfitLoss + "," + record.lastTradeProfitLoss + "," + record.stopLoss + "," + @@ -514,9 +513,8 @@ fileContent = fileContent + separator + '[' + record.begin + "," + record.end + "," + - record.amount + "," + - record.balanceA + "," + - record.balanceB + "," + + record.balanceBaseAsset + "," + + record.balanceQuotedAsset + "," + record.accumulatedProfitLoss + "," + record.lastTradeProfitLoss + "," + record.stopLoss + "," + diff --git a/TradingSimulation.js b/TradingSimulation.js index 44d26b0be..c45599c9c 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -47,7 +47,6 @@ let tradingSystem = bot.TRADING_SYSTEM - /* Initial Default Values */ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> bot.VALUES_TO_USE.timeRange.initialDatetime = " + bot.VALUES_TO_USE.timeRange.initialDatetime); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> bot.VALUES_TO_USE.timeRange.finalDatetime = " + bot.VALUES_TO_USE.timeRange.finalDatetime); } @@ -253,7 +252,6 @@ } /* Finding the Current Element on Single Files */ - function isItInside(elementWithTimestamp, elementWithBeginEnd) { if (elementWithTimestamp.timestamp >= elementWithBeginEnd.begin && elementWithTimestamp.timestamp <= elementWithBeginEnd.end) { return true @@ -317,24 +315,6 @@ } previousLoopingDay = loopingDay.valueOf() - /* If any of the needed data dependencies is missing for this particular candle, then we jump the candle*/ - /* - for (let k = 0; k < dataDependencies.length; k++) { - let dataDependencyNode = dataDependencies[k] - let singularVariableName = dataDependencyNode.referenceParent.parentNode.code.singularVariableName - let pluralVariableName = dataDependencyNode.referenceParent.parentNode.code.pluralVariableName - let product = currentChart[pluralVariableName] - let currentElement = currentChart[singularVariableName] - - if (currentElement === undefined) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Candle because " + singularVariableName + " is undefined."); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> For some indicators it is normal to start after a few candles."); } - controlLoop(); - return - } - } - */ - variable.periods++; variable.days = variable.periods * timeFrame / ONE_DAY_IN_MILISECONDS; @@ -446,7 +426,7 @@ if (openStage !== undefined) { /* Default Values*/ - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { positionSize = variable.balanceBaseAsset; positionRate = candle.close; } else { @@ -469,13 +449,13 @@ initialDefinition.positionSize.formula.error = err.message } if (isNaN(positionSize)) { - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { positionSize = variable.balanceBaseAsset; } else { positionSize = variable.balanceQuotedAsset; } } else { - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { if (positionSize > variable.balanceBaseAsset) { positionSize = variable.balanceBaseAsset } } else { if (positionSize > variable.balanceQuotedAsset) { positionSize = variable.balanceQuotedAsset } @@ -496,7 +476,7 @@ initialDefinition.positionRate.formula.error = err.message } if (isNaN(positionRate)) { - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { positionRate = candle.close; } else { positionRate = candle.close; @@ -874,7 +854,6 @@ function newCondition(key, node, chart) { let condition; - let error = '' let value try { @@ -921,7 +900,7 @@ let maximumBalance let balance - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { balance = variable.balanceBaseAsset minimumBalance = variable.minimumBalanceBaseAsset maximumBalance = variable.maximumBalanceBaseAsset @@ -1011,7 +990,7 @@ } /* Trigger Off Condition */ - if (strategyStage === 'Trigger Stage') { + if (variable.strategyStage === 'Trigger Stage') { let strategy = tradingSystem.strategies[strategyIndex]; @@ -1061,7 +1040,7 @@ } /* Take Position Condition */ - if (strategyStage === 'Trigger Stage') { + if (variable.strategyStage === 'Trigger Stage') { let strategy = tradingSystem.strategies[strategyIndex]; @@ -1114,7 +1093,7 @@ /* Stop Loss Management */ if ( - (strategyStage === 'Open Stage' || variable.strategyStage === 'Manage Stage') && + (variable.strategyStage === 'Open Stage' || variable.strategyStage === 'Manage Stage') && takePositionNow !== true ) { @@ -1285,7 +1264,7 @@ /* Take Profit Management */ if ( - (strategyStage === 'Open Stage' || variable.strategyStage === 'Manage Stage') && + (variable.strategyStage === 'Open Stage' || variable.strategyStage === 'Manage Stage') && takePositionNow !== true ) { @@ -1458,7 +1437,7 @@ /* Keeping Position Counters Up-to-date */ if ( - (strategyStage === 'Open Stage' || variable.strategyStage === 'Manage Stage') + (variable.strategyStage === 'Open Stage' || variable.strategyStage === 'Manage Stage') ) { if (takePositionNow === true) { @@ -1500,7 +1479,7 @@ /* Checking if Stop or Take Profit were hit */ if ( - (strategyStage === 'Open Stage' || variable.strategyStage === 'Manage Stage') && + (variable.strategyStage === 'Open Stage' || variable.strategyStage === 'Manage Stage') && takePositionNow !== true ) { let strategy = tradingSystem.strategies[strategyIndex]; @@ -1510,7 +1489,7 @@ /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - if ((baseAsset === variable.marketBaseAsset && candle.max >= variable.stopLoss) || (baseAsset !== variable.marketBaseAsset && candle.min <= variable.stopLoss)) { + if ((variable.baseAsset === variable.marketBaseAsset && candle.max >= variable.stopLoss) || (variable.baseAsset !== variable.marketBaseAsset && candle.min <= variable.stopLoss)) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Stop Loss was hit."); } /* @@ -1520,7 +1499,7 @@ If we take the stop loss value at those situation would be a huge distortion of facts. */ - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { if (stopLoss < candle.min) { variable.stopLoss = candle.min } @@ -1535,7 +1514,7 @@ /* Apply the Slippage */ let slippageAmount = slippedStopLoss * bot.VALUES_TO_USE.slippage.stopLoss / 100 - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { slippedStopLoss = slippedStopLoss + slippageAmount } else { slippedStopLoss = slippedStopLoss - slippageAmount @@ -1558,7 +1537,7 @@ /* Take Profit condition: Here we verify if the Take Profit was hit or not. */ - if ((baseAsset === variable.marketBaseAsset && candle.min <= variable.takeProfit) || (baseAsset !== variable.marketBaseAsset && candle.max >= variable.takeProfit)) { + if ((variable.baseAsset === variable.marketBaseAsset && candle.min <= variable.takeProfit) || (variable.baseAsset !== variable.marketBaseAsset && candle.max >= variable.takeProfit)) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Take Profit was hit."); } /* @@ -1568,7 +1547,7 @@ If we take the stop loss value at those situation would be a huge distortion of facts. */ - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { if (takeProfit > candle.max) { variable.takeProfit = candle.max } @@ -1582,7 +1561,7 @@ /* Apply the Slippage */ let slippageAmount = slippedTakeProfit * bot.VALUES_TO_USE.slippage.takeProfit / 100 - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { slippedTakeProfit = slippedTakeProfit + slippageAmount } else { slippedTakeProfit = slippedTakeProfit - slippageAmount @@ -1625,7 +1604,7 @@ /* We take what was calculated at the formula and apply the slippage. */ let slippageAmount = variable.tradePositionRate * bot.VALUES_TO_USE.slippage.positionRate / 100 - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { variable.tradePositionRate = variable.tradePositionRate - slippageAmount } else { variable.tradePositionRate = variable.tradePositionRate + slippageAmount @@ -1712,7 +1691,7 @@ /* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */ if (variable.executionContext !== undefined) { if (variable.executionContext.periods !== undefined) { - if (periods <= variable.executionContext.periods) { + if (variable.periods <= variable.executionContext.periods) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because it was already placed at a previous execution."); } takePositionAtSimulation() return; @@ -1739,7 +1718,7 @@ let orderSide - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { orderSide = "sell" orderPrice = variable.tradePositionRate - 100 // This is going to be ingnored at the Exchange API for now since we only put market orders. @@ -1759,7 +1738,7 @@ variable.executionContext = { status: "Taking Position", - variable.periods: variable.periods, + periods: variable.periods, } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Ready to create order."); } @@ -1774,7 +1753,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_OK_RESPONSE "); } variable.executionContext = { status: "In a Position", - variable.periods: variable.periods, + periods: variable.periods, amountA: amountA, amountB: amountB, orderId: order.id @@ -1824,7 +1803,7 @@ let feePaid = 0 - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { feePaid = variable.tradePositionSize * variable.tradePositionRate * bot.VALUES_TO_USE.feeStructure.taker / 100 @@ -1907,7 +1886,7 @@ /* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */ if (variable.executionContext !== undefined) { if (variable.executionContext.periods !== undefined) { - if (periods <= variable.executionContext.periods) { + if (variable.periods <= variable.executionContext.periods) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> Exiting function because this closing was already submited at a previous execution."); } closePositionAtSimulation() return; @@ -1920,7 +1899,7 @@ let amountB let orderSide - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { orderSide = "buy" orderPrice = ticker.last + 100; // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. @@ -1940,7 +1919,7 @@ variable.executionContext = { status: "Closing Position", - variable.periods: variable.periods, + periods: variable.periods, } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> About to close position at the exchange."); } @@ -1955,7 +1934,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> DEFAULT_OK_RESPONSE "); } variable.executionContext = { status: "Position Closed", - variable.periods: variable.periods, + periods: variable.periods, amountA: amountA, amountB: amountB, orderId: order.id @@ -1996,7 +1975,7 @@ let feePaid = 0 - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { strategy.positionSize = variable.balanceQuotedAsset / closeRate; strategy.positionRate = closeRate; @@ -2014,7 +1993,7 @@ variable.balanceBaseAsset = 0; } - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { variable.lastTradeProfitLoss = variable.balanceBaseAsset - variable.previousBalanceBaseAsset; variable.lastTradeROI = variable.lastTradeProfitLoss * 100 / variable.tradePositionSize; if (isNaN(lastTradeROI)) { variable.lastTradeROI = 0; } @@ -2028,13 +2007,13 @@ variable.currentTrade.lastTradeROI = variable.lastTradeROI; - if (lastTradeProfitLoss > 0) { + if (variable.lastTradeProfitLoss > 0) { variable.hits++; } else { variable.fails++; } - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { variable.ROI = (variable.initialBalanceBaseAsset + variable.accumulatedProfitLoss) / variable.initialBalanceBaseAsset - 1; variable.hitRatio = variable.hits / variable.tradesCount; variable.anualizedRateOfReturn = variable.ROI / variable.days * 365; @@ -2065,7 +2044,7 @@ } /* Closing the Closing Stage */ - if (strategyStage === 'Close Stage') { + if (variable.strategyStage === 'Close Stage') { if (candle.begin - 5 * 60 * 1000 > timerToCloseStage) { variable.currentStrategy.number = variable.strategyIndex @@ -2094,26 +2073,21 @@ function addRecord() { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> addRecord -> Entering function."); } - - // Since we are going to write the message to a file that the Simulation Executor is going to read, we use the abbreviations. - let messageType; - let message; let simulationRecord; - if (balanceBaseAsset === Infinity) { + if (variable.balanceBaseAsset === Infinity) { variable.balanceBaseAsset = Number.MAX_SAFE_INTEGER } - if (balanceQuotedAsset === Infinity) { + if (variable.balanceQuotedAsset === Infinity) { variable.balanceQuotedAsset = Number.MAX_SAFE_INTEGER } simulationRecord = { begin: candle.begin, end: candle.end, - amount: 1, - balanceA: variable.balanceBaseAsset, - balanceB: variable.balanceQuotedAsset, + balanceBaseAsset: variable.balanceBaseAsset, + balanceQuotedAsset: variable.balanceQuotedAsset, accumulatedProfitLoss: variable.accumulatedProfitLoss, lastTradeProfitLoss: variable.lastTradeProfitLoss, stopLoss: variable.stopLoss, @@ -2198,7 +2172,7 @@ variable.currentTrade.endRate = candle.close /* Here we will calculate the ongoing variable.ROI */ - if (baseAsset === variable.marketBaseAsset) { + if (variable.baseAsset === variable.marketBaseAsset) { variable.currentTrade.lastTradeROI = (tradePositionRate - candle.close) / variable.tradePositionRate * 100 } else { variable.currentTrade.lastTradeROI = (candle.close - variable.tradePositionRate) / variable.tradePositionRate * 100 @@ -2251,7 +2225,7 @@ } } - if (periods > lastPeriodAnnounced) { + if (variable.periods > lastPeriodAnnounced) { if (isNaN(value) === false) { /* The Value Variation is what tells us how much the value already announced must change in order to annouce it again. */ @@ -2284,7 +2258,7 @@ } else { newAnnouncementRecord = { key: key, - variable.periods: variable.periods, + periods: variable.periods, value: value } variable.announcements.push(newAnnouncementRecord) From e3fa8231bf8fabe1d11b3042d67d173c49c207a7 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 19 May 2020 20:47:37 +0200 Subject: [PATCH 21/44] Update TradingSimulation.js --- TradingSimulation.js | 310 ++++++++++++++++++++++--------------------- 1 file changed, 158 insertions(+), 152 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index c45599c9c..1df29a8d6 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -93,17 +93,19 @@ variable.takeProfitPhase = -1 variable.takeProfitStage = 'No Stage' - variable.currentStrategy = { + variable.current = {} + + variable.current.strategy = { begin: 0, end: 0, status: 0, number: 0, beginRate: 0, endRate: 0, - triggerOnSituation: '' + situationName: '' } - variable.currentTrade = { + variable.current.position = { begin: 0, end: 0, status: 0, @@ -111,11 +113,11 @@ exitType: 0, beginRate: 0, endRate: 0, - takePositionSituation: '' + situationName: '' } - variable.balanceBaseAsset = bot.VALUES_TO_USE.initialBalanceA - variable.balanceQuotedAsset = bot.VALUES_TO_USE.initialBalanceB + variable.current.balance.baseAsset = bot.VALUES_TO_USE.initialBalanceA + variable.current.balance.quotedAsset = bot.VALUES_TO_USE.initialBalanceB variable.initialBalanceBaseAsset = bot.VALUES_TO_USE.initialBalanceA variable.minimumBalanceBaseAsset = bot.VALUES_TO_USE.minimumBalanceA @@ -125,29 +127,33 @@ variable.minimumBalanceQuotedAsset = bot.VALUES_TO_USE.minimumBalanceB variable.maximumBalanceQuotedAsset = bot.VALUES_TO_USE.maximumBalanceB - variable.lastTradeProfitLoss = 0 - variable.accumulatedProfitLoss = 0 - variable.lastTradeROI = 0 + variable.lastTrade = { + profitLoss: 0, + ROI: 0 + } + + variable.episode = { + profitLoss: 0, + tradesCount: 0, + fails: 0, + hits: 0, + hitRatio: 0, + periods: 0, + days: 0, + ROI: 0, + anualizedRateOfReturn: 0 + } - variable.tradesCount = 0 - variable.fails = 0 - variable.hits = 0 - variable.periods = 0 variable.positionPeriods = 0 - variable.days = 0 /* Usefull counters for conditions and formulas */ - variable.distanceToLast = { + variable.distanceToEvent = { triggerOn: 0, triggerOff: 0, takePosition: 0, closePosition: 0 } - variable.hitRatio = 0; - variable.ROI = 0; - variable.anualizedRateOfReturn = 0; - variable.announcements = [] /* Allowing these to be accesible at formulas */ @@ -315,8 +321,8 @@ } previousLoopingDay = loopingDay.valueOf() - variable.periods++; - variable.days = variable.periods * timeFrame / ONE_DAY_IN_MILISECONDS; + variable.episode.periods++; + variable.episode.days = variable.episode.periods * timeFrame / ONE_DAY_IN_MILISECONDS; if (processingDailyFiles) { @@ -329,7 +335,7 @@ controlLoop(); return /* Note here that in the last candle of the first day or the second day it will use an incomplete candle and partially calculated indicators. - if we skip these two variable.periods, then there will be a hole in the file since the last period will be missing. */ + if we skip these two variable.episode.periods, then there will be a hole in the file since the last period will be missing. */ } } @@ -427,10 +433,10 @@ /* Default Values*/ if (variable.baseAsset === variable.marketBaseAsset) { - positionSize = variable.balanceBaseAsset; + positionSize = variable.current.balance.baseAsset; positionRate = candle.close; } else { - positionSize = variable.balanceQuotedAsset; + positionSize = variable.current.balance.quotedAsset; positionRate = candle.close; } @@ -450,15 +456,15 @@ } if (isNaN(positionSize)) { if (variable.baseAsset === variable.marketBaseAsset) { - positionSize = variable.balanceBaseAsset; + positionSize = variable.current.balance.baseAsset; } else { - positionSize = variable.balanceQuotedAsset; + positionSize = variable.current.balance.quotedAsset; } } else { if (variable.baseAsset === variable.marketBaseAsset) { - if (positionSize > variable.balanceBaseAsset) { positionSize = variable.balanceBaseAsset } + if (positionSize > variable.current.balance.baseAsset) { positionSize = variable.current.balance.baseAsset } } else { - if (positionSize > variable.balanceQuotedAsset) { positionSize = variable.balanceQuotedAsset } + if (positionSize > variable.current.balance.quotedAsset) { positionSize = variable.current.balance.quotedAsset } } } } @@ -901,11 +907,11 @@ let balance if (variable.baseAsset === variable.marketBaseAsset) { - balance = variable.balanceBaseAsset + balance = variable.current.balance.baseAsset minimumBalance = variable.minimumBalanceBaseAsset maximumBalance = variable.maximumBalanceBaseAsset } else { - balance = variable.balanceQuotedAsset + balance = variable.current.balance.quotedAsset minimumBalance = variable.minimumBalanceQuotedAsset maximumBalance = variable.maximumBalanceQuotedAsset } @@ -970,12 +976,12 @@ checkAnnouncements(triggerStage) variable.strategyIndex = j; - variable.currentStrategy.begin = candle.begin; - variable.currentStrategy.beginRate = candle.min; - variable.currentStrategy.endRate = candle.min; // In case the strategy does not get exited - variable.currentStrategy.triggerOnSituation = situation.name + variable.current.strategy.begin = candle.begin; + variable.current.strategy.beginRate = candle.min; + variable.current.strategy.endRate = candle.min; // In case the strategy does not get exited + variable.current.strategy.situationName = situation.name - variable.distanceToLast.triggerOn = 1; + variable.distanceToEvent.triggerOn = 1; checkAnnouncements(triggerStage.triggerOn) @@ -1020,14 +1026,14 @@ if (passed) { - variable.currentStrategy.number = variable.strategyIndex - variable.currentStrategy.end = candle.end; - variable.currentStrategy.endRate = candle.min; - variable.currentStrategy.status = 1; // This means the strategy is closed, i.e. that has a begin and end. + variable.current.strategy.number = variable.strategyIndex + variable.current.strategy.end = candle.end; + variable.current.strategy.endRate = candle.min; + variable.current.strategy.status = 1; // This means the strategy is closed, i.e. that has a begin and end. variable.strategyStage = 'No Stage'; variable.strategyIndex = -1; - variable.distanceToLast.triggerOff = 1; + variable.distanceToEvent.triggerOff = 1; checkAnnouncements(triggerStage.triggerOff) @@ -1079,7 +1085,7 @@ variable.takeProfitPhase = 0; takePositionNow = true - variable.currentTrade.takePositionSituation = situation.name + variable.current.position.situationName = situation.name checkAnnouncements(triggerStage.takePosition) @@ -1454,27 +1460,27 @@ /* Keeping Distance Counters Up-to-date */ if ( - variable.distanceToLast.triggerOn > 0 // with this we avoind counting before the first event happens. + variable.distanceToEvent.triggerOn > 0 // with this we avoind counting before the first event happens. ) { - variable.distanceToLast.triggerOn++; + variable.distanceToEvent.triggerOn++; } if ( - variable.distanceToLast.triggerOff > 0 // with this we avoind counting before the first event happens. + variable.distanceToEvent.triggerOff > 0 // with this we avoind counting before the first event happens. ) { - variable.distanceToLast.triggerOff++; + variable.distanceToEvent.triggerOff++; } if ( - variable.distanceToLast.takePosition > 0 // with this we avoind counting before the first event happens. + variable.distanceToEvent.takePosition > 0 // with this we avoind counting before the first event happens. ) { - variable.distanceToLast.takePosition++; + variable.distanceToEvent.takePosition++; } if ( - variable.distanceToLast.closePosition > 0 // with this we avoind counting before the first event happens. + variable.distanceToEvent.closePosition > 0 // with this we avoind counting before the first event happens. ) { - variable.distanceToLast.closePosition++; + variable.distanceToEvent.closePosition++; } /* Checking if Stop or Take Profit were hit */ @@ -1527,10 +1533,10 @@ variable.stopLossStage = 'No Stage'; variable.takeProfitStage = 'No Stage'; - variable.currentTrade.end = candle.end; - variable.currentTrade.status = 1; - variable.currentTrade.exitType = 1; - variable.currentTrade.endRate = closeRate; + variable.current.position.end = candle.end; + variable.current.position.status = 1; + variable.current.position.exitType = 1; + variable.current.position.endRate = closeRate; closePositionNow = true; } @@ -1575,10 +1581,10 @@ variable.stopLossStage = 'No Stage'; variable.takeProfitStage = 'No Stage'; - variable.currentTrade.end = candle.end; - variable.currentTrade.status = 1; - variable.currentTrade.exitType = 2; - variable.currentTrade.endRate = closeRate; + variable.current.position.end = candle.end; + variable.current.position.status = 1; + variable.current.position.exitType = 2; + variable.current.position.endRate = closeRate; closePositionNow = true; @@ -1593,7 +1599,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionNow -> Entering code block."); } /* Inicializing this counter */ - variable.distanceToLast.takePosition = 1; + variable.distanceToEvent.takePosition = 1; /* Position size and rate */ let strategy = tradingSystem.strategies[strategyIndex]; @@ -1611,8 +1617,8 @@ } /* Update the trade record information. */ - variable.currentTrade.begin = candle.begin; - variable.currentTrade.beginRate = variable.tradePositionRate; + variable.current.position.begin = candle.begin; + variable.current.position.beginRate = variable.tradePositionRate; /* Check if we need to execute. */ if (currentCandleIndex > candles.length - 10) { /* Only at the last candles makes sense to check if we are in live mode or not.*/ @@ -1691,7 +1697,7 @@ /* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */ if (variable.executionContext !== undefined) { if (variable.executionContext.periods !== undefined) { - if (variable.periods <= variable.executionContext.periods) { + if (variable.episode.periods <= variable.executionContext.periods) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because it was already placed at a previous execution."); } takePositionAtSimulation() return; @@ -1738,7 +1744,7 @@ variable.executionContext = { status: "Taking Position", - periods: variable.periods, + periods: variable.episode.periods, } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Ready to create order."); } @@ -1753,7 +1759,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_OK_RESPONSE "); } variable.executionContext = { status: "In a Position", - periods: variable.periods, + periods: variable.episode.periods, amountA: amountA, amountB: amountB, orderId: order.id @@ -1795,11 +1801,11 @@ calculateTakeProfit(); calculateStopLoss(); - variable.previousBalanceBaseAsset = variable.balanceBaseAsset; - variable.previousBalanceQuotedAsset = variable.balanceQuotedAsset; + variable.previousBalanceBaseAsset = variable.current.balance.baseAsset; + variable.previousBalanceQuotedAsset = variable.current.balance.quotedAsset; - variable.lastTradeProfitLoss = 0; - variable.lastTradeROI = 0; + variable.lastTrade.profitLoss = 0; + variable.lastTrade.ROI = 0; let feePaid = 0 @@ -1807,14 +1813,14 @@ feePaid = variable.tradePositionSize * variable.tradePositionRate * bot.VALUES_TO_USE.feeStructure.taker / 100 - variable.balanceQuotedAsset = variable.balanceQuotedAsset + variable.tradePositionSize * variable.tradePositionRate - feePaid; - variable.balanceBaseAsset = variable.balanceBaseAsset - variable.tradePositionSize; + variable.current.balance.quotedAsset = variable.current.balance.quotedAsset + variable.tradePositionSize * variable.tradePositionRate - feePaid; + variable.current.balance.baseAsset = variable.current.balance.baseAsset - variable.tradePositionSize; } else { feePaid = variable.tradePositionSize / variable.tradePositionRate * bot.VALUES_TO_USE.feeStructure.taker / 100 - variable.balanceBaseAsset = variable.balanceBaseAsset + variable.tradePositionSize / variable.tradePositionRate - feePaid; - variable.balanceQuotedAsset = variable.balanceQuotedAsset - variable.tradePositionSize; + variable.current.balance.baseAsset = variable.current.balance.baseAsset + variable.tradePositionSize / variable.tradePositionRate - feePaid; + variable.current.balance.quotedAsset = variable.current.balance.quotedAsset - variable.tradePositionSize; } addRecord(); @@ -1831,7 +1837,7 @@ closePositionNow = false /* Inicializing this counter */ - variable.distanceToLast.closePosition = 1; + variable.distanceToEvent.closePosition = 1; /* Position size and rate */ let strategy = tradingSystem.strategies[strategyIndex]; @@ -1886,7 +1892,7 @@ /* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */ if (variable.executionContext !== undefined) { if (variable.executionContext.periods !== undefined) { - if (variable.periods <= variable.executionContext.periods) { + if (variable.episode.periods <= variable.executionContext.periods) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> Exiting function because this closing was already submited at a previous execution."); } closePositionAtSimulation() return; @@ -1904,22 +1910,22 @@ orderPrice = ticker.last + 100; // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. - amountA = variable.balanceQuotedAsset - amountB = variable.balanceQuotedAsset / orderPrice + amountA = variable.current.balance.quotedAsset + amountB = variable.current.balance.quotedAsset / orderPrice } else { orderSide = "sell" orderPrice = ticker.last - 100; // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. - amountA = variable.balanceBaseAsset * orderPrice - amountB = variable.balanceBaseAsset + amountA = variable.current.balance.baseAsset * orderPrice + amountB = variable.current.balance.baseAsset } variable.executionContext = { status: "Closing Position", - periods: variable.periods, + periods: variable.episode.periods, } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> About to close position at the exchange."); } @@ -1934,7 +1940,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> DEFAULT_OK_RESPONSE "); } variable.executionContext = { status: "Position Closed", - periods: variable.periods, + periods: variable.episode.periods, amountA: amountA, amountB: amountB, orderId: order.id @@ -1971,56 +1977,56 @@ function closePositionAtSimulation() { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> closePositionAtSimulation -> Entering function."); } - variable.tradesCount++; + variable.episode.tradesCount++; let feePaid = 0 if (variable.baseAsset === variable.marketBaseAsset) { - strategy.positionSize = variable.balanceQuotedAsset / closeRate; + strategy.positionSize = variable.current.balance.quotedAsset / closeRate; strategy.positionRate = closeRate; - feePaid = variable.balanceQuotedAsset / closeRate * bot.VALUES_TO_USE.feeStructure.taker / 100 + feePaid = variable.current.balance.quotedAsset / closeRate * bot.VALUES_TO_USE.feeStructure.taker / 100 - variable.balanceBaseAsset = variable.balanceBaseAsset + variable.balanceQuotedAsset / closeRate - feePaid; - variable.balanceQuotedAsset = 0; + variable.current.balance.baseAsset = variable.current.balance.baseAsset + variable.current.balance.quotedAsset / closeRate - feePaid; + variable.current.balance.quotedAsset = 0; } else { - strategy.positionSize = variable.balanceBaseAsset * closeRate; + strategy.positionSize = variable.current.balance.baseAsset * closeRate; strategy.positionRate = closeRate; - feePaid = variable.balanceBaseAsset * closeRate * bot.VALUES_TO_USE.feeStructure.taker / 100 + feePaid = variable.current.balance.baseAsset * closeRate * bot.VALUES_TO_USE.feeStructure.taker / 100 - variable.balanceQuotedAsset = variable.balanceQuotedAsset + variable.balanceBaseAsset * closeRate - feePaid; - variable.balanceBaseAsset = 0; + variable.current.balance.quotedAsset = variable.current.balance.quotedAsset + variable.current.balance.baseAsset * closeRate - feePaid; + variable.current.balance.baseAsset = 0; } if (variable.baseAsset === variable.marketBaseAsset) { - variable.lastTradeProfitLoss = variable.balanceBaseAsset - variable.previousBalanceBaseAsset; - variable.lastTradeROI = variable.lastTradeProfitLoss * 100 / variable.tradePositionSize; - if (isNaN(lastTradeROI)) { variable.lastTradeROI = 0; } - variable.accumulatedProfitLoss = variable.balanceBaseAsset - variable.initialBalanceBaseAsset; + variable.lastTrade.profitLoss = variable.current.balance.baseAsset - variable.previousBalanceBaseAsset; + variable.lastTrade.ROI = variable.lastTrade.profitLoss * 100 / variable.tradePositionSize; + if (isNaN(lastTradeROI)) { variable.lastTrade.ROI = 0; } + variable.episode.profitLoss = variable.current.balance.baseAsset - variable.initialBalanceBaseAsset; } else { - variable.lastTradeProfitLoss = variable.balanceQuotedAsset - variable.previousBalanceQuotedAsset; - variable.lastTradeROI = variable.lastTradeProfitLoss * 100 / variable.tradePositionSize; - if (isNaN(lastTradeROI)) { variable.lastTradeROI = 0; } - variable.accumulatedProfitLoss = variable.balanceQuotedAsset - variable.initialBalanceQuotedAsset; + variable.lastTrade.profitLoss = variable.current.balance.quotedAsset - variable.previousBalanceQuotedAsset; + variable.lastTrade.ROI = variable.lastTrade.profitLoss * 100 / variable.tradePositionSize; + if (isNaN(lastTradeROI)) { variable.lastTrade.ROI = 0; } + variable.episode.profitLoss = variable.current.balance.quotedAsset - variable.initialBalanceQuotedAsset; } - variable.currentTrade.lastTradeROI = variable.lastTradeROI; + variable.current.position.lastTradeROI = variable.lastTrade.ROI; - if (variable.lastTradeProfitLoss > 0) { - variable.hits++; + if (variable.lastTrade.profitLoss > 0) { + variable.episode.hits++; } else { - variable.fails++; + variable.episode.fails++; } if (variable.baseAsset === variable.marketBaseAsset) { - variable.ROI = (variable.initialBalanceBaseAsset + variable.accumulatedProfitLoss) / variable.initialBalanceBaseAsset - 1; - variable.hitRatio = variable.hits / variable.tradesCount; - variable.anualizedRateOfReturn = variable.ROI / variable.days * 365; + variable.episode.ROI = (variable.initialBalanceBaseAsset + variable.episode.profitLoss) / variable.initialBalanceBaseAsset - 1; + variable.episode.hitRatio = variable.episode.hits / variable.episode.tradesCount; + variable.anualizedRateOfReturn = variable.episode.ROI / variable.episode.days * 365; } else { - variable.ROI = (variable.initialBalanceQuotedAsset + variable.accumulatedProfitLoss) / variable.initialBalanceQuotedAsset - 1; - variable.hitRatio = variable.hits / variable.tradesCount; - variable.anualizedRateOfReturn = variable.ROI / variable.days * 365; + variable.episode.ROI = (variable.initialBalanceQuotedAsset + variable.episode.profitLoss) / variable.initialBalanceQuotedAsset - 1; + variable.episode.hitRatio = variable.episode.hits / variable.episode.tradesCount; + variable.anualizedRateOfReturn = variable.episode.ROI / variable.episode.days * 365; } addRecord(); @@ -2047,16 +2053,16 @@ if (variable.strategyStage === 'Close Stage') { if (candle.begin - 5 * 60 * 1000 > timerToCloseStage) { - variable.currentStrategy.number = variable.strategyIndex - variable.currentStrategy.end = candle.end; - variable.currentStrategy.endRate = candle.min; - variable.currentStrategy.status = 1; // This means the strategy is closed, i.e. that has a begin and end. + variable.current.strategy.number = variable.strategyIndex + variable.current.strategy.end = candle.end; + variable.current.strategy.endRate = candle.min; + variable.current.strategy.status = 1; // This means the strategy is closed, i.e. that has a begin and end. variable.strategyIndex = -1; variable.strategyStage = 'No Stage'; timerToCloseStage = 0 - variable.distanceToLast.triggerOff = 1; + variable.distanceToEvent.triggerOff = 1; if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing the Closing Stage -> Exiting Close Stage."); } } else { @@ -2075,32 +2081,32 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> addRecord -> Entering function."); } let simulationRecord; - if (variable.balanceBaseAsset === Infinity) { - variable.balanceBaseAsset = Number.MAX_SAFE_INTEGER + if (variable.current.balance.baseAsset === Infinity) { + variable.current.balance.baseAsset = Number.MAX_SAFE_INTEGER } - if (variable.balanceQuotedAsset === Infinity) { - variable.balanceQuotedAsset = Number.MAX_SAFE_INTEGER + if (variable.current.balance.quotedAsset === Infinity) { + variable.current.balance.quotedAsset = Number.MAX_SAFE_INTEGER } simulationRecord = { begin: candle.begin, end: candle.end, - balanceBaseAsset: variable.balanceBaseAsset, - balanceQuotedAsset: variable.balanceQuotedAsset, - accumulatedProfitLoss: variable.accumulatedProfitLoss, - lastTradeProfitLoss: variable.lastTradeProfitLoss, + balanceBaseAsset: variable.current.balance.baseAsset, + balanceQuotedAsset: variable.current.balance.quotedAsset, + accumulatedProfitLoss: variable.episode.profitLoss, + lastTradeProfitLoss: variable.lastTrade.profitLoss, stopLoss: variable.stopLoss, - tradesCount: variable.tradesCount, - hits: variable.hits, - fails: variable.fails, - hitRatio: variable.hitRatio, - ROI: variable.ROI, - periods: variable.periods, - days: variable.days, + tradesCount: variable.episode.tradesCount, + hits: variable.episode.hits, + fails: variable.episode.fails, + hitRatio: variable.episode.hitRatio, + ROI: variable.episode.ROI, + periods: variable.episode.periods, + days: variable.episode.days, anualizedRateOfReturn: variable.anualizedRateOfReturn, positionRate: variable.tradePositionRate, - lastTradeROI: variable.lastTradeROI, + lastTradeROI: variable.lastTrade.ROI, strategy: variable.strategyIndex, takeProfit: variable.takeProfit, stopLossPhase: variable.stopLossPhase, @@ -2118,10 +2124,10 @@ marketQuotedAsset: '"' + variable.marketQuotedAsset + '"' , positionPeriods: variable.positionPeriods, positionDays: variable.positionDays, - distanceToLastTriggerOn: variable.distanceToLast.triggerOn, - distanceToLastTriggerOff: variable.distanceToLast.triggerOff, - distanceToLastTakePosition: variable.distanceToLast.takePosition, - distanceToLastClosePosition: variable.distanceToLast.closePosition + distanceToEventTriggerOn: variable.distanceToEvent.triggerOn, + distanceToEventTriggerOff: variable.distanceToEvent.triggerOff, + distanceToEventTakePosition: variable.distanceToEvent.takePosition, + distanceToEventClosePosition: variable.distanceToEvent.closePosition } recordsArray.push(simulationRecord); @@ -2141,24 +2147,24 @@ Lets see if there will be an open strategy ... Except if we are at the head of the market (remember we skipped the last candle for not being closed.) */ - if (currentStrategy.begin !== 0 && variable.currentStrategy.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { - variable.currentStrategy.status = 2; // This means the strategy is open, i.e. that has a begin but no end. - variable.currentStrategy.end = candle.end + if (currentStrategy.begin !== 0 && variable.current.strategy.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { + variable.current.strategy.status = 2; // This means the strategy is open, i.e. that has a begin but no end. + variable.current.strategy.end = candle.end } /* Prepare the information for the Strategies File*/ - if (currentStrategy.begin !== 0 && variable.currentStrategy.end !== 0) + if (currentStrategy.begin !== 0 && variable.current.strategy.end !== 0) { strategiesArray.push(currentStrategy); - variable.currentStrategy = { + variable.current.strategy = { begin: 0, end: 0, status: 0, number: 0, beginRate: 0, endRate: 0, - triggerOnSituation: '' + situationName: '' } } @@ -2166,27 +2172,27 @@ Lets see if there will be an open trade ... Except if we are at the head of the market (remember we skipped the last candle for not being closed.) */ - if (variable.currentTrade.begin !== 0 && variable.currentTrade.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { - variable.currentTrade.status = 2; // This means the trade is open - variable.currentTrade.end = candle.end - variable.currentTrade.endRate = candle.close + if (variable.current.position.begin !== 0 && variable.current.position.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { + variable.current.position.status = 2; // This means the trade is open + variable.current.position.end = candle.end + variable.current.position.endRate = candle.close - /* Here we will calculate the ongoing variable.ROI */ + /* Here we will calculate the ongoing variable.episode.ROI */ if (variable.baseAsset === variable.marketBaseAsset) { - variable.currentTrade.lastTradeROI = (tradePositionRate - candle.close) / variable.tradePositionRate * 100 + variable.current.position.lastTradeROI = (tradePositionRate - candle.close) / variable.tradePositionRate * 100 } else { - variable.currentTrade.lastTradeROI = (candle.close - variable.tradePositionRate) / variable.tradePositionRate * 100 + variable.current.position.lastTradeROI = (candle.close - variable.tradePositionRate) / variable.tradePositionRate * 100 } } /* Prepare the information for the Trades File */ - if (variable.currentTrade.begin !== 0 && variable.currentTrade.end !== 0) { + if (variable.current.position.begin !== 0 && variable.current.position.end !== 0) { - variable.currentTrade.profit = variable.lastTradeProfitLoss; + variable.current.position.profit = variable.lastTrade.profitLoss; - tradesArray.push(variable.currentTrade); + tradesArray.push(variable.current.position); - variable.currentTrade = { + variable.current.position = { begin: 0, end: 0, status: 0, @@ -2194,7 +2200,7 @@ exitType: 0, beginRate: 0, endRate: 0, - takePositionSituation: '' + situationName: '' } } @@ -2225,7 +2231,7 @@ } } - if (variable.periods > lastPeriodAnnounced) { + if (variable.episode.periods > lastPeriodAnnounced) { if (isNaN(value) === false) { /* The Value Variation is what tells us how much the value already announced must change in order to annouce it again. */ @@ -2253,12 +2259,12 @@ /* Next, we will remmeber this announcement was already done, so that it is not announced again in further processing of the same day. */ if (newAnnouncementRecord.periods !== undefined) { - newAnnouncementRecord.periods = variable.periods + newAnnouncementRecord.periods = variable.episode.periods newAnnouncementRecord.value = value } else { newAnnouncementRecord = { key: key, - periods: variable.periods, + periods: variable.episode.periods, value: value } variable.announcements.push(newAnnouncementRecord) From ed25240c7ac4b589a5b0d3904ee327370c6afd6f Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 20 May 2020 10:16:16 +0200 Subject: [PATCH 22/44] Update TradingSimulation.js --- TradingSimulation.js | 542 ++++++++++++++++++++++--------------------- 1 file changed, 274 insertions(+), 268 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index 1df29a8d6..556c5492e 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -74,65 +74,19 @@ variable.isInitialized = true - variable.stopLoss = 0 - variable.takeProfit = 0 + variable.initial = {} // Everything in here means the status at the begining of the episode. + variable.current = {} // Everything in here means that is happening right now. + variable.last = {} // Everything in here means that it already happened. + variable.minimun = {} // Everything in here means the minimun in the whole episode. + variable.maximun = {} // Everything in here means the maximun in the whole episode. + variable.previous = {} // Everything in here means the the value that was current before a new current value was set. + variable.distance = {} // Everything in here means the distance, measured in periods to whatever happened in the past, usually events. - /*Needed for statistics */ - variable.previousBalanceBaseAsset = 0 - variable.previousBalanceQuotedAsset = 0 - - /* Position Management */ - variable.tradePositionRate = 0 - variable.tradePositionSize = 0 - - /* Strategy and Phase Management */ - variable.strategyIndex = -1 - variable.strategyStage = 'No Stage' - variable.stopLossPhase = -1 - variable.stopLossStage = 'No Stage' - variable.takeProfitPhase = -1 - variable.takeProfitStage = 'No Stage' - - variable.current = {} - - variable.current.strategy = { - begin: 0, - end: 0, - status: 0, - number: 0, - beginRate: 0, - endRate: 0, - situationName: '' - } - - variable.current.position = { - begin: 0, - end: 0, - status: 0, - profit: 0, - exitType: 0, - beginRate: 0, - endRate: 0, - situationName: '' - } - - variable.current.balance.baseAsset = bot.VALUES_TO_USE.initialBalanceA - variable.current.balance.quotedAsset = bot.VALUES_TO_USE.initialBalanceB - - variable.initialBalanceBaseAsset = bot.VALUES_TO_USE.initialBalanceA - variable.minimumBalanceBaseAsset = bot.VALUES_TO_USE.minimumBalanceA - variable.maximumBalanceBaseAsset = bot.VALUES_TO_USE.maximumBalanceA - - variable.initialBalanceQuotedAsset = bot.VALUES_TO_USE.initialBalanceB - variable.minimumBalanceQuotedAsset = bot.VALUES_TO_USE.minimumBalanceB - variable.maximumBalanceQuotedAsset = bot.VALUES_TO_USE.maximumBalanceB - - variable.lastTrade = { - profitLoss: 0, - ROI: 0 - } - - variable.episode = { + variable.episode = { // An Episode represents each execution of the Simulation + baseAsset: bot.VALUES_TO_USE.baseAsset, + quotedAsset: bot.VALUES_TO_USE.quotedAsset, + marketBaseAsset: bot.market.baseAsset, + marketQuotedAsset: bot.market.quotedAsset, profitLoss: 0, tradesCount: 0, fails: 0, @@ -144,10 +98,29 @@ anualizedRateOfReturn: 0 } - variable.positionPeriods = 0 + variable.previous.balance.baseAsset = 0 + variable.previous.balance.quotedAsset = 0 - /* Usefull counters for conditions and formulas */ - variable.distanceToEvent = { + inializeCurrentStrategy() + initializeCurrentPosition() + + variable.current.balance.baseAsset = bot.VALUES_TO_USE.initialBalanceA + variable.current.balance.quotedAsset = bot.VALUES_TO_USE.initialBalanceB + + variable.initial.balance.baseAsset = bot.VALUES_TO_USE.initialBalanceA + variable.minimum.balance.baseAsset = bot.VALUES_TO_USE.minimumBalanceA + variable.maximum.balance.baseAsset = bot.VALUES_TO_USE.maximumBalanceA + + variable.initial.balance.quotedAsset = bot.VALUES_TO_USE.initialBalanceB + variable.minimum.balance.quotedAsset = bot.VALUES_TO_USE.minimumBalanceB + variable.maximum.balance.quotedAsset = bot.VALUES_TO_USE.maximumBalanceB + + variable.last.position = { + profitLoss: 0, + ROI: 0 + } + + variable.distance.toEvent = { triggerOn: 0, triggerOff: 0, takePosition: 0, @@ -156,13 +129,44 @@ variable.announcements = [] - /* Allowing these to be accesible at formulas */ - variable.baseAsset = bot.VALUES_TO_USE.baseAsset - variable.quotedAsset = bot.VALUES_TO_USE.quotedAsset - variable.marketBaseAsset = bot.market.baseAsset - variable.marketQuotedAsset = bot.market.quotedAsset } + function inializeCurrentStrategy() { + variable.current.strategy = { + index: -1, + stage: 'No Stage', + begin: 0, + end: 0, + status: 0, + number: 0, + beginRate: 0, + endRate: 0, + situationName: '' + } + } + + function initializeCurrentPosition() { + variable.current.position = { + begin: 0, + end: 0, + rate: 0, + size: 0, + stopLoss: 0, + takeProfit: 0, + status: 0, + profit: 0, + exitType: 0, + beginRate: 0, + endRate: 0, + periods: 0, + situationName: '', + stopLossPhase: -1, + stopLossStage: 'No Stage', + takeProfitPhase: -1, + takeProfitStage: 'No Stage' + } + } + /* Main Array and Maps */ let propertyName = 'at' + timeFrameLabel.replace('-', ''); let candles = chart[propertyName].candles @@ -432,7 +436,7 @@ if (openStage !== undefined) { /* Default Values*/ - if (variable.baseAsset === variable.marketBaseAsset) { + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { positionSize = variable.current.balance.baseAsset; positionRate = candle.close; } else { @@ -444,8 +448,8 @@ if (initialDefinition !== undefined) { - if (tradePositionSize !== 0) { - positionSize = variable.tradePositionSize + if (variable.current.position.size !== 0) { + positionSize = variable.current.position.size } else { if (initialDefinition.positionSize !== undefined) { if (initialDefinition.positionSize.formula !== undefined) { @@ -455,13 +459,13 @@ initialDefinition.positionSize.formula.error = err.message } if (isNaN(positionSize)) { - if (variable.baseAsset === variable.marketBaseAsset) { + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { positionSize = variable.current.balance.baseAsset; } else { positionSize = variable.current.balance.quotedAsset; } } else { - if (variable.baseAsset === variable.marketBaseAsset) { + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { if (positionSize > variable.current.balance.baseAsset) { positionSize = variable.current.balance.baseAsset } } else { if (positionSize > variable.current.balance.quotedAsset) { positionSize = variable.current.balance.quotedAsset } @@ -471,8 +475,8 @@ } } - if (tradePositionRate !== 0) { - positionRate = variable.tradePositionRate + if (variable.current.position.rate !== 0) { + positionRate = variable.current.position.rate } else { if (initialDefinition.positionRate !== undefined) { if (initialDefinition.positionRate.formula !== undefined) { @@ -482,7 +486,7 @@ initialDefinition.positionRate.formula.error = err.message } if (isNaN(positionRate)) { - if (variable.baseAsset === variable.marketBaseAsset) { + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { positionRate = candle.close; } else { positionRate = candle.close; @@ -899,21 +903,21 @@ /* Trigger On Conditions */ if ( - variable.strategyStage === 'No Stage' && - variable.strategyIndex === -1 + variable.current.strategy.stage === 'No Stage' && + variable.current.strategy.index === -1 ) { let minimumBalance let maximumBalance let balance - if (variable.baseAsset === variable.marketBaseAsset) { + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { balance = variable.current.balance.baseAsset - minimumBalance = variable.minimumBalanceBaseAsset - maximumBalance = variable.maximumBalanceBaseAsset + minimumBalance = variable.minimum.balance.baseAsset + maximumBalance = variable.maximum.balance.baseAsset } else { balance = variable.current.balance.quotedAsset - minimumBalance = variable.minimumBalanceQuotedAsset - maximumBalance = variable.maximumBalanceQuotedAsset + minimumBalance = variable.minimum.balance.quotedAsset + maximumBalance = variable.maximum.balance.quotedAsset } let stopRunningDate = new Date(candle.begin) @@ -972,16 +976,16 @@ if (passed) { - variable.strategyStage = 'Trigger Stage'; + variable.current.strategy.stage = 'Trigger Stage'; checkAnnouncements(triggerStage) - variable.strategyIndex = j; + variable.current.strategy.index = j; variable.current.strategy.begin = candle.begin; variable.current.strategy.beginRate = candle.min; variable.current.strategy.endRate = candle.min; // In case the strategy does not get exited variable.current.strategy.situationName = situation.name - variable.distanceToEvent.triggerOn = 1; + variable.distance.toEvent.triggerOn = 1; checkAnnouncements(triggerStage.triggerOn) @@ -996,7 +1000,7 @@ } /* Trigger Off Condition */ - if (variable.strategyStage === 'Trigger Stage') { + if (variable.current.strategy.stage === 'Trigger Stage') { let strategy = tradingSystem.strategies[strategyIndex]; @@ -1014,7 +1018,7 @@ for (let m = 0; m < situation.conditions.length; m++) { let condition = situation.conditions[m]; - let key = variable.strategyIndex + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; + let key = variable.current.strategy.index + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; let value = false if (conditions.get(key) !== undefined) { @@ -1026,14 +1030,14 @@ if (passed) { - variable.current.strategy.number = variable.strategyIndex + variable.current.strategy.number = variable.current.strategy.index variable.current.strategy.end = candle.end; variable.current.strategy.endRate = candle.min; variable.current.strategy.status = 1; // This means the strategy is closed, i.e. that has a begin and end. - variable.strategyStage = 'No Stage'; - variable.strategyIndex = -1; + variable.current.strategy.stage = 'No Stage'; + variable.current.strategy.index = -1; - variable.distanceToEvent.triggerOff = 1; + variable.distance.toEvent.triggerOff = 1; checkAnnouncements(triggerStage.triggerOff) @@ -1046,7 +1050,7 @@ } /* Take Position Condition */ - if (variable.strategyStage === 'Trigger Stage') { + if (variable.current.strategy.stage === 'Trigger Stage') { let strategy = tradingSystem.strategies[strategyIndex]; @@ -1064,7 +1068,7 @@ for (let m = 0; m < situation.conditions.length; m++) { let condition = situation.conditions[m]; - let key = variable.strategyIndex + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; + let key = variable.current.strategy.index + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; let value = false if (conditions.get(key) !== undefined) { @@ -1076,13 +1080,13 @@ if (passed) { - variable.strategyStage = 'Open Stage'; + variable.current.strategy.stage = 'Open Stage'; checkAnnouncements(strategy.openStage) - variable.stopLossStage = 'Open Stage'; - variable.takeProfitStage = 'Open Stage'; - variable.stopLossPhase = 0; - variable.takeProfitPhase = 0; + variable.current.position.stopLossStage = 'Open Stage'; + variable.current.position.takeProfitStage = 'Open Stage'; + variable.current.position.stopLossPhase = 0; + variable.current.position.takeProfitPhase = 0; takePositionNow = true variable.current.position.situationName = situation.name @@ -1099,7 +1103,7 @@ /* Stop Loss Management */ if ( - (variable.strategyStage === 'Open Stage' || variable.strategyStage === 'Manage Stage') && + (variable.current.strategy.stage === 'Open Stage' || variable.current.strategy.stage === 'Manage Stage') && takePositionNow !== true ) { @@ -1115,7 +1119,7 @@ let openStage = strategy.openStage let manageStage = strategy.manageStage let parentNode - let j = variable.strategyIndex + let j = variable.current.strategy.index let stageKey let initialDefinitionKey = '' let p @@ -1126,7 +1130,7 @@ parentNode = openStage.initialDefinition initialDefinitionKey = '-' + 'initialDefinition' stageKey = 'openStage' - p = variable.stopLossPhase + p = variable.current.position.stopLossPhase } } } @@ -1135,7 +1139,7 @@ if (manageStage.stopLoss !== undefined) { parentNode = manageStage stageKey = 'manageStage' - p = variable.stopLossPhase - 1 + p = variable.current.position.stopLossPhase - 1 } } @@ -1166,10 +1170,10 @@ if (passed) { - variable.stopLossPhase++; - variable.stopLossStage = 'Manage Stage' + variable.current.position.stopLossPhase++; + variable.current.position.stopLossStage = 'Manage Stage' if (takeProfitPhase > 0) { - variable.strategyStage = 'Manage Stage' + variable.current.strategy.stage = 'Manage Stage' checkAnnouncements(manageStage, 'Take Profit') } @@ -1208,7 +1212,7 @@ if (moveToPhase !== undefined) { for (let q = 0; q < parentNode.stopLoss.phases.length; q++) { if (parentNode.stopLoss.phases[q].id === moveToPhase.id) { - variable.stopLossPhase = q + 1 + variable.current.position.stopLossPhase = q + 1 } } } else { @@ -1216,9 +1220,9 @@ continue } - variable.stopLossStage = 'Manage Stage' + variable.current.position.stopLossStage = 'Manage Stage' if (takeProfitPhase > 0) { - variable.strategyStage = 'Manage Stage' + variable.current.strategy.stage = 'Manage Stage' checkAnnouncements(manageStage, 'Take Profit') } @@ -1243,7 +1247,7 @@ if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.stopLoss !== undefined) { phase = openStage.initialDefinition.stopLoss.phases[stopLossPhase]; - key = variable.strategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + (stopLossPhase); + key = variable.current.strategy.index + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + (stopLossPhase); } } } @@ -1251,18 +1255,18 @@ if (stopLossStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.stopLoss !== undefined) { phase = manageStage.stopLoss.phases[stopLossPhase - 1]; - key = variable.strategyIndex + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + (stopLossPhase - 1); + key = variable.current.strategy.index + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + (stopLossPhase - 1); } } if (phase !== undefined) { if (phase.formula !== undefined) { - let previousValue = variable.stopLoss + let previousValue = variable.current.position.stopLoss - variable.stopLoss = formulas.get(key) + variable.current.position.stopLoss = formulas.get(key) if (stopLoss !== previousValue) { - checkAnnouncements(phase, variable.stopLoss) + checkAnnouncements(phase, variable.current.position.stopLoss) } } } @@ -1270,7 +1274,7 @@ /* Take Profit Management */ if ( - (variable.strategyStage === 'Open Stage' || variable.strategyStage === 'Manage Stage') && + (variable.current.strategy.stage === 'Open Stage' || variable.current.strategy.stage === 'Manage Stage') && takePositionNow !== true ) { @@ -1286,7 +1290,7 @@ let openStage = strategy.openStage let manageStage = strategy.manageStage let parentNode - let j = variable.strategyIndex + let j = variable.current.strategy.index let stageKey let initialDefinitionKey = '' let p @@ -1297,7 +1301,7 @@ parentNode = openStage.initialDefinition initialDefinitionKey = '-' + 'initialDefinition' stageKey = 'openStage' - p = variable.takeProfitPhase + p = variable.current.position.takeProfitPhase } } } @@ -1306,7 +1310,7 @@ if (manageStage.takeProfit !== undefined) { parentNode = manageStage stageKey = 'manageStage' - p = variable.takeProfitPhase - 1 + p = variable.current.position.takeProfitPhase - 1 } } @@ -1338,10 +1342,10 @@ if (passed) { - variable.takeProfitPhase++; - variable.takeProfitStage = 'Manage Stage' + variable.current.position.takeProfitPhase++; + variable.current.position.takeProfitStage = 'Manage Stage' if (stopLossPhase > 0) { - variable.strategyStage = 'Manage Stage' + variable.current.strategy.stage = 'Manage Stage' checkAnnouncements(manageStage, 'Stop') } @@ -1380,7 +1384,7 @@ if (moveToPhase !== undefined) { for (let q = 0; q < parentNode.takeProfit.phases.length; q++) { if (parentNode.takeProfit.phases[q].id === moveToPhase.id) { - variable.takeProfitPhase = q + 1 + variable.current.position.takeProfitPhase = q + 1 } } } else { @@ -1388,9 +1392,9 @@ continue } - variable.takeProfitStage = 'Manage Stage' + variable.current.position.takeProfitStage = 'Manage Stage' if (stopLossPhase > 0) { - variable.strategyStage = 'Manage Stage' + variable.current.strategy.stage = 'Manage Stage' checkAnnouncements(manageStage, 'Stop') } @@ -1415,7 +1419,7 @@ if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.takeProfit !== undefined) { phase = openStage.initialDefinition.takeProfit.phases[takeProfitPhase]; - key = variable.strategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + (takeProfitPhase); + key = variable.current.strategy.index + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + (takeProfitPhase); } } } @@ -1423,19 +1427,19 @@ if (takeProfitStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.takeProfit !== undefined) { phase = manageStage.takeProfit.phases[takeProfitPhase - 1]; - key = variable.strategyIndex + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 1); + key = variable.current.strategy.index + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 1); } } if (phase !== undefined) { if (phase.formula !== undefined) { - let previousValue = variable.stopLoss + let previousValue = variable.current.position.stopLoss - variable.takeProfit = formulas.get(key) + variable.current.position.takeProfit = formulas.get(key) if (takeProfit !== previousValue) { - checkAnnouncements(phase, variable.takeProfit) + checkAnnouncements(phase, variable.current.position.takeProfit) } } } @@ -1443,49 +1447,49 @@ /* Keeping Position Counters Up-to-date */ if ( - (variable.strategyStage === 'Open Stage' || variable.strategyStage === 'Manage Stage') + (variable.current.strategy.stage === 'Open Stage' || variable.current.strategy.stage === 'Manage Stage') ) { if (takePositionNow === true) { - variable.positionPeriods = 0 + variable.current.position.periods = 0 } - variable.positionPeriods++; - variable.positionDays = variable.positionPeriods * timeFrame / ONE_DAY_IN_MILISECONDS; + variable.current.position.periods++; + variable.positionDays = variable.current.position.periods * timeFrame / ONE_DAY_IN_MILISECONDS; } else { - variable.positionPeriods = 0 + variable.current.position.periods = 0 variable.positionDays = 0 } /* Keeping Distance Counters Up-to-date */ if ( - variable.distanceToEvent.triggerOn > 0 // with this we avoind counting before the first event happens. + variable.distance.toEvent.triggerOn > 0 // with this we avoind counting before the first event happens. ) { - variable.distanceToEvent.triggerOn++; + variable.distance.toEvent.triggerOn++; } if ( - variable.distanceToEvent.triggerOff > 0 // with this we avoind counting before the first event happens. + variable.distance.toEvent.triggerOff > 0 // with this we avoind counting before the first event happens. ) { - variable.distanceToEvent.triggerOff++; + variable.distance.toEvent.triggerOff++; } if ( - variable.distanceToEvent.takePosition > 0 // with this we avoind counting before the first event happens. + variable.distance.toEvent.takePosition > 0 // with this we avoind counting before the first event happens. ) { - variable.distanceToEvent.takePosition++; + variable.distance.toEvent.takePosition++; } if ( - variable.distanceToEvent.closePosition > 0 // with this we avoind counting before the first event happens. + variable.distance.toEvent.closePosition > 0 // with this we avoind counting before the first event happens. ) { - variable.distanceToEvent.closePosition++; + variable.distance.toEvent.closePosition++; } /* Checking if Stop or Take Profit were hit */ if ( - (variable.strategyStage === 'Open Stage' || variable.strategyStage === 'Manage Stage') && + (variable.current.strategy.stage === 'Open Stage' || variable.current.strategy.stage === 'Manage Stage') && takePositionNow !== true ) { let strategy = tradingSystem.strategies[strategyIndex]; @@ -1495,7 +1499,7 @@ /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - if ((variable.baseAsset === variable.marketBaseAsset && candle.max >= variable.stopLoss) || (variable.baseAsset !== variable.marketBaseAsset && candle.min <= variable.stopLoss)) { + if ((variable.episode.baseAsset === variable.episode.marketBaseAsset && candle.max >= variable.current.position.stopLoss) || (variable.episode.baseAsset !== variable.episode.marketBaseAsset && candle.min <= variable.current.position.stopLoss)) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Stop Loss was hit."); } /* @@ -1505,22 +1509,22 @@ If we take the stop loss value at those situation would be a huge distortion of facts. */ - if (variable.baseAsset === variable.marketBaseAsset) { + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { if (stopLoss < candle.min) { - variable.stopLoss = candle.min + variable.current.position.stopLoss = candle.min } } else { if (stopLoss > candle.max) { - variable.stopLoss = candle.max + variable.current.position.stopLoss = candle.max } } - let slippedStopLoss = variable.stopLoss + let slippedStopLoss = variable.current.position.stopLoss /* Apply the Slippage */ let slippageAmount = slippedStopLoss * bot.VALUES_TO_USE.slippage.stopLoss / 100 - if (variable.baseAsset === variable.marketBaseAsset) { + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { slippedStopLoss = slippedStopLoss + slippageAmount } else { slippedStopLoss = slippedStopLoss - slippageAmount @@ -1528,11 +1532,11 @@ closeRate = slippedStopLoss; - variable.strategyStage = 'Close Stage'; + variable.current.strategy.stage = 'Close Stage'; checkAnnouncements(strategy.closeStage, 'Stop') - variable.stopLossStage = 'No Stage'; - variable.takeProfitStage = 'No Stage'; + variable.current.position.stopLossStage = 'No Stage'; + variable.current.position.takeProfitStage = 'No Stage'; variable.current.position.end = candle.end; variable.current.position.status = 1; variable.current.position.exitType = 1; @@ -1543,7 +1547,7 @@ /* Take Profit condition: Here we verify if the Take Profit was hit or not. */ - if ((variable.baseAsset === variable.marketBaseAsset && candle.min <= variable.takeProfit) || (variable.baseAsset !== variable.marketBaseAsset && candle.max >= variable.takeProfit)) { + if ((variable.episode.baseAsset === variable.episode.marketBaseAsset && candle.min <= variable.current.position.takeProfit) || (variable.episode.baseAsset !== variable.episode.marketBaseAsset && candle.max >= variable.current.position.takeProfit)) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Take Profit was hit."); } /* @@ -1553,21 +1557,21 @@ If we take the stop loss value at those situation would be a huge distortion of facts. */ - if (variable.baseAsset === variable.marketBaseAsset) { + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { if (takeProfit > candle.max) { - variable.takeProfit = candle.max + variable.current.position.takeProfit = candle.max } } else { if (takeProfit < candle.min) { - variable.takeProfit = candle.min + variable.current.position.takeProfit = candle.min } } - let slippedTakeProfit = variable.takeProfit + let slippedTakeProfit = variable.current.position.takeProfit /* Apply the Slippage */ let slippageAmount = slippedTakeProfit * bot.VALUES_TO_USE.slippage.takeProfit / 100 - if (variable.baseAsset === variable.marketBaseAsset) { + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { slippedTakeProfit = slippedTakeProfit + slippageAmount } else { slippedTakeProfit = slippedTakeProfit - slippageAmount @@ -1575,11 +1579,11 @@ closeRate = slippedTakeProfit; - variable.strategyStage = 'Close Stage'; + variable.current.strategy.stage = 'Close Stage'; checkAnnouncements(strategy.closeStage, 'Take Profit') - variable.stopLossStage = 'No Stage'; - variable.takeProfitStage = 'No Stage'; + variable.current.position.stopLossStage = 'No Stage'; + variable.current.position.takeProfitStage = 'No Stage'; variable.current.position.end = candle.end; variable.current.position.status = 1; @@ -1599,26 +1603,26 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionNow -> Entering code block."); } /* Inicializing this counter */ - variable.distanceToEvent.takePosition = 1; + variable.distance.toEvent.takePosition = 1; /* Position size and rate */ let strategy = tradingSystem.strategies[strategyIndex]; - variable.tradePositionSize = strategy.positionSize; - variable.tradePositionRate = strategy.positionRate; + variable.current.position.size = strategy.positionSize; + variable.current.position.rate = strategy.positionRate; /* We take what was calculated at the formula and apply the slippage. */ - let slippageAmount = variable.tradePositionRate * bot.VALUES_TO_USE.slippage.positionRate / 100 + let slippageAmount = variable.current.position.rate * bot.VALUES_TO_USE.slippage.positionRate / 100 - if (variable.baseAsset === variable.marketBaseAsset) { - variable.tradePositionRate = variable.tradePositionRate - slippageAmount + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + variable.current.position.rate = variable.current.position.rate - slippageAmount } else { - variable.tradePositionRate = variable.tradePositionRate + slippageAmount + variable.current.position.rate = variable.current.position.rate + slippageAmount } /* Update the trade record information. */ variable.current.position.begin = candle.begin; - variable.current.position.beginRate = variable.tradePositionRate; + variable.current.position.beginRate = variable.current.position.rate; /* Check if we need to execute. */ if (currentCandleIndex > candles.length - 10) { /* Only at the last candles makes sense to check if we are in live mode or not.*/ @@ -1724,21 +1728,21 @@ let orderSide - if (variable.baseAsset === variable.marketBaseAsset) { + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { orderSide = "sell" - orderPrice = variable.tradePositionRate - 100 // This is going to be ingnored at the Exchange API for now since we only put market orders. + orderPrice = variable.current.position.rate - amountA = variable.tradePositionSize * orderPrice - amountB = variable.tradePositionSize + amountA = variable.current.position.size * orderPrice + amountB = variable.current.position.size } else { orderSide = "buy" - orderPrice = variable.tradePositionRate // This is going to be ingnored at the Exchange API for now since we only put market orders. + orderPrice = variable.current.position.rate - amountA = variable.tradePositionSize - amountB = variable.tradePositionSize / orderPrice + amountA = variable.current.position.size + amountB = variable.current.position.size / orderPrice } @@ -1801,26 +1805,26 @@ calculateTakeProfit(); calculateStopLoss(); - variable.previousBalanceBaseAsset = variable.current.balance.baseAsset; - variable.previousBalanceQuotedAsset = variable.current.balance.quotedAsset; + variable.previous.balance.baseAsset = variable.current.balance.baseAsset; + variable.previous.balance.quotedAsset = variable.current.balance.quotedAsset; - variable.lastTrade.profitLoss = 0; - variable.lastTrade.ROI = 0; + variable.last.position.profitLoss = 0; + variable.last.position.ROI = 0; let feePaid = 0 - if (variable.baseAsset === variable.marketBaseAsset) { + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { - feePaid = variable.tradePositionSize * variable.tradePositionRate * bot.VALUES_TO_USE.feeStructure.taker / 100 + feePaid = variable.current.position.size * variable.current.position.rate * bot.VALUES_TO_USE.feeStructure.taker / 100 - variable.current.balance.quotedAsset = variable.current.balance.quotedAsset + variable.tradePositionSize * variable.tradePositionRate - feePaid; - variable.current.balance.baseAsset = variable.current.balance.baseAsset - variable.tradePositionSize; + variable.current.balance.quotedAsset = variable.current.balance.quotedAsset + variable.current.position.size * variable.current.position.rate - feePaid; + variable.current.balance.baseAsset = variable.current.balance.baseAsset - variable.current.position.size; } else { - feePaid = variable.tradePositionSize / variable.tradePositionRate * bot.VALUES_TO_USE.feeStructure.taker / 100 + feePaid = variable.current.position.size / variable.current.position.rate * bot.VALUES_TO_USE.feeStructure.taker / 100 - variable.current.balance.baseAsset = variable.current.balance.baseAsset + variable.tradePositionSize / variable.tradePositionRate - feePaid; - variable.current.balance.quotedAsset = variable.current.balance.quotedAsset - variable.tradePositionSize; + variable.current.balance.baseAsset = variable.current.balance.baseAsset + variable.current.position.size / variable.current.position.rate - feePaid; + variable.current.balance.quotedAsset = variable.current.balance.quotedAsset - variable.current.position.size; } addRecord(); @@ -1837,7 +1841,7 @@ closePositionNow = false /* Inicializing this counter */ - variable.distanceToEvent.closePosition = 1; + variable.distance.toEvent.closePosition = 1; /* Position size and rate */ let strategy = tradingSystem.strategies[strategyIndex]; @@ -1905,7 +1909,7 @@ let amountB let orderSide - if (variable.baseAsset === variable.marketBaseAsset) { + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { orderSide = "buy" orderPrice = ticker.last + 100; // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. @@ -1981,7 +1985,7 @@ let feePaid = 0 - if (variable.baseAsset === variable.marketBaseAsset) { + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { strategy.positionSize = variable.current.balance.quotedAsset / closeRate; strategy.positionRate = closeRate; @@ -1999,49 +2003,49 @@ variable.current.balance.baseAsset = 0; } - if (variable.baseAsset === variable.marketBaseAsset) { - variable.lastTrade.profitLoss = variable.current.balance.baseAsset - variable.previousBalanceBaseAsset; - variable.lastTrade.ROI = variable.lastTrade.profitLoss * 100 / variable.tradePositionSize; - if (isNaN(lastTradeROI)) { variable.lastTrade.ROI = 0; } - variable.episode.profitLoss = variable.current.balance.baseAsset - variable.initialBalanceBaseAsset; + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + variable.last.position.profitLoss = variable.current.balance.baseAsset - variable.previous.balance.baseAsset; + variable.last.position.ROI = variable.last.position.profitLoss * 100 / variable.current.position.size; + if (isNaN(lastTradeROI)) { variable.last.position.ROI = 0; } + variable.episode.profitLoss = variable.current.balance.baseAsset - variable.initial.balance.baseAsset; } else { - variable.lastTrade.profitLoss = variable.current.balance.quotedAsset - variable.previousBalanceQuotedAsset; - variable.lastTrade.ROI = variable.lastTrade.profitLoss * 100 / variable.tradePositionSize; - if (isNaN(lastTradeROI)) { variable.lastTrade.ROI = 0; } - variable.episode.profitLoss = variable.current.balance.quotedAsset - variable.initialBalanceQuotedAsset; + variable.last.position.profitLoss = variable.current.balance.quotedAsset - variable.previous.balance.quotedAsset; + variable.last.position.ROI = variable.last.position.profitLoss * 100 / variable.current.position.size; + if (isNaN(lastTradeROI)) { variable.last.position.ROI = 0; } + variable.episode.profitLoss = variable.current.balance.quotedAsset - variable.initial.balance.quotedAsset; } - variable.current.position.lastTradeROI = variable.lastTrade.ROI; + variable.current.position.lastTradeROI = variable.last.position.ROI; - if (variable.lastTrade.profitLoss > 0) { + if (variable.last.position.profitLoss > 0) { variable.episode.hits++; } else { variable.episode.fails++; } - if (variable.baseAsset === variable.marketBaseAsset) { - variable.episode.ROI = (variable.initialBalanceBaseAsset + variable.episode.profitLoss) / variable.initialBalanceBaseAsset - 1; + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + variable.episode.ROI = (variable.initial.balance.baseAsset + variable.episode.profitLoss) / variable.initial.balance.baseAsset - 1; variable.episode.hitRatio = variable.episode.hits / variable.episode.tradesCount; variable.anualizedRateOfReturn = variable.episode.ROI / variable.episode.days * 365; } else { - variable.episode.ROI = (variable.initialBalanceQuotedAsset + variable.episode.profitLoss) / variable.initialBalanceQuotedAsset - 1; + variable.episode.ROI = (variable.initial.balance.quotedAsset + variable.episode.profitLoss) / variable.initial.balance.quotedAsset - 1; variable.episode.hitRatio = variable.episode.hits / variable.episode.tradesCount; variable.anualizedRateOfReturn = variable.episode.ROI / variable.episode.days * 365; } addRecord(); - variable.stopLoss = 0; - variable.takeProfit = 0; + variable.current.position.stopLoss = 0; + variable.current.position.takeProfit = 0; - variable.tradePositionRate = 0; - variable.tradePositionSize = 0; + variable.current.position.rate = 0; + variable.current.position.size = 0; timerToCloseStage = candle.begin - variable.stopLossStage = 'No Stage'; - variable.takeProfitStage = 'No Stage'; - variable.stopLossPhase = -1; - variable.takeProfitPhase = -1; + variable.current.position.stopLossStage = 'No Stage'; + variable.current.position.takeProfitStage = 'No Stage'; + variable.current.position.stopLossPhase = -1; + variable.current.position.takeProfitPhase = -1; if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> closePositionAtSimulation -> Exiting Loop Body after closing position at simulation."); } controlLoop(); @@ -2050,19 +2054,19 @@ } /* Closing the Closing Stage */ - if (variable.strategyStage === 'Close Stage') { + if (variable.current.strategy.stage === 'Close Stage') { if (candle.begin - 5 * 60 * 1000 > timerToCloseStage) { - variable.current.strategy.number = variable.strategyIndex + variable.current.strategy.number = variable.current.strategy.index variable.current.strategy.end = candle.end; variable.current.strategy.endRate = candle.min; variable.current.strategy.status = 1; // This means the strategy is closed, i.e. that has a begin and end. - variable.strategyIndex = -1; - variable.strategyStage = 'No Stage'; + variable.current.strategy.index = -1; + variable.current.strategy.stage = 'No Stage'; timerToCloseStage = 0 - variable.distanceToEvent.triggerOff = 1; + variable.distance.toEvent.triggerOff = 1; if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing the Closing Stage -> Exiting Close Stage."); } } else { @@ -2095,8 +2099,8 @@ balanceBaseAsset: variable.current.balance.baseAsset, balanceQuotedAsset: variable.current.balance.quotedAsset, accumulatedProfitLoss: variable.episode.profitLoss, - lastTradeProfitLoss: variable.lastTrade.profitLoss, - stopLoss: variable.stopLoss, + lastTradeProfitLoss: variable.last.position.profitLoss, + stopLoss: variable.current.position.stopLoss, tradesCount: variable.episode.tradesCount, hits: variable.episode.hits, fails: variable.episode.fails, @@ -2105,29 +2109,29 @@ periods: variable.episode.periods, days: variable.episode.days, anualizedRateOfReturn: variable.anualizedRateOfReturn, - positionRate: variable.tradePositionRate, - lastTradeROI: variable.lastTrade.ROI, - strategy: variable.strategyIndex, - takeProfit: variable.takeProfit, - stopLossPhase: variable.stopLossPhase, - takeProfitPhase: variable.takeProfitPhase, - positionSize: variable.tradePositionSize, - initialBalanceA: variable.initialBalanceBaseAsset, - minimumBalanceA: variable.minimumBalanceBaseAsset, - maximumBalanceA: variable.maximumBalanceBaseAsset, - initialBalanceB: variable.initialBalanceQuotedAsset, - minimumBalanceB: variable.minimumBalanceQuotedAsset, - maximumBalanceB: variable.maximumBalanceQuotedAsset, - baseAsset: '"' + variable.baseAsset + '"', - quotedAsset: '"' + variable.quotedAsset + '"', - marketBaseAsset: '"' + variable.marketBaseAsset + '"', - marketQuotedAsset: '"' + variable.marketQuotedAsset + '"' , - positionPeriods: variable.positionPeriods, + positionRate: variable.current.position.rate, + lastTradeROI: variable.last.position.ROI, + strategy: variable.current.strategy.index, + takeProfit: variable.current.position.takeProfit, + stopLossPhase: variable.current.position.stopLossPhase, + takeProfitPhase: variable.current.position.takeProfitPhase, + positionSize: variable.current.position.size, + initialBalanceA: variable.initial.balance.baseAsset, + minimumBalanceA: variable.minimum.balance.baseAsset, + maximumBalanceA: variable.maximum.balance.baseAsset, + initialBalanceB: variable.initial.balance.quotedAsset, + minimumBalanceB: variable.minimum.balance.quotedAsset, + maximumBalanceB: variable.maximum.balance.quotedAsset, + baseAsset: '"' + variable.episode.baseAsset + '"', + quotedAsset: '"' + variable.episode.quotedAsset + '"', + marketBaseAsset: '"' + variable.episode.marketBaseAsset + '"', + marketQuotedAsset: '"' + variable.episode.marketQuotedAsset + '"' , + positionPeriods: variable.current.position.periods, positionDays: variable.positionDays, - distanceToEventTriggerOn: variable.distanceToEvent.triggerOn, - distanceToEventTriggerOff: variable.distanceToEvent.triggerOff, - distanceToEventTakePosition: variable.distanceToEvent.takePosition, - distanceToEventClosePosition: variable.distanceToEvent.closePosition + distanceToEventTriggerOn: variable.distance.toEvent.triggerOn, + distanceToEventTriggerOff: variable.distance.toEvent.triggerOff, + distanceToEventTakePosition: variable.distance.toEvent.takePosition, + distanceToEventClosePosition: variable.distance.toEvent.closePosition } recordsArray.push(simulationRecord); @@ -2147,25 +2151,27 @@ Lets see if there will be an open strategy ... Except if we are at the head of the market (remember we skipped the last candle for not being closed.) */ - if (currentStrategy.begin !== 0 && variable.current.strategy.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { + if (variable.current.strategy.begin !== 0 && variable.current.strategy.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { variable.current.strategy.status = 2; // This means the strategy is open, i.e. that has a begin but no end. variable.current.strategy.end = candle.end } /* Prepare the information for the Strategies File*/ - if (currentStrategy.begin !== 0 && variable.current.strategy.end !== 0) - { - strategiesArray.push(currentStrategy); - - variable.current.strategy = { - begin: 0, - end: 0, - status: 0, - number: 0, - beginRate: 0, - endRate: 0, - situationName: '' + if (variable.current.strategy.begin !== 0 && variable.current.strategy.end !== 0) + { + let currentStrategyRecord = { + begin: variable.current.strategy.begin, + end: variable.current.strategy.end, + status: variable.current.strategy.status, + number: variable.current.strategy.number, + beginRate: variable.current.strategy.beginRate, + endRate: variable.current.strategy.endRate, + situationName: variable.current.strategy.situationName } + + strategiesArray.push(currentStrategyRecord ); + + inializeCurrentStrategy() } /* @@ -2178,30 +2184,30 @@ variable.current.position.endRate = candle.close /* Here we will calculate the ongoing variable.episode.ROI */ - if (variable.baseAsset === variable.marketBaseAsset) { - variable.current.position.lastTradeROI = (tradePositionRate - candle.close) / variable.tradePositionRate * 100 + if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + variable.current.position.lastTradeROI = (variable.current.position.rate - candle.close) / variable.current.position.rate * 100 } else { - variable.current.position.lastTradeROI = (candle.close - variable.tradePositionRate) / variable.tradePositionRate * 100 + variable.current.position.lastTradeROI = (candle.close - variable.current.position.rate) / variable.current.position.rate * 100 } } /* Prepare the information for the Trades File */ if (variable.current.position.begin !== 0 && variable.current.position.end !== 0) { - variable.current.position.profit = variable.lastTrade.profitLoss; - - tradesArray.push(variable.current.position); - - variable.current.position = { - begin: 0, - end: 0, - status: 0, - lastTradeROI: 0, - exitType: 0, - beginRate: 0, - endRate: 0, - situationName: '' + let currentPositionRecord = { + begin: variable.current.position.begin, + end: variable.current.position.end, + status: variable.current.position.status, + lastTradeROI: variable.current.position.lastTradeROI, + exitType: variable.current.position.exitType, + beginRate: variable.current.position.beginRate, + endRate: variable.current.position.endRate, + situationName: variable.current.position.situationName } + + tradesArray.push(currentPositionRecord); + + initializeCurrentPosition() } makeAnnoucements() // After everything at the simulation level was done, we will do the annoucements that are pending. From 96719cdc2143e812e8f41e5035ed2c7a3f23a89b Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 20 May 2020 11:46:27 +0200 Subject: [PATCH 23/44] Update TradingSimulation.js --- TradingSimulation.js | 269 ++++++++++++++++++++++--------------------- 1 file changed, 140 insertions(+), 129 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index 556c5492e..7884a8079 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -74,61 +74,72 @@ variable.isInitialized = true - variable.initial = {} // Everything in here means the status at the begining of the episode. - variable.current = {} // Everything in here means that is happening right now. - variable.last = {} // Everything in here means that it already happened. - variable.minimun = {} // Everything in here means the minimun in the whole episode. - variable.maximun = {} // Everything in here means the maximun in the whole episode. - variable.previous = {} // Everything in here means the the value that was current before a new current value was set. - variable.distance = {} // Everything in here means the distance, measured in periods to whatever happened in the past, usually events. + variable.episode = {} // An Episode represents each execution of the Simulation + variable.episode.count = {} // Everything in here means the total count since the begining of the episode. + variable.episode.stat = {} // Everything in here means the statistics calculated since the begining of the episode. - variable.episode = { // An Episode represents each execution of the Simulation - baseAsset: bot.VALUES_TO_USE.baseAsset, - quotedAsset: bot.VALUES_TO_USE.quotedAsset, - marketBaseAsset: bot.market.baseAsset, - marketQuotedAsset: bot.market.quotedAsset, - profitLoss: 0, - tradesCount: 0, - fails: 0, - hits: 0, - hitRatio: 0, - periods: 0, - days: 0, - ROI: 0, - anualizedRateOfReturn: 0 - } + variable.current = {} // Everything in here means that is happening right now. + variable.current.balance = {} // Balances at the current candle of the Simulation. + variable.current.distance = {} // Everything in here means the distance, measured in periods to whatever happened in the past, usually events. + variable.current.distance.toEvent = {} // Distance to Events that already happened. + variable.current.strategy = {} // Everything in here are variables related to the current strategy being executed. + variable.current.position = {} // Everything in here are variables related to the current position being executed. + + variable.current.balance.baseAsset = bot.VALUES_TO_USE.initialBalanceA + variable.current.balance.quotedAsset = bot.VALUES_TO_USE.initialBalanceB + variable.current.distance.toEvent.triggerOn = 0 + variable.current.distance.toEvent.triggerOff = 0 + variable.current.distance.toEvent.takePosition = 0 + variable.current.distance.toEvent.closePosition = 0 + + variable.last = {} // Everything in here means that it already happened. + variable.last.position = {} // Las values of variables at the last position. + + variable.last.position.profitLoss = 0 + variable.last.position.ROI = 0 + + variable.previous = {} // Everything in here means the the value that was current before a new current value was set. + variable.previous.balance = {} // Balances values previous to the current ones. variable.previous.balance.baseAsset = 0 variable.previous.balance.quotedAsset = 0 + variable.episode.parameters = {} // Parameters give you access to information received by the Simulation as parameters. + variable.episode.parameters.initial = {} // Everything in here means the status at the begining of the episode received as a parameter of the Sumulation. + variable.episode.parameters.minimun = {} // Everything in here means the minimun in the whole episode received as a parameter of the Sumulation. + variable.episode.parameters.maximun = {} // Everything in here means the maximun in the whole episode received as a parameter of the Sumulation. + variable.episode.parameters.initial.balance = {} + variable.episode.parameters.minimun.balance = {} + variable.episode.parameters.maximun.balance = {} + + variable.episode.parameters.baseAsset = bot.VALUES_TO_USE.baseAsset + variable.episode.parameters.quotedAsset = bot.VALUES_TO_USE.quotedAsset + variable.episode.parameters.marketBaseAsset = bot.market.baseAsset + variable.episode.parameters.marketQuotedAsset = bot.market.quotedAsset + + variable.episode.parameters.initial.balance.baseAsset = bot.VALUES_TO_USE.initialBalanceA + variable.episode.parameters.minimum.balance.baseAsset = bot.VALUES_TO_USE.minimumBalanceA + variable.episode.parameters.maximum.balance.baseAsset = bot.VALUES_TO_USE.maximumBalanceA + + variable.episode.parameters.initial.balance.quotedAsset = bot.VALUES_TO_USE.initialBalanceB + variable.episode.parameters.minimum.balance.quotedAsset = bot.VALUES_TO_USE.minimumBalanceB + variable.episode.parameters.maximum.balance.quotedAsset = bot.VALUES_TO_USE.maximumBalanceB + + variable.episode.count.positions = 0 + variable.episode.count.fails = 0 + variable.episode.count.hits = 0 + variable.episode.count.periods = 0 + + variable.episode.stat.profitLoss = 0 + variable.episode.stat.hitRatio = 0 + variable.episode.stat.days = 0 + variable.episode.stat.ROI = 0 + variable.episode.stat.anualizedRateOfReturn = 0 + inializeCurrentStrategy() initializeCurrentPosition() - variable.current.balance.baseAsset = bot.VALUES_TO_USE.initialBalanceA - variable.current.balance.quotedAsset = bot.VALUES_TO_USE.initialBalanceB - - variable.initial.balance.baseAsset = bot.VALUES_TO_USE.initialBalanceA - variable.minimum.balance.baseAsset = bot.VALUES_TO_USE.minimumBalanceA - variable.maximum.balance.baseAsset = bot.VALUES_TO_USE.maximumBalanceA - - variable.initial.balance.quotedAsset = bot.VALUES_TO_USE.initialBalanceB - variable.minimum.balance.quotedAsset = bot.VALUES_TO_USE.minimumBalanceB - variable.maximum.balance.quotedAsset = bot.VALUES_TO_USE.maximumBalanceB - - variable.last.position = { - profitLoss: 0, - ROI: 0 - } - - variable.distance.toEvent = { - triggerOn: 0, - triggerOff: 0, - takePosition: 0, - closePosition: 0 - } - variable.announcements = [] - } function inializeCurrentStrategy() { @@ -325,8 +336,8 @@ } previousLoopingDay = loopingDay.valueOf() - variable.episode.periods++; - variable.episode.days = variable.episode.periods * timeFrame / ONE_DAY_IN_MILISECONDS; + variable.episode.count.periods++; + variable.episode.stat.days = variable.episode.count.periods * timeFrame / ONE_DAY_IN_MILISECONDS; if (processingDailyFiles) { @@ -339,7 +350,7 @@ controlLoop(); return /* Note here that in the last candle of the first day or the second day it will use an incomplete candle and partially calculated indicators. - if we skip these two variable.episode.periods, then there will be a hole in the file since the last period will be missing. */ + if we skip these two variable.episode.count.periods, then there will be a hole in the file since the last period will be missing. */ } } @@ -436,7 +447,7 @@ if (openStage !== undefined) { /* Default Values*/ - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { positionSize = variable.current.balance.baseAsset; positionRate = candle.close; } else { @@ -459,13 +470,13 @@ initialDefinition.positionSize.formula.error = err.message } if (isNaN(positionSize)) { - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { positionSize = variable.current.balance.baseAsset; } else { positionSize = variable.current.balance.quotedAsset; } } else { - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { if (positionSize > variable.current.balance.baseAsset) { positionSize = variable.current.balance.baseAsset } } else { if (positionSize > variable.current.balance.quotedAsset) { positionSize = variable.current.balance.quotedAsset } @@ -486,7 +497,7 @@ initialDefinition.positionRate.formula.error = err.message } if (isNaN(positionRate)) { - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { positionRate = candle.close; } else { positionRate = candle.close; @@ -910,14 +921,14 @@ let maximumBalance let balance - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { balance = variable.current.balance.baseAsset - minimumBalance = variable.minimum.balance.baseAsset - maximumBalance = variable.maximum.balance.baseAsset + minimumBalance = variable.episode.parameters.minimum.balance.baseAsset + maximumBalance = variable.episode.parameters.maximum.balance.baseAsset } else { balance = variable.current.balance.quotedAsset - minimumBalance = variable.minimum.balance.quotedAsset - maximumBalance = variable.maximum.balance.quotedAsset + minimumBalance = variable.episode.parameters.minimum.balance.quotedAsset + maximumBalance = variable.episode.parameters.maximum.balance.quotedAsset } let stopRunningDate = new Date(candle.begin) @@ -985,7 +996,7 @@ variable.current.strategy.endRate = candle.min; // In case the strategy does not get exited variable.current.strategy.situationName = situation.name - variable.distance.toEvent.triggerOn = 1; + variable.current.distance.toEvent.triggerOn = 1; checkAnnouncements(triggerStage.triggerOn) @@ -1037,7 +1048,7 @@ variable.current.strategy.stage = 'No Stage'; variable.current.strategy.index = -1; - variable.distance.toEvent.triggerOff = 1; + variable.current.distance.toEvent.triggerOff = 1; checkAnnouncements(triggerStage.triggerOff) @@ -1464,27 +1475,27 @@ /* Keeping Distance Counters Up-to-date */ if ( - variable.distance.toEvent.triggerOn > 0 // with this we avoind counting before the first event happens. + variable.current.distance.toEvent.triggerOn > 0 // with this we avoind counting before the first event happens. ) { - variable.distance.toEvent.triggerOn++; + variable.current.distance.toEvent.triggerOn++; } if ( - variable.distance.toEvent.triggerOff > 0 // with this we avoind counting before the first event happens. + variable.current.distance.toEvent.triggerOff > 0 // with this we avoind counting before the first event happens. ) { - variable.distance.toEvent.triggerOff++; + variable.current.distance.toEvent.triggerOff++; } if ( - variable.distance.toEvent.takePosition > 0 // with this we avoind counting before the first event happens. + variable.current.distance.toEvent.takePosition > 0 // with this we avoind counting before the first event happens. ) { - variable.distance.toEvent.takePosition++; + variable.current.distance.toEvent.takePosition++; } if ( - variable.distance.toEvent.closePosition > 0 // with this we avoind counting before the first event happens. + variable.current.distance.toEvent.closePosition > 0 // with this we avoind counting before the first event happens. ) { - variable.distance.toEvent.closePosition++; + variable.current.distance.toEvent.closePosition++; } /* Checking if Stop or Take Profit were hit */ @@ -1499,7 +1510,7 @@ /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - if ((variable.episode.baseAsset === variable.episode.marketBaseAsset && candle.max >= variable.current.position.stopLoss) || (variable.episode.baseAsset !== variable.episode.marketBaseAsset && candle.min <= variable.current.position.stopLoss)) { + if ((variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset && candle.max >= variable.current.position.stopLoss) || (variable.episode.parameters.baseAsset !== variable.episode.parameters.marketBaseAsset && candle.min <= variable.current.position.stopLoss)) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Stop Loss was hit."); } /* @@ -1509,7 +1520,7 @@ If we take the stop loss value at those situation would be a huge distortion of facts. */ - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { if (stopLoss < candle.min) { variable.current.position.stopLoss = candle.min } @@ -1524,7 +1535,7 @@ /* Apply the Slippage */ let slippageAmount = slippedStopLoss * bot.VALUES_TO_USE.slippage.stopLoss / 100 - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { slippedStopLoss = slippedStopLoss + slippageAmount } else { slippedStopLoss = slippedStopLoss - slippageAmount @@ -1547,7 +1558,7 @@ /* Take Profit condition: Here we verify if the Take Profit was hit or not. */ - if ((variable.episode.baseAsset === variable.episode.marketBaseAsset && candle.min <= variable.current.position.takeProfit) || (variable.episode.baseAsset !== variable.episode.marketBaseAsset && candle.max >= variable.current.position.takeProfit)) { + if ((variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset && candle.min <= variable.current.position.takeProfit) || (variable.episode.parameters.baseAsset !== variable.episode.parameters.marketBaseAsset && candle.max >= variable.current.position.takeProfit)) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Take Profit was hit."); } /* @@ -1557,7 +1568,7 @@ If we take the stop loss value at those situation would be a huge distortion of facts. */ - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { if (takeProfit > candle.max) { variable.current.position.takeProfit = candle.max } @@ -1571,7 +1582,7 @@ /* Apply the Slippage */ let slippageAmount = slippedTakeProfit * bot.VALUES_TO_USE.slippage.takeProfit / 100 - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { slippedTakeProfit = slippedTakeProfit + slippageAmount } else { slippedTakeProfit = slippedTakeProfit - slippageAmount @@ -1603,7 +1614,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionNow -> Entering code block."); } /* Inicializing this counter */ - variable.distance.toEvent.takePosition = 1; + variable.current.distance.toEvent.takePosition = 1; /* Position size and rate */ let strategy = tradingSystem.strategies[strategyIndex]; @@ -1614,7 +1625,7 @@ /* We take what was calculated at the formula and apply the slippage. */ let slippageAmount = variable.current.position.rate * bot.VALUES_TO_USE.slippage.positionRate / 100 - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { variable.current.position.rate = variable.current.position.rate - slippageAmount } else { variable.current.position.rate = variable.current.position.rate + slippageAmount @@ -1701,7 +1712,7 @@ /* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */ if (variable.executionContext !== undefined) { if (variable.executionContext.periods !== undefined) { - if (variable.episode.periods <= variable.executionContext.periods) { + if (variable.episode.count.periods <= variable.executionContext.periods) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because it was already placed at a previous execution."); } takePositionAtSimulation() return; @@ -1728,7 +1739,7 @@ let orderSide - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { orderSide = "sell" orderPrice = variable.current.position.rate @@ -1748,7 +1759,7 @@ variable.executionContext = { status: "Taking Position", - periods: variable.episode.periods, + periods: variable.episode.count.periods, } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Ready to create order."); } @@ -1763,7 +1774,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_OK_RESPONSE "); } variable.executionContext = { status: "In a Position", - periods: variable.episode.periods, + periods: variable.episode.count.periods, amountA: amountA, amountB: amountB, orderId: order.id @@ -1813,7 +1824,7 @@ let feePaid = 0 - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { feePaid = variable.current.position.size * variable.current.position.rate * bot.VALUES_TO_USE.feeStructure.taker / 100 @@ -1841,7 +1852,7 @@ closePositionNow = false /* Inicializing this counter */ - variable.distance.toEvent.closePosition = 1; + variable.current.distance.toEvent.closePosition = 1; /* Position size and rate */ let strategy = tradingSystem.strategies[strategyIndex]; @@ -1896,7 +1907,7 @@ /* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */ if (variable.executionContext !== undefined) { if (variable.executionContext.periods !== undefined) { - if (variable.episode.periods <= variable.executionContext.periods) { + if (variable.episode.count.periods <= variable.executionContext.periods) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> Exiting function because this closing was already submited at a previous execution."); } closePositionAtSimulation() return; @@ -1909,7 +1920,7 @@ let amountB let orderSide - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { orderSide = "buy" orderPrice = ticker.last + 100; // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. @@ -1929,7 +1940,7 @@ variable.executionContext = { status: "Closing Position", - periods: variable.episode.periods, + periods: variable.episode.count.periods, } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> About to close position at the exchange."); } @@ -1944,7 +1955,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> DEFAULT_OK_RESPONSE "); } variable.executionContext = { status: "Position Closed", - periods: variable.episode.periods, + periods: variable.episode.count.periods, amountA: amountA, amountB: amountB, orderId: order.id @@ -1981,11 +1992,11 @@ function closePositionAtSimulation() { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> closePositionAtSimulation -> Entering function."); } - variable.episode.tradesCount++; + variable.episode.count.positions++; let feePaid = 0 - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { strategy.positionSize = variable.current.balance.quotedAsset / closeRate; strategy.positionRate = closeRate; @@ -2003,34 +2014,34 @@ variable.current.balance.baseAsset = 0; } - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { variable.last.position.profitLoss = variable.current.balance.baseAsset - variable.previous.balance.baseAsset; variable.last.position.ROI = variable.last.position.profitLoss * 100 / variable.current.position.size; if (isNaN(lastTradeROI)) { variable.last.position.ROI = 0; } - variable.episode.profitLoss = variable.current.balance.baseAsset - variable.initial.balance.baseAsset; + variable.episode.stat.profitLoss = variable.current.balance.baseAsset - variable.episode.parameters.initial.balance.baseAsset; } else { variable.last.position.profitLoss = variable.current.balance.quotedAsset - variable.previous.balance.quotedAsset; variable.last.position.ROI = variable.last.position.profitLoss * 100 / variable.current.position.size; if (isNaN(lastTradeROI)) { variable.last.position.ROI = 0; } - variable.episode.profitLoss = variable.current.balance.quotedAsset - variable.initial.balance.quotedAsset; + variable.episode.stat.profitLoss = variable.current.balance.quotedAsset - variable.episode.parameters.initial.balance.quotedAsset; } variable.current.position.lastTradeROI = variable.last.position.ROI; if (variable.last.position.profitLoss > 0) { - variable.episode.hits++; + variable.episode.count.hits++; } else { - variable.episode.fails++; + variable.episode.count.fails++; } - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { - variable.episode.ROI = (variable.initial.balance.baseAsset + variable.episode.profitLoss) / variable.initial.balance.baseAsset - 1; - variable.episode.hitRatio = variable.episode.hits / variable.episode.tradesCount; - variable.anualizedRateOfReturn = variable.episode.ROI / variable.episode.days * 365; + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + variable.episode.stat.ROI = (variable.episode.parameters.initial.balance.baseAsset + variable.episode.stat.profitLoss) / variable.episode.parameters.initial.balance.baseAsset - 1; + variable.episode.stat.hitRatio = variable.episode.count.hits / variable.episode.count.positions; + variable.episode.stat.anualizedRateOfReturn = variable.episode.stat.ROI / variable.episode.stat.days * 365; } else { - variable.episode.ROI = (variable.initial.balance.quotedAsset + variable.episode.profitLoss) / variable.initial.balance.quotedAsset - 1; - variable.episode.hitRatio = variable.episode.hits / variable.episode.tradesCount; - variable.anualizedRateOfReturn = variable.episode.ROI / variable.episode.days * 365; + variable.episode.stat.ROI = (variable.episode.parameters.initial.balance.quotedAsset + variable.episode.stat.profitLoss) / variable.episode.parameters.initial.balance.quotedAsset - 1; + variable.episode.stat.hitRatio = variable.episode.count.hits / variable.episode.count.positions; + variable.episode.stat.anualizedRateOfReturn = variable.episode.stat.ROI / variable.episode.stat.days * 365; } addRecord(); @@ -2066,7 +2077,7 @@ variable.current.strategy.stage = 'No Stage'; timerToCloseStage = 0 - variable.distance.toEvent.triggerOff = 1; + variable.current.distance.toEvent.triggerOff = 1; if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing the Closing Stage -> Exiting Close Stage."); } } else { @@ -2098,17 +2109,17 @@ end: candle.end, balanceBaseAsset: variable.current.balance.baseAsset, balanceQuotedAsset: variable.current.balance.quotedAsset, - accumulatedProfitLoss: variable.episode.profitLoss, + accumulatedProfitLoss: variable.episode.stat.profitLoss, lastTradeProfitLoss: variable.last.position.profitLoss, stopLoss: variable.current.position.stopLoss, - tradesCount: variable.episode.tradesCount, - hits: variable.episode.hits, - fails: variable.episode.fails, - hitRatio: variable.episode.hitRatio, - ROI: variable.episode.ROI, - periods: variable.episode.periods, - days: variable.episode.days, - anualizedRateOfReturn: variable.anualizedRateOfReturn, + tradesCount: variable.episode.count.positions, + hits: variable.episode.count.hits, + fails: variable.episode.count.fails, + hitRatio: variable.episode.stat.hitRatio, + ROI: variable.episode.stat.ROI, + periods: variable.episode.count.periods, + days: variable.episode.stat.days, + anualizedRateOfReturn: variable.episode.stat.anualizedRateOfReturn, positionRate: variable.current.position.rate, lastTradeROI: variable.last.position.ROI, strategy: variable.current.strategy.index, @@ -2116,22 +2127,22 @@ stopLossPhase: variable.current.position.stopLossPhase, takeProfitPhase: variable.current.position.takeProfitPhase, positionSize: variable.current.position.size, - initialBalanceA: variable.initial.balance.baseAsset, - minimumBalanceA: variable.minimum.balance.baseAsset, - maximumBalanceA: variable.maximum.balance.baseAsset, - initialBalanceB: variable.initial.balance.quotedAsset, - minimumBalanceB: variable.minimum.balance.quotedAsset, - maximumBalanceB: variable.maximum.balance.quotedAsset, - baseAsset: '"' + variable.episode.baseAsset + '"', - quotedAsset: '"' + variable.episode.quotedAsset + '"', - marketBaseAsset: '"' + variable.episode.marketBaseAsset + '"', - marketQuotedAsset: '"' + variable.episode.marketQuotedAsset + '"' , + initialBalanceA: variable.episode.parameters.initial.balance.baseAsset, + minimumBalanceA: variable.episode.parameters.minimum.balance.baseAsset, + maximumBalanceA: variable.episode.parameters.maximum.balance.baseAsset, + initialBalanceB: variable.episode.parameters.initial.balance.quotedAsset, + minimumBalanceB: variable.episode.parameters.minimum.balance.quotedAsset, + maximumBalanceB: variable.episode.parameters.maximum.balance.quotedAsset, + baseAsset: '"' + variable.episode.parameters.baseAsset + '"', + quotedAsset: '"' + variable.episode.parameters.quotedAsset + '"', + marketBaseAsset: '"' + variable.episode.parameters.marketBaseAsset + '"', + marketQuotedAsset: '"' + variable.episode.parameters.marketQuotedAsset + '"' , positionPeriods: variable.current.position.periods, positionDays: variable.positionDays, - distanceToEventTriggerOn: variable.distance.toEvent.triggerOn, - distanceToEventTriggerOff: variable.distance.toEvent.triggerOff, - distanceToEventTakePosition: variable.distance.toEvent.takePosition, - distanceToEventClosePosition: variable.distance.toEvent.closePosition + distanceToEventTriggerOn: variable.current.distance.toEvent.triggerOn, + distanceToEventTriggerOff: variable.current.distance.toEvent.triggerOff, + distanceToEventTakePosition: variable.current.distance.toEvent.takePosition, + distanceToEventClosePosition: variable.current.distance.toEvent.closePosition } recordsArray.push(simulationRecord); @@ -2183,8 +2194,8 @@ variable.current.position.end = candle.end variable.current.position.endRate = candle.close - /* Here we will calculate the ongoing variable.episode.ROI */ - if (variable.episode.baseAsset === variable.episode.marketBaseAsset) { + /* Here we will calculate the ongoing variable.episode.stat.ROI */ + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { variable.current.position.lastTradeROI = (variable.current.position.rate - candle.close) / variable.current.position.rate * 100 } else { variable.current.position.lastTradeROI = (candle.close - variable.current.position.rate) / variable.current.position.rate * 100 @@ -2237,7 +2248,7 @@ } } - if (variable.episode.periods > lastPeriodAnnounced) { + if (variable.episode.count.periods > lastPeriodAnnounced) { if (isNaN(value) === false) { /* The Value Variation is what tells us how much the value already announced must change in order to annouce it again. */ @@ -2265,12 +2276,12 @@ /* Next, we will remmeber this announcement was already done, so that it is not announced again in further processing of the same day. */ if (newAnnouncementRecord.periods !== undefined) { - newAnnouncementRecord.periods = variable.episode.periods + newAnnouncementRecord.periods = variable.episode.count.periods newAnnouncementRecord.value = value } else { newAnnouncementRecord = { key: key, - periods: variable.episode.periods, + periods: variable.episode.count.periods, value: value } variable.announcements.push(newAnnouncementRecord) From 8415cdba0d6d39349afe31c2a34158b61123548c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 20 May 2020 12:33:58 +0200 Subject: [PATCH 24/44] Move to Code --- TradingBot.js | 1202 ++++++------- TradingSimulation.js | 3800 +++++++++++++++++++++--------------------- 2 files changed, 2501 insertions(+), 2501 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index bc34ed945..8af541f99 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -1,134 +1,134 @@ -exports.newTradingBot = function newTradingBot (bot, logger, UTILITIES, FILE_STORAGE) { - const FULL_LOG = true - const LOG_FILE_CONTENT = false - const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000 +exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STORAGE) { + const FULL_LOG = true + const LOG_FILE_CONTENT = false + const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000 - const MODULE_NAME = 'Trading Bot' + const MODULE_NAME = 'Trading Bot' - let thisObject = { - initialize: initialize, - finalize: finalize, - start: start - } - - let utilities = UTILITIES.newCloudUtilities(logger) - let fileStorage = FILE_STORAGE.newFileStorage(logger) - - const COMMONS = require('./Commons.js') - let commons = COMMONS.newCommons(bot, logger, UTILITIES, FILE_STORAGE) - - let exchangeAPI - - return thisObject - - function finalize () { - thisObject = undefined - utilities = undefined - fileStorage = undefined - commons = undefined - } - - function initialize (pExchangeAPI, callBackFunction) { - try { - logger.fileName = MODULE_NAME - logger.initialize() - - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] initialize -> Entering function.') } - - exchangeAPI = pExchangeAPI - callBackFunction(global.DEFAULT_OK_RESPONSE) - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] initialize -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) + let thisObject = { + initialize: initialize, + finalize: finalize, + start: start } - } - function start (multiPeriodDataFiles, timeFrame, timeFrameLabel, currentDay, variable, callBackFunction) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> Entering function.') } + let utilities = UTILITIES.newCloudUtilities(logger) + let fileStorage = FILE_STORAGE.newFileStorage(logger) - let chart = {} - let mainDependency = {} + const COMMONS = require('./Commons.js') + let commons = COMMONS.newCommons(bot, logger, UTILITIES, FILE_STORAGE) + + let exchangeAPI + + return thisObject + + function finalize() { + thisObject = undefined + utilities = undefined + fileStorage = undefined + commons = undefined + } + + function initialize(pExchangeAPI, callBackFunction) { + try { + logger.fileName = MODULE_NAME + logger.initialize() + + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] initialize -> Entering function.') } + + exchangeAPI = pExchangeAPI + callBackFunction(global.DEFAULT_OK_RESPONSE) + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] initialize -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + + function start(multiPeriodDataFiles, timeFrame, timeFrameLabel, currentDay, variable, callBackFunction) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> Entering function.') } + + let chart = {} + let mainDependency = {} /* The first phase here is about checking that we have everything we need at the definition level. */ - let dataDependencies = bot.processNode.referenceParent.processDependencies.dataDependencies - if (commons.validateDataDependencies(dataDependencies, callBackFunction) !== true) { return } + let dataDependencies = bot.processNode.referenceParent.processDependencies.dataDependencies + if (commons.validateDataDependencies(dataDependencies, callBackFunction) !== true) { return } - let outputDatasets = bot.processNode.referenceParent.processOutput.outputDatasets - if (commons.validateOutputDatasets(outputDatasets, callBackFunction) !== true) { return } + let outputDatasets = bot.processNode.referenceParent.processOutput.outputDatasets + if (commons.validateOutputDatasets(outputDatasets, callBackFunction) !== true) { return } /* The second phase is about transforming the inputs into a format that can be used to apply the user defined code. */ - for (let j = 0; j < global.marketFilesPeriods.length; j++) { - let timeFrameLabel = marketFilesPeriods[j][1] - let dataFiles = multiPeriodDataFiles.get(timeFrameLabel) - let products = {} + for (let j = 0; j < global.marketFilesPeriods.length; j++) { + let timeFrameLabel = marketFilesPeriods[j][1] + let dataFiles = multiPeriodDataFiles.get(timeFrameLabel) + let products = {} - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> Inflating Data Files for timeFrame = ' + timeFrameLabel) } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> Inflating Data Files for timeFrame = ' + timeFrameLabel) } - if (dataFiles !== undefined) { - commons.inflateDatafiles(dataFiles, dataDependencies, products, mainDependency, timeFrame) + if (dataFiles !== undefined) { + commons.inflateDatafiles(dataFiles, dataDependencies, products, mainDependency, timeFrame) - let propertyName = 'at' + timeFrameLabel.replace('-', '') - chart[propertyName] = products - } - } + let propertyName = 'at' + timeFrameLabel.replace('-', '') + chart[propertyName] = products + } + } - for (let j = 0; j < global.dailyFilePeriods.length; j++) { - let timeFrameLabel = global.dailyFilePeriods[j][1] - let dataFiles = multiPeriodDataFiles.get(timeFrameLabel) - let products = {} + for (let j = 0; j < global.dailyFilePeriods.length; j++) { + let timeFrameLabel = global.dailyFilePeriods[j][1] + let dataFiles = multiPeriodDataFiles.get(timeFrameLabel) + let products = {} - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> Inflating Data Files for timeFrame = ' + timeFrameLabel) } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> Inflating Data Files for timeFrame = ' + timeFrameLabel) } - if (dataFiles !== undefined) { - commons.inflateDatafiles(dataFiles, dataDependencies, products, mainDependency, timeFrame) + if (dataFiles !== undefined) { + commons.inflateDatafiles(dataFiles, dataDependencies, products, mainDependency, timeFrame) - let propertyName = 'at' + timeFrameLabel.replace('-', '') - chart[propertyName] = products - } - } + let propertyName = 'at' + timeFrameLabel.replace('-', '') + chart[propertyName] = products + } + } /* Single Files */ - let dataFiles = multiPeriodDataFiles.get('Single Files') - let products = {} + let dataFiles = multiPeriodDataFiles.get('Single Files') + let products = {} - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> Inflating Data Files from Single Files.') } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> Inflating Data Files from Single Files.') } - if (dataFiles !== undefined) { - commons.inflateDatafiles(dataFiles, dataDependencies, products, mainDependency, timeFrame) + if (dataFiles !== undefined) { + commons.inflateDatafiles(dataFiles, dataDependencies, products, mainDependency, timeFrame) - let propertyName = 'atAnyTimeFrame' - chart[propertyName] = products - } + let propertyName = 'atAnyTimeFrame' + chart[propertyName] = products + } /* Simulation */ - const TRADING_SIMULATION = require('./TradingSimulation.js') - let tradingSimulation = TRADING_SIMULATION.newTradingSimulation(bot, logger, UTILITIES) + const TRADING_SIMULATION = require('./TradingSimulation.js') + let tradingSimulation = TRADING_SIMULATION.newTradingSimulation(bot, logger, UTILITIES) - let market = bot.market + let market = bot.market - const SIMULATED_RECORDS_FOLDER_NAME = 'Trading-Simulation' - const CONDITIONS_FOLDER_NAME = 'Simulation-Conditions' - const STRATEGIES_FOLDER_NAME = 'Simulation-Strategies' - const TRADES_FOLDER_NAME = 'Simulation-Trades' - const SNAPSHOTS_FOLDER_NAME = 'Snapshots' + const SIMULATED_RECORDS_FOLDER_NAME = 'Trading-Simulation' + const CONDITIONS_FOLDER_NAME = 'Simulation-Conditions' + const STRATEGIES_FOLDER_NAME = 'Simulation-Strategies' + const TRADES_FOLDER_NAME = 'Simulation-Trades' + const SNAPSHOTS_FOLDER_NAME = 'Snapshots' - const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000 + const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000 - let recordsArray - let conditionsArray - let strategiesArray - let tradesArray + let recordsArray + let conditionsArray + let strategiesArray + let tradesArray - let snapshotHeaders - let triggerOnSnapshot - let takePositionSnapshot + let snapshotHeaders + let triggerOnSnapshot + let takePositionSnapshot - let tradingSystem = {} + let tradingSystem = {} - tradingSimulation.runSimulation( + tradingSimulation.runSimulation( chart, dataDependencies, timeFrame, @@ -139,42 +139,42 @@ exports.newTradingBot = function newTradingBot (bot, logger, UTILITIES, FILE_STO writeFiles, callBackFunction) - function writeFiles (pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pSnapshotHeaders, pTriggerOnSnapshot, pTakePositionSnapshot) { - tradingSystem = pTradingSystem - recordsArray = pRecordsArray - conditionsArray = pConditionsArray - strategiesArray = pStrategiesArray - tradesArray = pTradesArray + function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pSnapshotHeaders, pTriggerOnSnapshot, pTakePositionSnapshot) { + tradingSystem = pTradingSystem + recordsArray = pRecordsArray + conditionsArray = pConditionsArray + strategiesArray = pStrategiesArray + tradesArray = pTradesArray - snapshotHeaders = pSnapshotHeaders - triggerOnSnapshot = pTriggerOnSnapshot - takePositionSnapshot = pTakePositionSnapshot + snapshotHeaders = pSnapshotHeaders + triggerOnSnapshot = pTriggerOnSnapshot + takePositionSnapshot = pTakePositionSnapshot - if (timeFrame > global.dailyFilePeriods[0][0]) { - writeMarketFiles() - } else { - writeDailyFiles() - } - } + if (timeFrame > global.dailyFilePeriods[0][0]) { + writeMarketFiles() + } else { + writeDailyFiles() + } + } - function writeMarketFiles () { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> Entering function.') } + function writeMarketFiles() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> Entering function.') } - writeRecordsFile() + writeRecordsFile() - function writeRecordsFile () { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeRecordsFile -> Entering function.') } + function writeRecordsFile() { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeRecordsFile -> Entering function.') } - let separator = '' - let fileRecordCounter = 0 + let separator = '' + let fileRecordCounter = 0 - let fileContent = '' + let fileContent = '' - for (let i = 0; i < recordsArray.length; i++) { - let record = recordsArray[i] + for (let i = 0; i < recordsArray.length; i++) { + let record = recordsArray[i] - fileContent = fileContent + separator + '[' + + fileContent = fileContent + separator + '[' + record.begin + ',' + record.end + ',' + record.balanceBaseAsset + ',' + @@ -214,124 +214,124 @@ exports.newTradingBot = function newTradingBot (bot, logger, UTILITIES, FILE_STO record.distanceToLastTakePosition + ',' + record.distanceToLastClosePosition + ']' - if (separator === '') { separator = ',' } + if (separator === '') { separator = ',' } - fileRecordCounter++ - } + fileRecordCounter++ + } - fileContent = '[' + fileContent + ']' + fileContent = '[' + fileContent + ']' - let fileName = 'Data.json' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + SIMULATED_RECORDS_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel - filePath += '/' + fileName + let fileName = 'Data.json' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + SIMULATED_RECORDS_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel + filePath += '/' + fileName - fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) + fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) - function onFileCreated (err) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> Entering function.') } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> fileContent = ' + fileContent) } + function onFileCreated(err) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> Entering function.') } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> fileContent = ' + fileContent) } - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) - callBackFunction(err) - return + callBackFunction(err) + return + } + + writeConditionsFile() + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeRecordsFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } } - writeConditionsFile() - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeRecordsFile -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } + function writeConditionsFile() { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeConditionsFile -> Entering function.') } - function writeConditionsFile () { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeConditionsFile -> Entering function.') } + let separator = '' + let fileRecordCounter = 0 - let separator = '' - let fileRecordCounter = 0 + let fileContent = '' - let fileContent = '' + for (let i = 0; i < conditionsArray.length; i++) { + let record = conditionsArray[i] - for (let i = 0; i < conditionsArray.length; i++) { - let record = conditionsArray[i] + let conditions = '' + let conditionsSeparator = '' - let conditions = '' - let conditionsSeparator = '' + for (let j = 0; j < record.length - 3; j++) { + conditions = conditions + conditionsSeparator + record[j] + if (conditionsSeparator === '') { conditionsSeparator = ',' } + } - for (let j = 0; j < record.length - 3; j++) { - conditions = conditions + conditionsSeparator + record[j] - if (conditionsSeparator === '') { conditionsSeparator = ',' } - } + conditions = conditions + conditionsSeparator + '[' + record[record.length - 3] + ']' // The last item contains an Array of condition values. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 2] + ']' // The last item contains an Array of formulaErrors. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']' // The last item contains an Array of formulaValues. - conditions = conditions + conditionsSeparator + '[' + record[record.length - 3] + ']' // The last item contains an Array of condition values. - conditions = conditions + conditionsSeparator + '[' + record[record.length - 2] + ']' // The last item contains an Array of formulaErrors. - conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']' // The last item contains an Array of formulaValues. + fileContent = fileContent + separator + '[' + conditions + ']' - fileContent = fileContent + separator + '[' + conditions + ']' + if (separator === '') { separator = ',' } - if (separator === '') { separator = ',' } + fileRecordCounter++ + } - fileRecordCounter++ - } + fileContent = '[' + fileContent + ']' + fileContent = '[' + JSON.stringify(tradingSystem) + ',' + fileContent + ']' - fileContent = '[' + fileContent + ']' - fileContent = '[' + JSON.stringify(tradingSystem) + ',' + fileContent + ']' + let fileName = 'Data.json' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + CONDITIONS_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel + filePath += '/' + fileName - let fileName = 'Data.json' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + CONDITIONS_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel - filePath += '/' + fileName + fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) - fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) + function onFileCreated(err) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> Entering function.') } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> fileContent = ' + fileContent) } - function onFileCreated (err) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> Entering function.') } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> fileContent = ' + fileContent) } + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) + callBackFunction(err) + return + } - callBackFunction(err) - return + writeStrategiesFile() + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeConditionsFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } } - writeStrategiesFile() - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeConditionsFile -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } + function writeStrategiesFile() { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeStrategiesFile -> Entering function.') } - function writeStrategiesFile () { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeStrategiesFile -> Entering function.') } + let separator = '' + let fileRecordCounter = 0 - let separator = '' - let fileRecordCounter = 0 + let fileContent = '' - let fileContent = '' + for (let i = 0; i < strategiesArray.length; i++) { + let record = strategiesArray[i] - for (let i = 0; i < strategiesArray.length; i++) { - let record = strategiesArray[i] - - fileContent = fileContent + separator + '[' + + fileContent = fileContent + separator + '[' + record.begin + ',' + record.end + ',' + record.status + ',' + @@ -341,59 +341,59 @@ exports.newTradingBot = function newTradingBot (bot, logger, UTILITIES, FILE_STO '"' + record.triggerOnSituation + '"' + ',' + '"' + record.name + '"' + ']' - if (separator === '') { separator = ',' } + if (separator === '') { separator = ',' } - fileRecordCounter++ - } + fileRecordCounter++ + } - fileContent = '[' + fileContent + ']' + fileContent = '[' + fileContent + ']' - let fileName = 'Data.json' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + STRATEGIES_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel - filePath += '/' + fileName + let fileName = 'Data.json' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + STRATEGIES_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel + filePath += '/' + fileName - fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) + fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) - function onFileCreated (err) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> Entering function.') } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> fileContent = ' + fileContent) } + function onFileCreated(err) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> Entering function.') } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> fileContent = ' + fileContent) } - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) - callBackFunction(err) - return + callBackFunction(err) + return + } + + writeTradesFile() + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeStrategiesFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } } - writeTradesFile() - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeStrategiesFile -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } + function writeTradesFile() { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeTradesFile -> Entering function.') } - function writeTradesFile () { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeTradesFile -> Entering function.') } + let separator = '' + let fileRecordCounter = 0 - let separator = '' - let fileRecordCounter = 0 + let fileContent = '' - let fileContent = '' + for (let i = 0; i < tradesArray.length; i++) { + let record = tradesArray[i] + if (record.stopRate === undefined) { record.stopRate = 0 } - for (let i = 0; i < tradesArray.length; i++) { - let record = tradesArray[i] - if (record.stopRate === undefined) { record.stopRate = 0 } - - fileContent = fileContent + separator + '[' + + fileContent = fileContent + separator + '[' + record.begin + ',' + record.end + ',' + record.status + ',' + @@ -403,139 +403,139 @@ exports.newTradingBot = function newTradingBot (bot, logger, UTILITIES, FILE_STO record.exitType + ',' + '"' + record.takePositionSituation + '"' + ']' - if (separator === '') { separator = ',' } + if (separator === '') { separator = ',' } - fileRecordCounter++ - } + fileRecordCounter++ + } - fileContent = '[' + fileContent + ']' + fileContent = '[' + fileContent + ']' - let fileName = 'Data.json' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + TRADES_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel - filePath += '/' + fileName + let fileName = 'Data.json' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + TRADES_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel + filePath += '/' + fileName - fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) + fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) - function onFileCreated (err) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> Entering function.') } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> fileContent = ' + fileContent) } + function onFileCreated(err) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> Entering function.') } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> fileContent = ' + fileContent) } - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) - callBackFunction(err) - return + callBackFunction(err) + return + } + + writeSnapshotFiles() + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeTradesFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } } - writeSnapshotFiles() - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeTradesFile -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } + function writeSnapshotFiles() { + writeSnapshotFile(triggerOnSnapshot, 'Trigger-On', onFinish) - function writeSnapshotFiles () { - writeSnapshotFile(triggerOnSnapshot, 'Trigger-On', onFinish) - - function onFinish () { - writeSnapshotFile(takePositionSnapshot, 'Take-Position', callBackFunction) - } - } - - function writeSnapshotFile (snapshotArray, pFileName, callBack) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeSnapshotFile -> Entering function.') } - - let fileRecordCounter = 0 - - let fileContent = '' - let separator = '\r\n' - - parseRecord(snapshotHeaders) - - for (let i = 0; i < snapshotArray.length; i++) { - let record = snapshotArray[i] - parseRecord(record) - fileRecordCounter++ - } - - function parseRecord (record) { - for (let j = 0; j < record.length; j++) { - let property = record[j] - - fileContent = fileContent + '' + property - if (j !== record.length - 1) { - fileContent = fileContent + ',' - } - } - fileContent = fileContent + separator - } - - fileContent = '' + fileContent + '' - - let fileName = pFileName + '.csv' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + SNAPSHOTS_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel - filePath += '/' + fileName - - fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) - - function onFileCreated (err) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> Entering function.') } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> fileContent = ' + fileContent) } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) - - callBackFunction(err) - return + function onFinish() { + writeSnapshotFile(takePositionSnapshot, 'Take-Position', callBackFunction) + } } - callBack(global.DEFAULT_OK_RESPONSE) - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } + function writeSnapshotFile(snapshotArray, pFileName, callBack) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeSnapshotFile -> Entering function.') } + + let fileRecordCounter = 0 + + let fileContent = '' + let separator = '\r\n' + + parseRecord(snapshotHeaders) + + for (let i = 0; i < snapshotArray.length; i++) { + let record = snapshotArray[i] + parseRecord(record) + fileRecordCounter++ + } + + function parseRecord(record) { + for (let j = 0; j < record.length; j++) { + let property = record[j] + + fileContent = fileContent + '' + property + if (j !== record.length - 1) { + fileContent = fileContent + ',' + } + } + fileContent = fileContent + separator + } + + fileContent = '' + fileContent + '' + + let fileName = pFileName + '.csv' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + SNAPSHOTS_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel + filePath += '/' + fileName + + fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) + + function onFileCreated(err) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> Entering function.') } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> fileContent = ' + fileContent) } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) + + callBackFunction(err) + return + } + + callBack(global.DEFAULT_OK_RESPONSE) + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } - function writeDailyFiles () { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> Entering function.') } + function writeDailyFiles() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> Entering function.') } - writeRecordsFile() + writeRecordsFile() - function writeRecordsFile () { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeRecordsFile -> Entering function.') } + function writeRecordsFile() { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeRecordsFile -> Entering function.') } - let separator = '' - let fileRecordCounter = 0 + let separator = '' + let fileRecordCounter = 0 - let fileContent = '' + let fileContent = '' - for (let i = 0; i < recordsArray.length; i++) { - let record = recordsArray[i] + for (let i = 0; i < recordsArray.length; i++) { + let record = recordsArray[i] /* Will only add to the file the records of the current day */ - if (record.begin < currentDay.valueOf()) { continue } + if (record.begin < currentDay.valueOf()) { continue } - fileContent = fileContent + separator + '[' + + fileContent = fileContent + separator + '[' + record.begin + ',' + record.end + ',' + record.balanceBaseAsset + ',' + @@ -575,139 +575,139 @@ exports.newTradingBot = function newTradingBot (bot, logger, UTILITIES, FILE_STO record.distanceToLastTakePosition + ',' + record.distanceToLastClosePosition + ']' - if (separator === '') { separator = ',' } + if (separator === '') { separator = ',' } - fileRecordCounter++ - } + fileRecordCounter++ + } - fileContent = '[' + fileContent + ']' + fileContent = '[' + fileContent + ']' - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) - let fileName = 'Data.json' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + SIMULATED_RECORDS_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath - filePath += '/' + fileName + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) + let fileName = 'Data.json' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + SIMULATED_RECORDS_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath + filePath += '/' + fileName - fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) + fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) - function onFileCreated (err) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> Entering function.') } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> fileContent = ' + fileContent) } + function onFileCreated(err) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> Entering function.') } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> fileContent = ' + fileContent) } - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) - callBackFunction(err) - return + callBackFunction(err) + return + } + + writeConditionsFile() + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeRecordsFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } } - writeConditionsFile() - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeRecordsFile -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } + function writeConditionsFile() { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeConditionsFile -> Entering function.') } - function writeConditionsFile () { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeConditionsFile -> Entering function.') } + let separator = '' + let fileRecordCounter = 0 - let separator = '' - let fileRecordCounter = 0 + let fileContent = '' - let fileContent = '' - - for (let i = 0; i < conditionsArray.length; i++) { - let record = conditionsArray[i] + for (let i = 0; i < conditionsArray.length; i++) { + let record = conditionsArray[i] /* Will only add to the file the records of the current day */ - if (record.begin < currentDay.valueOf()) { continue } + if (record.begin < currentDay.valueOf()) { continue } - let conditions = '' - let conditionsSeparator = '' + let conditions = '' + let conditionsSeparator = '' /* Will only add to the file the records of the current day */ - if (record.begin < currentDay.valueOf()) { continue } + if (record.begin < currentDay.valueOf()) { continue } - for (let j = 0; j < record.length - 3; j++) { - conditions = conditions + conditionsSeparator + record[j] - if (conditionsSeparator === '') { conditionsSeparator = ',' } - } + for (let j = 0; j < record.length - 3; j++) { + conditions = conditions + conditionsSeparator + record[j] + if (conditionsSeparator === '') { conditionsSeparator = ',' } + } - conditions = conditions + conditionsSeparator + '[' + record[record.length - 3] + ']' // The last item contains an Array of condition values. - conditions = conditions + conditionsSeparator + '[' + record[record.length - 2] + ']' // The last item contains an Array of formulaErrors. - conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']' // The last item contains an Array of formulaValues. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 3] + ']' // The last item contains an Array of condition values. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 2] + ']' // The last item contains an Array of formulaErrors. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']' // The last item contains an Array of formulaValues. - fileContent = fileContent + separator + '[' + conditions + ']' + fileContent = fileContent + separator + '[' + conditions + ']' - if (separator === '') { separator = ',' } + if (separator === '') { separator = ',' } - fileRecordCounter++ - } + fileRecordCounter++ + } - fileContent = '[' + fileContent + ']' - fileContent = '[' + JSON.stringify(tradingSystem) + ',' + fileContent + ']' + fileContent = '[' + fileContent + ']' + fileContent = '[' + JSON.stringify(tradingSystem) + ',' + fileContent + ']' - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) - let fileName = 'Data.json' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + CONDITIONS_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath - filePath += '/' + fileName + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) + let fileName = 'Data.json' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + CONDITIONS_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath + filePath += '/' + fileName - fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) + fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) - function onFileCreated (err) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> Entering function.') } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> fileContent = ' + fileContent) } + function onFileCreated(err) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> Entering function.') } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> fileContent = ' + fileContent) } - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) - callBackFunction(err) - return + callBackFunction(err) + return + } + + writeStrategiesFile() + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeConditionsFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } } - writeStrategiesFile() - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeConditionsFile -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } + function writeStrategiesFile() { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeStrategiesFile -> Entering function.') } - function writeStrategiesFile () { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeStrategiesFile -> Entering function.') } + let separator = '' + let fileRecordCounter = 0 - let separator = '' - let fileRecordCounter = 0 + let fileContent = '' - let fileContent = '' - - for (let i = 0; i < strategiesArray.length; i++) { - let record = strategiesArray[i] + for (let i = 0; i < strategiesArray.length; i++) { + let record = strategiesArray[i] /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends at the current date. */ - if (record.end < currentDay.valueOf()) { continue } + if (record.end < currentDay.valueOf()) { continue } - fileContent = fileContent + separator + '[' + + fileContent = fileContent + separator + '[' + record.begin + ',' + record.end + ',' + record.status + ',' + @@ -717,65 +717,65 @@ exports.newTradingBot = function newTradingBot (bot, logger, UTILITIES, FILE_STO '"' + record.triggerOnSituation + '"' + ',' + '"' + record.name + '"' + ']' - if (separator === '') { separator = ',' } + if (separator === '') { separator = ',' } - fileRecordCounter++ - } + fileRecordCounter++ + } - fileContent = '[' + fileContent + ']' + fileContent = '[' + fileContent + ']' - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) - let fileName = 'Data.json' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + STRATEGIES_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath - filePath += '/' + fileName + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) + let fileName = 'Data.json' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + STRATEGIES_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath + filePath += '/' + fileName - fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) + fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) - function onFileCreated (err) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> Entering function.') } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> fileContent = ' + fileContent) } + function onFileCreated(err) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> Entering function.') } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> fileContent = ' + fileContent) } - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) - callBackFunction(err) - return + callBackFunction(err) + return + } + + writeTradesFile() + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeStrategiesFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } } - writeTradesFile() - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeStrategiesFile -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } + function writeTradesFile() { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeTradesFile -> Entering function.') } - function writeTradesFile () { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeTradesFile -> Entering function.') } + let separator = '' + let fileRecordCounter = 0 - let separator = '' - let fileRecordCounter = 0 + let fileContent = '' - let fileContent = '' - - for (let i = 0; i < tradesArray.length; i++) { - let record = tradesArray[i] + for (let i = 0; i < tradesArray.length; i++) { + let record = tradesArray[i] /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends at the current date. */ - if (record.end < currentDay.valueOf()) { continue } - if (record.stopRate === undefined) { record.stopRate = 0 } + if (record.end < currentDay.valueOf()) { continue } + if (record.stopRate === undefined) { record.stopRate = 0 } - fileContent = fileContent + separator + '[' + + fileContent = fileContent + separator + '[' + record.begin + ',' + record.end + ',' + record.status + ',' + @@ -785,122 +785,122 @@ exports.newTradingBot = function newTradingBot (bot, logger, UTILITIES, FILE_STO record.exitType + ',' + '"' + record.takePositionSituation + '"' + ']' - if (separator === '') { separator = ',' } + if (separator === '') { separator = ',' } - fileRecordCounter++ - } + fileRecordCounter++ + } - fileContent = '[' + fileContent + ']' + fileContent = '[' + fileContent + ']' - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) - let fileName = 'Data.json' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + TRADES_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath - filePath += '/' + fileName + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) + let fileName = 'Data.json' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + TRADES_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath + filePath += '/' + fileName - fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) + fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) - function onFileCreated (err) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> Entering function.') } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> fileContent = ' + fileContent) } + function onFileCreated(err) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> Entering function.') } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> fileContent = ' + fileContent) } - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) - callBackFunction(err) - return + callBackFunction(err) + return + } + + writeSnapshotFiles() + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeTradesFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } } - writeSnapshotFiles() - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } + function writeSnapshotFiles() { + writeSnapshotFile(triggerOnSnapshot, 'Trigger-On', onFinish) + + function onFinish() { + writeSnapshotFile(takePositionSnapshot, 'Take-Position', callBackFunction) + } + } + + function writeSnapshotFile(snapshotArray, pFileName, callBack) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeSnapshotFile -> Entering function.') } + + let fileRecordCounter = 0 + + let fileContent = '' + let separator = '\r\n' + + parseRecord(snapshotHeaders) + + for (let i = 0; i < snapshotArray.length; i++) { + let record = snapshotArray[i] + parseRecord(record) + fileRecordCounter++ + } + + function parseRecord(record) { + for (let j = 0; j < record.length; j++) { + let property = record[j] + + fileContent = fileContent + '' + property + if (j !== record.length - 1) { + fileContent = fileContent + ',' + } + } + fileContent = fileContent + separator + } + + fileContent = '' + fileContent + '' + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) + let fileName = pFileName + '.csv' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + SNAPSHOTS_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath + filePath += '/' + fileName + + fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) + + function onFileCreated(err) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> Entering function.') } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> fileContent = ' + fileContent) } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) + + callBackFunction(err) + return + } + + callBack(global.DEFAULT_OK_RESPONSE) + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeSnapshotFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeTradesFile -> err = ' + err.stack) + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> err = ' + err.stack) callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } } - - function writeSnapshotFiles () { - writeSnapshotFile(triggerOnSnapshot, 'Trigger-On', onFinish) - - function onFinish () { - writeSnapshotFile(takePositionSnapshot, 'Take-Position', callBackFunction) - } - } - - function writeSnapshotFile (snapshotArray, pFileName, callBack) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeSnapshotFile -> Entering function.') } - - let fileRecordCounter = 0 - - let fileContent = '' - let separator = '\r\n' - - parseRecord(snapshotHeaders) - - for (let i = 0; i < snapshotArray.length; i++) { - let record = snapshotArray[i] - parseRecord(record) - fileRecordCounter++ - } - - function parseRecord (record) { - for (let j = 0; j < record.length; j++) { - let property = record[j] - - fileContent = fileContent + '' + property - if (j !== record.length - 1) { - fileContent = fileContent + ',' - } - } - fileContent = fileContent + separator - } - - fileContent = '' + fileContent + '' - - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) - let fileName = pFileName + '.csv' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + SNAPSHOTS_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath - filePath += '/' + fileName - - fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated) - - function onFileCreated (err) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> Entering function.') } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> fileContent = ' + fileContent) } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) - - callBackFunction(err) - return - } - - callBack(global.DEFAULT_OK_RESPONSE) - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeSnapshotFile -> onFileCreated -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeSnapshotFile -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) } - } } diff --git a/TradingSimulation.js b/TradingSimulation.js index d79e83e98..be9153fbb 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -1,25 +1,25 @@ -exports.newTradingSimulation = function newTradingSimulation (bot, logger, UTILITIES) { - const FULL_LOG = true - const LOG_FILE_CONTENT = false - const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000 - const MODULE_NAME = 'Trading Simulation -> ' + bot.SESSION.name +exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILITIES) { + const FULL_LOG = true + const LOG_FILE_CONTENT = false + const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000 + const MODULE_NAME = 'Trading Simulation -> ' + bot.SESSION.name - const GMT_SECONDS = ':00.000 GMT+0000' + const GMT_SECONDS = ':00.000 GMT+0000' - let thisObject = { - finalize: finalize, - runSimulation: runSimulation - } + let thisObject = { + finalize: finalize, + runSimulation: runSimulation + } - let utilities = UTILITIES.newCloudUtilities(bot, logger) + let utilities = UTILITIES.newCloudUtilities(bot, logger) - return thisObject + return thisObject - function finalize () { - thisObject = undefined - } + function finalize() { + thisObject = undefined + } - function runSimulation ( + function runSimulation( chart, dataDependencies, timeFrame, @@ -29,2441 +29,2441 @@ exports.newTradingSimulation = function newTradingSimulation (bot, logger, UTILI exchangeAPI, callback, callBackFunction) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> Entering function.') } - let processingDailyFiles - if (timeFrame > global.dailyFilePeriods[0][0]) { - processingDailyFiles = false - } else { - processingDailyFiles = true - } + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> Entering function.') } + let processingDailyFiles + if (variable.episode.parameters.timeFrame > global.dailyFilePeriods[0][0]) { + processingDailyFiles = false + } else { + processingDailyFiles = true + } - let recordsArray = [] - let conditionsArray = [] - let strategiesArray = [] - let tradesArray = [] + let recordsArray = [] + let conditionsArray = [] + let strategiesArray = [] + let positionsArray = [] - let tradingSystem = bot.TRADING_SYSTEM + let tradingSystem = bot.TRADING_SYSTEM - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> bot.VALUES_TO_USE.timeRange.initialDatetime = ' + bot.VALUES_TO_USE.timeRange.initialDatetime) } - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> bot.VALUES_TO_USE.timeRange.finalDatetime = ' + bot.VALUES_TO_USE.timeRange.finalDatetime) } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> bot.VALUES_TO_USE.timeRange.initialDatetime = ' + bot.VALUES_TO_USE.timeRange.initialDatetime) } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> bot.VALUES_TO_USE.timeRange.finalDatetime = ' + bot.VALUES_TO_USE.timeRange.finalDatetime) } - let timerToCloseStage = 0 + let timerToCloseStage = 0 /* Stop Loss Management */ - const MIN_STOP_LOSS_VALUE = 0.0000000001 // We can not let the stop be zero to avoid division by 0 error or infinity numbers as a result. - const MAX_STOP_LOSS_VALUE = Number.MAX_SAFE_INTEGER + const MIN_STOP_LOSS_VALUE = 0.0000000001 // We can not let the stop be zero to avoid division by 0 error or infinity numbers as a result. + const MAX_STOP_LOSS_VALUE = Number.MAX_SAFE_INTEGER /* Take Profit Management */ - const MIN_TAKE_PROFIT_VALUE = 0.0000000001 // We can not let the buy order be zero to avoid division by 0 error or infinity numbers as a result. - const MAX_TAKE_PROFIT_VALUE = Number.MAX_SAFE_INTEGER + const MIN_TAKE_PROFIT_VALUE = 0.0000000001 // We can not let the buy order be zero to avoid division by 0 error or infinity numbers as a result. + const MAX_TAKE_PROFIT_VALUE = Number.MAX_SAFE_INTEGER /* Variables for this executioin only */ - let takePositionNow = false - let closePositionNow = false + let takePositionNow = false + let closePositionNow = false /* In some cases we need to know if we are positioned at the last candle of the calendar day, for that we need these variables. */ - let lastInstantOfTheDay = 0 - if (currentDay) { - lastInstantOfTheDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1 - } + let lastInstantOfTheDay = 0 + if (currentDay) { + lastInstantOfTheDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1 + } - if (variable.isInitialized !== true) { - variable.isInitialized = true + if (variable.isInitialized !== true) { + variable.isInitialized = true - variable.episode = {} // An Episode represents each execution of the Simulation - variable.episode.count = {} // Everything in here means the total count since the begining of the episode. - variable.episode.stat = {} // Everything in here means the statistics calculated since the begining of the episode. + variable.episode = {} // An Episode represents each execution of the Simulation + variable.episode.count = {} // Everything in here means the total count since the begining of the episode. + variable.episode.stat = {} // Everything in here means the statistics calculated since the begining of the episode. - variable.current = {} // Everything in here means that is happening right now. - variable.current.balance = {} // Balances at the current candle of the Simulation. - variable.current.distance = {} // Everything in here means the distance, measured in periods to whatever happened in the past, usually events. - variable.current.distance.toEvent = {} // Distance to Events that already happened. - variable.current.strategy = {} // Everything in here are variables related to the current strategy being executed. - variable.current.position = {} // Everything in here are variables related to the current position being executed. + variable.current = {} // Everything in here means that is happening right now. + variable.current.balance = {} // Balances at the current candle of the Simulation. + variable.current.distance = {} // Everything in here means the distance, measured in periods to whatever happened in the past, usually events. + variable.current.distance.toEvent = {} // Distance to Events that already happened. + variable.current.strategy = {} // Everything in here are variables related to the current strategy being executed. + variable.current.position = {} // Everything in here are variables related to the current position being executed. - variable.current.balance.baseAsset = bot.VALUES_TO_USE.initialBalanceA - variable.current.balance.quotedAsset = bot.VALUES_TO_USE.initialBalanceB - variable.current.distance.toEvent.triggerOn = 0 - variable.current.distance.toEvent.triggerOff = 0 - variable.current.distance.toEvent.takePosition = 0 - variable.current.distance.toEvent.closePosition = 0 + variable.current.balance.baseAsset = bot.VALUES_TO_USE.initialBalanceA + variable.current.balance.quotedAsset = bot.VALUES_TO_USE.initialBalanceB + variable.current.distance.toEvent.triggerOn = 0 + variable.current.distance.toEvent.triggerOff = 0 + variable.current.distance.toEvent.takePosition = 0 + variable.current.distance.toEvent.closePosition = 0 - variable.last = {} // Everything in here means that it already happened. - variable.last.position = {} // Las values of variables at the last position. + variable.last = {} // Everything in here means that it already happened. + variable.last.position = {} // Las values of variables at the last position. - variable.last.position.profitLoss = 0 - variable.last.position.ROI = 0 + variable.last.position.profitLoss = 0 + variable.last.position.ROI = 0 - variable.previous = {} // Everything in here means the the value that was current before a new current value was set. - variable.previous.balance = {} // Balances values previous to the current ones. + variable.previous = {} // Everything in here means the the value that was current before a new current value was set. + variable.previous.balance = {} // Balances values previous to the current ones. - variable.previous.balance.baseAsset = 0 - variable.previous.balance.quotedAsset = 0 + variable.previous.balance.baseAsset = 0 + variable.previous.balance.quotedAsset = 0 - variable.episode.parameters = {} // Parameters give you access to information received by the Simulation as parameters. - variable.episode.parameters.initial = {} // Everything in here means the status at the begining of the episode received as a parameter of the Sumulation. - variable.episode.parameters.minimun = {} // Everything in here means the minimun in the whole episode received as a parameter of the Sumulation. - variable.episode.parameters.maximun = {} // Everything in here means the maximun in the whole episode received as a parameter of the Sumulation. - variable.episode.parameters.initial.balance = {} - variable.episode.parameters.minimun.balance = {} - variable.episode.parameters.maximun.balance = {} + variable.episode.parameters = {} // Parameters give you access to information received by the Simulation as parameters. + variable.episode.parameters.initial = {} // Everything in here means the status at the begining of the episode received as a parameter of the Sumulation. + variable.episode.parameters.minimun = {} // Everything in here means the minimun in the whole episode received as a parameter of the Sumulation. + variable.episode.parameters.maximun = {} // Everything in here means the maximun in the whole episode received as a parameter of the Sumulation. + variable.episode.parameters.initial.balance = {} + variable.episode.parameters.minimun.balance = {} + variable.episode.parameters.maximun.balance = {} - variable.episode.parameters.baseAsset = bot.VALUES_TO_USE.baseAsset - variable.episode.parameters.quotedAsset = bot.VALUES_TO_USE.quotedAsset - variable.episode.parameters.marketBaseAsset = bot.market.baseAsset - variable.episode.parameters.marketQuotedAsset = bot.market.quotedAsset + variable.episode.parameters.baseAsset = bot.VALUES_TO_USE.baseAsset + variable.episode.parameters.quotedAsset = bot.VALUES_TO_USE.quotedAsset + variable.episode.parameters.marketBaseAsset = bot.market.baseAsset + variable.episode.parameters.marketQuotedAsset = bot.market.quotedAsset + variable.episode.parameters.timeFrame = timeFrame // The numeric value of the time frame, in milliseconds + variable.episode.parameters.timeFrameLabel = timeFrameLabel // The alpha-numeric value of the time frame - variable.episode.parameters.initial.balance.baseAsset = bot.VALUES_TO_USE.initialBalanceA - variable.episode.parameters.minimum.balance.baseAsset = bot.VALUES_TO_USE.minimumBalanceA - variable.episode.parameters.maximum.balance.baseAsset = bot.VALUES_TO_USE.maximumBalanceA + variable.episode.parameters.initial.balance.baseAsset = bot.VALUES_TO_USE.initialBalanceA + variable.episode.parameters.minimum.balance.baseAsset = bot.VALUES_TO_USE.minimumBalanceA + variable.episode.parameters.maximum.balance.baseAsset = bot.VALUES_TO_USE.maximumBalanceA - variable.episode.parameters.initial.balance.quotedAsset = bot.VALUES_TO_USE.initialBalanceB - variable.episode.parameters.minimum.balance.quotedAsset = bot.VALUES_TO_USE.minimumBalanceB - variable.episode.parameters.maximum.balance.quotedAsset = bot.VALUES_TO_USE.maximumBalanceB + variable.episode.parameters.initial.balance.quotedAsset = bot.VALUES_TO_USE.initialBalanceB + variable.episode.parameters.minimum.balance.quotedAsset = bot.VALUES_TO_USE.minimumBalanceB + variable.episode.parameters.maximum.balance.quotedAsset = bot.VALUES_TO_USE.maximumBalanceB - variable.episode.count.positions = 0 - variable.episode.count.fails = 0 - variable.episode.count.hits = 0 - variable.episode.count.periods = 0 + variable.episode.count.positions = 0 + variable.episode.count.fails = 0 + variable.episode.count.hits = 0 + variable.episode.count.periods = 0 - variable.episode.stat.profitLoss = 0 - variable.episode.stat.hitRatio = 0 - variable.episode.stat.days = 0 - variable.episode.stat.ROI = 0 - variable.episode.stat.anualizedRateOfReturn = 0 + variable.episode.stat.profitLoss = 0 + variable.episode.stat.hitRatio = 0 + variable.episode.stat.days = 0 + variable.episode.stat.ROI = 0 + variable.episode.stat.anualizedRateOfReturn = 0 - inializeCurrentStrategy() - initializeCurrentPosition() + inializeCurrentStrategy() + initializeCurrentPosition() - variable.announcements = [] - } + variable.announcements = [] + } - function inializeCurrentStrategy () { - variable.current.strategy = { - index: -1, - stage: 'No Stage', - begin: 0, - end: 0, - status: 0, - number: 0, - beginRate: 0, - endRate: 0, - situationName: '' - } - } + function inializeCurrentStrategy() { + variable.current.strategy = { + index: -1, + stage: 'No Stage', + begin: 0, + end: 0, + status: 0, + number: 0, + beginRate: 0, + endRate: 0, + situationName: '' + } + } - function initializeCurrentPosition () { - variable.current.position = { - begin: 0, - end: 0, - rate: 0, - size: 0, - stopLoss: 0, - takeProfit: 0, - status: 0, - profit: 0, - exitType: 0, - beginRate: 0, - endRate: 0, - periods: 0, - situationName: '', - stopLossPhase: -1, - stopLossStage: 'No Stage', - takeProfitPhase: -1, - takeProfitStage: 'No Stage' - } - } + function initializeCurrentPosition() { + variable.current.position = { + begin: 0, + end: 0, + rate: 0, + size: 0, + stopLoss: 0, + takeProfit: 0, + status: 0, + profit: 0, + exitType: 0, + beginRate: 0, + endRate: 0, + periods: 0, + situationName: '', + stopLossPhase: -1, + stopLossStage: 'No Stage', + takeProfitPhase: -1, + takeProfitStage: 'No Stage' + } + } /* Main Array and Maps */ - let propertyName = 'at' + timeFrameLabel.replace('-', '') - let candles = chart[propertyName].candles - let currentChart = chart[propertyName] + let propertyName = 'at' + variable.episode.parameters.timeFrameLabel.replace('-', '') + let candles = chart[propertyName].candles + let currentChart = chart[propertyName] /* Last Candle */ - let lastCandle = candles[candles.length - 1] + let lastCandle = candles[candles.length - 1] /* Main Simulation Loop: We go thourgh all the candles at this time period. */ - let currentCandleIndex + let currentCandleIndex /* For Loop Level heartbeat */ - let loopingDay - let previousLoopingDay + let loopingDay + let previousLoopingDay - initializeLoop() + initializeLoop() - function initializeLoop () { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> initializeLoop -> Entering function.') } + function initializeLoop() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> initializeLoop -> Entering function.') } /* Estimate Initial Candle */ - let firstEnd = candles[0].end - let targetEnd = bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf() - let diff = targetEnd - firstEnd - let amount = diff / timeFrame + let firstEnd = candles[0].end + let targetEnd = bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf() + let diff = targetEnd - firstEnd + let amount = diff / variable.episode.parameters.timeFrame - currentCandleIndex = Math.trunc(amount) - if (currentCandleIndex < 0) { currentCandleIndex = 0 } - if (currentCandleIndex > candles.length - 1) { + currentCandleIndex = Math.trunc(amount) + if (currentCandleIndex < 0) { currentCandleIndex = 0 } + if (currentCandleIndex > candles.length - 1) { /* This will happen when the bot.VALUES_TO_USE.timeRange.initialDatetime is beyond the last candle available, meaning that the dataSet needs to be updated with more up-to-date data. */ - currentCandleIndex = candles.length - 1 - } + currentCandleIndex = candles.length - 1 + } - loop() - } + loop() + } - function loop () { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Entering function.') } - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Processing candle # ' + currentCandleIndex) } + function loop() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Entering function.') } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Processing candle # ' + currentCandleIndex) } /* We are going to take snapshots of the values of indicators at key moments of the sumulation. */ - let snapshotKeys = new Map() - snapshotLoopHeaders = [] - snapshotDataRecord = [] - saveAsLastTriggerOnSnapshot = false - saveAsLastTakePositionSnapshot = false - addToSnapshots = false + let snapshotKeys = new Map() + snapshotLoopHeaders = [] + snapshotDataRecord = [] + saveAsLastTriggerOnSnapshot = false + saveAsLastTakePositionSnapshot = false + addToSnapshots = false - let announcementsToBeMade = [] - let candle = candles[currentCandleIndex] + let announcementsToBeMade = [] + let candle = candles[currentCandleIndex] /* Not processing while out of user-defined time range */ - - if (candle.end < bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Skipping Candle before the bot.VALUES_TO_USE.timeRange.initialDatetime.') } - controlLoop() - return - } - if (candle.begin > bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Skipping Candle after the bot.VALUES_TO_USE.timeRange.finalDatetime.') } - afterLoop() - return - } + if (candle.end < bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Skipping Candle before the bot.VALUES_TO_USE.timeRange.initialDatetime.') } + controlLoop() + return + } + if (candle.begin > bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Skipping Candle after the bot.VALUES_TO_USE.timeRange.finalDatetime.') } + afterLoop() + return + } /* Here we update at the chart data structure the objects for each product representing where we are currently standing at the simulation loop */ - if (processingDailyFiles) { - for (let j = 0; j < global.dailyFilePeriods.length; j++) { - let mapKey = dailyFilePeriods[j][1] - let propertyName = 'at' + mapKey.replace('-', '') - let thisChart = chart[propertyName] + if (processingDailyFiles) { + for (let j = 0; j < global.dailyFilePeriods.length; j++) { + let mapKey = dailyFilePeriods[j][1] + let propertyName = 'at' + mapKey.replace('-', '') + let thisChart = chart[propertyName] - for (let k = 0; k < dataDependencies.length; k++) { - let dataDependencyNode = dataDependencies[k] - if (dataDependencyNode.referenceParent.code.codeName !== 'Multi-Period-Daily') { continue } - let singularVariableName = dataDependencyNode.referenceParent.parentNode.code.singularVariableName - let pluralVariableName = dataDependencyNode.referenceParent.parentNode.code.pluralVariableName - let currentElement = getElement(thisChart[pluralVariableName], candle, 'Daily' + '-' + mapKey + '-' + pluralVariableName) - thisChart[singularVariableName] = currentElement - } - } - } + for (let k = 0; k < dataDependencies.length; k++) { + let dataDependencyNode = dataDependencies[k] + if (dataDependencyNode.referenceParent.code.codeName !== 'Multi-Period-Daily') { continue } + let singularVariableName = dataDependencyNode.referenceParent.parentNode.code.singularVariableName + let pluralVariableName = dataDependencyNode.referenceParent.parentNode.code.pluralVariableName + let currentElement = getElement(thisChart[pluralVariableName], candle, 'Daily' + '-' + mapKey + '-' + pluralVariableName) + thisChart[singularVariableName] = currentElement + } + } + } /* Finding the Current Element on Market Files */ - for (let j = 0; j < global.marketFilesPeriods.length; j++) { - let mapKey = marketFilesPeriods[j][1] - let propertyName = 'at' + mapKey.replace('-', '') - let thisChart = chart[propertyName] + for (let j = 0; j < global.marketFilesPeriods.length; j++) { + let mapKey = marketFilesPeriods[j][1] + let propertyName = 'at' + mapKey.replace('-', '') + let thisChart = chart[propertyName] - for (let k = 0; k < dataDependencies.length; k++) { - let dataDependencyNode = dataDependencies[k] - if (dataDependencyNode.referenceParent.code.codeName !== 'Multi-Period-Market') { continue } - let singularVariableName = dataDependencyNode.referenceParent.parentNode.code.singularVariableName - let pluralVariableName = dataDependencyNode.referenceParent.parentNode.code.pluralVariableName - let currentElement = getElement(thisChart[pluralVariableName], candle, 'Market' + '-' + mapKey + '-' + pluralVariableName) - thisChart[singularVariableName] = currentElement - } - } + for (let k = 0; k < dataDependencies.length; k++) { + let dataDependencyNode = dataDependencies[k] + if (dataDependencyNode.referenceParent.code.codeName !== 'Multi-Period-Market') { continue } + let singularVariableName = dataDependencyNode.referenceParent.parentNode.code.singularVariableName + let pluralVariableName = dataDependencyNode.referenceParent.parentNode.code.pluralVariableName + let currentElement = getElement(thisChart[pluralVariableName], candle, 'Market' + '-' + mapKey + '-' + pluralVariableName) + thisChart[singularVariableName] = currentElement + } + } /* Finding the Current Element on Single Files */ - function isItInside (elementWithTimestamp, elementWithBeginEnd) { - if (elementWithTimestamp.timestamp >= elementWithBeginEnd.begin && elementWithTimestamp.timestamp <= elementWithBeginEnd.end) { - return true - } else { - return false - } - } + function isItInside(elementWithTimestamp, elementWithBeginEnd) { + if (elementWithTimestamp.timestamp >= elementWithBeginEnd.begin && elementWithTimestamp.timestamp <= elementWithBeginEnd.end) { + return true + } else { + return false + } + } - let propertyName = 'atAnyTimeFrame' - let thisChart = chart[propertyName] + let propertyName = 'atAnyvariable.episode.parameters.timeFrame' + let thisChart = chart[propertyName] - for (let k = 0; k < dataDependencies.length; k++) { - let dataDependencyNode = dataDependencies[k] - if (dataDependencyNode.referenceParent.code.codeName !== 'Single-File') { continue } - let singularVariableName = dataDependencyNode.referenceParent.parentNode.code.singularVariableName - let pluralVariableName = dataDependencyNode.referenceParent.parentNode.code.pluralVariableName - let elementArray = thisChart[pluralVariableName] - let currentElement - if (elementArray !== undefined) { - currentElement = elementArray[elementArray.length - 1] - } - thisChart[singularVariableName] = currentElement - } + for (let k = 0; k < dataDependencies.length; k++) { + let dataDependencyNode = dataDependencies[k] + if (dataDependencyNode.referenceParent.code.codeName !== 'Single-File') { continue } + let singularVariableName = dataDependencyNode.referenceParent.parentNode.code.singularVariableName + let pluralVariableName = dataDependencyNode.referenceParent.parentNode.code.pluralVariableName + let elementArray = thisChart[pluralVariableName] + let currentElement + if (elementArray !== undefined) { + currentElement = elementArray[elementArray.length - 1] + } + thisChart[singularVariableName] = currentElement + } /* While we are processing the previous day. */ - let positionedAtYesterday = false - if (currentDay) { - positionedAtYesterday = (candle.end < currentDay.valueOf()) - } + let positionedAtYesterday = false + if (currentDay) { + positionedAtYesterday = (candle.end < currentDay.valueOf()) + } - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Candle Begin @ ' + (new Date(candle.begin)).toLocaleString()) } - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Candle End @ ' + (new Date(candle.end)).toLocaleString()) } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Candle Begin @ ' + (new Date(candle.begin)).toLocaleString()) } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Candle End @ ' + (new Date(candle.end)).toLocaleString()) } - let ticker = { - bid: candle.close, - ask: candle.close, - last: candle.close - } + let ticker = { + bid: candle.close, + ask: candle.close, + last: candle.close + } /* We will produce a simulation level heartbeat in order to inform the user this is running. */ + loopingDay = new Date(Math.trunc(candle.begin / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) + if (loopingDay.valueOf() !== previousLoopingDay) { + let processingDate = loopingDay.getUTCFullYear() + '-' + utilities.pad(loopingDay.getUTCMonth() + 1, 2) + '-' + utilities.pad(loopingDay.getUTCDate(), 2) - loopingDay = new Date(Math.trunc(candle.begin / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) - if (loopingDay.valueOf() !== previousLoopingDay) { - let processingDate = loopingDay.getUTCFullYear() + '-' + utilities.pad(loopingDay.getUTCMonth() + 1, 2) + '-' + utilities.pad(loopingDay.getUTCDate(), 2) - - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Simulation ' + bot.sessionKey + ' Loop # ' + currentCandleIndex + ' @ ' + processingDate) } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Simulation ' + bot.sessionKey + ' Loop # ' + currentCandleIndex + ' @ ' + processingDate) } /* Telling the world we are alive and doing well */ - let fromDate = new Date(bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) - let lastDate = new Date(bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf()) + let fromDate = new Date(bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) + let lastDate = new Date(bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf()) - let currentDateString = loopingDay.getUTCFullYear() + '-' + utilities.pad(loopingDay.getUTCMonth() + 1, 2) + '-' + utilities.pad(loopingDay.getUTCDate(), 2) - let currentDate = new Date(loopingDay) - let percentage = global.getPercentage(fromDate, currentDate, lastDate) - bot.processHeartBeat(currentDateString, percentage) + let currentDateString = loopingDay.getUTCFullYear() + '-' + utilities.pad(loopingDay.getUTCMonth() + 1, 2) + '-' + utilities.pad(loopingDay.getUTCDate(), 2) + let currentDate = new Date(loopingDay) + let percentage = global.getPercentage(fromDate, currentDate, lastDate) + bot.processHeartBeat(currentDateString, percentage) - if (global.areEqualDates(currentDate, new Date()) === false) { - logger.newInternalLoop(bot.codeName, bot.process, currentDate, percentage) - } - } - previousLoopingDay = loopingDay.valueOf() + if (global.areEqualDates(currentDate, new Date()) === false) { + logger.newInternalLoop(bot.codeName, bot.process, currentDate, percentage) + } + } + previousLoopingDay = loopingDay.valueOf() - variable.episode.count.periods++ - variable.episode.stat.days = variable.episode.count.periods * timeFrame / ONE_DAY_IN_MILISECONDS + variable.episode.count.periods++ + variable.episode.stat.days = variable.episode.count.periods * variable.episode.parameters.timeFrame / ONE_DAY_IN_MILISECONDS - if (processingDailyFiles) { + if (processingDailyFiles) { /* We skip the candle at the head of the market because currentCandleIndex has not closed yet. */ - let candlesPerDay = ONE_DAY_IN_MILISECONDS / timeFrame - if (currentCandleIndex === candles.length - 1) { - if ((candles.length < candlesPerDay) || (candles.length > candlesPerDay && candles.length < candlesPerDay * 2)) { + let candlesPerDay = ONE_DAY_IN_MILISECONDS / variable.episode.parameters.timeFrame + if (currentCandleIndex === candles.length - 1) { + if ((candles.length < candlesPerDay) || (candles.length > candlesPerDay && candles.length < candlesPerDay * 2)) { /* We are at the head of the market, thus we skip the last candle because it has not close yet. */ - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Skipping Candle because it is the last one and has not been closed yet.') } - controlLoop() - return + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Skipping Candle because it is the last one and has not been closed yet.') } + controlLoop() + return /* Note here that in the last candle of the first day or the second day it will use an incomplete candle and partially calculated indicators. if we skip these two variable.episode.count.periods, then there will be a hole in the file since the last period will be missing. */ - } - } - } else { // We are processing Market Files - if (currentCandleIndex === candles.length - 1) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Skipping Candle because it is the last one and has not been closed yet.') } - controlLoop() - return - } - } + } + } + } else { // We are processing Market Files + if (currentCandleIndex === candles.length - 1) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Skipping Candle because it is the last one and has not been closed yet.') } + controlLoop() + return + } + } - let conditions = new Map() // Here we store the conditions values that will be use in the simulator for decision making. - let formulas = new Map() - let conditionsArrayRecord = [] // These are the records that will be saved in a file for the plotter to consume. - let conditionsArrayValues = [] // Here we store the conditions values that will be written on file for the plotter. - let formulasErrors = [] // Here we store the errors produced by all phase formulas. - let formulasValues = [] // Here we store the values produced by all phase formulas. + let conditions = new Map() // Here we store the conditions values that will be use in the simulator for decision making. + let formulas = new Map() + let conditionsArrayRecord = [] // These are the records that will be saved in a file for the plotter to consume. + let conditionsArrayValues = [] // Here we store the conditions values that will be written on file for the plotter. + let formulasErrors = [] // Here we store the errors produced by all phase formulas. + let formulasValues = [] // Here we store the values produced by all phase formulas. /* We define and evaluate all conditions to be used later during the simulation loop. */ - conditionsArrayRecord.push(candle.begin) - conditionsArrayRecord.push(candle.end) + conditionsArrayRecord.push(candle.begin) + conditionsArrayRecord.push(candle.end) - for (let j = 0; j < tradingSystem.strategies.length; j++) { - let strategy = tradingSystem.strategies[j] + for (let j = 0; j < tradingSystem.strategies.length; j++) { + let strategy = tradingSystem.strategies[j] - let positionSize = 0 - let positionRate = 0 + let positionSize = 0 + let positionRate = 0 /* Continue with the rest of the formulas and conditions */ - let triggerStage = strategy.triggerStage + let triggerStage = strategy.triggerStage - if (triggerStage !== undefined) { - if (triggerStage.triggerOn !== undefined) { - for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { - let situation = triggerStage.triggerOn.situations[k] + if (triggerStage !== undefined) { + if (triggerStage.triggerOn !== undefined) { + for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { + let situation = triggerStage.triggerOn.situations[k] - for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m - if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode, chart) - } - } - } - } + if (condition.javascriptCode !== undefined) { + newCondition(key, condition.javascriptCode, chart) + } + } + } + } - if (triggerStage.triggerOff !== undefined) { - for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { - let situation = triggerStage.triggerOff.situations[k] + if (triggerStage.triggerOff !== undefined) { + for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { + let situation = triggerStage.triggerOff.situations[k] - for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m - if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode, chart) - } - } - } - } + if (condition.javascriptCode !== undefined) { + newCondition(key, condition.javascriptCode, chart) + } + } + } + } - if (triggerStage.takePosition !== undefined) { - for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { - let situation = triggerStage.takePosition.situations[k] + if (triggerStage.takePosition !== undefined) { + for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { + let situation = triggerStage.takePosition.situations[k] - for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m - if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode, chart) - } - } - } - } - } + if (condition.javascriptCode !== undefined) { + newCondition(key, condition.javascriptCode, chart) + } + } + } + } + } - let openStage = strategy.openStage + let openStage = strategy.openStage - if (openStage !== undefined) { + if (openStage !== undefined) { /* Default Values */ - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - positionSize = variable.current.balance.baseAsset - positionRate = candle.close - } else { - positionSize = variable.current.balance.quotedAsset - positionRate = candle.close - } - - let initialDefinition = openStage.initialDefinition - - if (initialDefinition !== undefined) { - if (variable.current.position.size !== 0) { - positionSize = variable.current.position.size - } else { - if (initialDefinition.positionSize !== undefined) { - if (initialDefinition.positionSize.formula !== undefined) { - try { - let code = initialDefinition.positionSize.formula.code - positionSize = eval(code) - addCodeToSnapshot(code) - } catch (err) { - initialDefinition.positionSize.formula.error = err.message - } - if (isNaN(positionSize)) { if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { positionSize = variable.current.balance.baseAsset - } else { + positionRate = candle.close + } else { positionSize = variable.current.balance.quotedAsset - } - } else { - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - if (positionSize > variable.current.balance.baseAsset) { positionSize = variable.current.balance.baseAsset } - } else { - if (positionSize > variable.current.balance.quotedAsset) { positionSize = variable.current.balance.quotedAsset } - } - } - } - } - } - - if (variable.current.position.rate !== 0) { - positionRate = variable.current.position.rate - } else { - if (initialDefinition.positionRate !== undefined) { - if (initialDefinition.positionRate.formula !== undefined) { - try { - let code = initialDefinition.positionRate.formula.code - positionRate = eval(initialDefinition.positionRate.formula.code) - addCodeToSnapshot(code) - } catch (err) { - initialDefinition.positionRate.formula.error = err.message - } - if (isNaN(positionRate)) { - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { positionRate = candle.close - } else { - positionRate = candle.close - } - } - } - } - } + } - if (initialDefinition.stopLoss !== undefined) { - for (let p = 0; p < initialDefinition.stopLoss.phases.length; p++) { - let phase = initialDefinition.stopLoss.phases[p] + let initialDefinition = openStage.initialDefinition + + if (initialDefinition !== undefined) { + if (variable.current.position.size !== 0) { + positionSize = variable.current.position.size + } else { + if (initialDefinition.positionSize !== undefined) { + if (initialDefinition.positionSize.formula !== undefined) { + try { + let code = initialDefinition.positionSize.formula.code + positionSize = eval(code) + addCodeToSnapshot(code) + } catch (err) { + initialDefinition.positionSize.formula.error = err.message + } + if (isNaN(positionSize)) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + positionSize = variable.current.balance.baseAsset + } else { + positionSize = variable.current.balance.quotedAsset + } + } else { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + if (positionSize > variable.current.balance.baseAsset) { positionSize = variable.current.balance.baseAsset } + } else { + if (positionSize > variable.current.balance.quotedAsset) { positionSize = variable.current.balance.quotedAsset } + } + } + } + } + } + + if (variable.current.position.rate !== 0) { + positionRate = variable.current.position.rate + } else { + if (initialDefinition.positionRate !== undefined) { + if (initialDefinition.positionRate.formula !== undefined) { + try { + let code = initialDefinition.positionRate.formula.code + positionRate = eval(initialDefinition.positionRate.formula.code) + addCodeToSnapshot(code) + } catch (err) { + initialDefinition.positionRate.formula.error = err.message + } + if (isNaN(positionRate)) { + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + positionRate = candle.close + } else { + positionRate = candle.close + } + } + } + } + } + + if (initialDefinition.stopLoss !== undefined) { + for (let p = 0; p < initialDefinition.stopLoss.phases.length; p++) { + let phase = initialDefinition.stopLoss.phases[p] /* Evaluate Formula */ - let formulaValue - let formulaError = '' + let formulaValue + let formulaError = '' - if (phase.formula !== undefined) { - try { - let code = phase.formula.code - formulaValue = eval(code) - addCodeToSnapshot(code) - if (formulaValue === Infinity) { - formulaError = 'Formula evaluates to Infinity.' - formulaValue = MAX_STOP_LOSS_VALUE - if (stopLossStage === 'Open Stage') { - formulaError = 'WARNING: Formula evaluates to Infinity.' - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> initialDefinition.stopLoss -> MAX_STOP_LOSS_VALUE -> formulaError = ' + formulaError) } - } - } - } catch (err) { - if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { + if (phase.formula !== undefined) { + try { + let code = phase.formula.code + formulaValue = eval(code) + addCodeToSnapshot(code) + if (formulaValue === Infinity) { + formulaError = 'Formula evaluates to Infinity.' + formulaValue = MAX_STOP_LOSS_VALUE + if (variable.current.position.stopLossStage === 'Open Stage') { + formulaError = 'WARNING: Formula evaluates to Infinity.' + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> initialDefinition.stopLoss -> MAX_STOP_LOSS_VALUE -> formulaError = ' + formulaError) } + } + } + } catch (err) { + if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { /* We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. */ - } else { - formulaError = err.message - } - } - if (isNaN(formulaValue)) { formulaValue = 0 } - if (formulaValue < MIN_STOP_LOSS_VALUE) { - formulaValue = MIN_STOP_LOSS_VALUE - if (stopLossStage === 'Open Stage') { - formulaError = 'WARNING: Formula is evaluating below the MIN_STOP_LOSS_VALUE.' - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> initialDefinition.stopLoss -> MIN_STOP_LOSS_VALUE -> formulaError = ' + formulaError) } - } - } + } else { + formulaError = err.message + } + } + if (isNaN(formulaValue)) { formulaValue = 0 } + if (formulaValue < MIN_STOP_LOSS_VALUE) { + formulaValue = MIN_STOP_LOSS_VALUE + if (variable.current.position.stopLossStage === 'Open Stage') { + formulaError = 'WARNING: Formula is evaluating below the MIN_STOP_LOSS_VALUE.' + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> initialDefinition.stopLoss -> MIN_STOP_LOSS_VALUE -> formulaError = ' + formulaError) } + } + } - formulasErrors.push('"' + formulaError + '"') - formulasValues.push(formulaValue) - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p - formulas.set(key, formulaValue) - } + formulasErrors.push('"' + formulaError + '"') + formulasValues.push(formulaValue) + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + formulas.set(key, formulaValue) + } /* next phase event */ - let nextPhaseEvent = phase.nextPhaseEvent - if (nextPhaseEvent !== undefined) { + let nextPhaseEvent = phase.nextPhaseEvent + if (nextPhaseEvent !== undefined) { - for (let k = 0; k < nextPhaseEvent.situations.length; k++) { + for (let k = 0; k < nextPhaseEvent.situations.length; k++) { - let situation = nextPhaseEvent.situations[k] + let situation = nextPhaseEvent.situations[k] - for (let m = 0; m < situation.conditions.length; m++) { + for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m + let condition = situation.conditions[m] + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m - if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode, chart) - } - } - } - } + if (condition.javascriptCode !== undefined) { + newCondition(key, condition.javascriptCode, chart) + } + } + } + } /* move to phase events */ - for (let n = 0; n < phase.moveToPhaseEvents.length; n++) { - let moveToPhaseEvent = phase.moveToPhaseEvents[n] - if (moveToPhaseEvent !== undefined) { + for (let n = 0; n < phase.moveToPhaseEvents.length; n++) { + let moveToPhaseEvent = phase.moveToPhaseEvents[n] + if (moveToPhaseEvent !== undefined) { - for (let k = 0; k < moveToPhaseEvent.situations.length; k++) { + for (let k = 0; k < moveToPhaseEvent.situations.length; k++) { - let situation = moveToPhaseEvent.situations[k] + let situation = moveToPhaseEvent.situations[k] - for (let m = 0; m < situation.conditions.length; m++) { + for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + '-' + n + '-' + k + '-' + m + let condition = situation.conditions[m] + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + '-' + n + '-' + k + '-' + m - if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode, chart) - } - } - } - } - } - } - } + if (condition.javascriptCode !== undefined) { + newCondition(key, condition.javascriptCode, chart) + } + } + } + } + } + } + } - if (initialDefinition.takeProfit !== undefined) { - for (let p = 0; p < initialDefinition.takeProfit.phases.length; p++) { - let phase = initialDefinition.takeProfit.phases[p] + if (initialDefinition.takeProfit !== undefined) { + for (let p = 0; p < initialDefinition.takeProfit.phases.length; p++) { + let phase = initialDefinition.takeProfit.phases[p] /* Evaluate Formula */ - let formulaValue - let formulaError = '' + let formulaValue + let formulaError = '' - if (phase.formula !== undefined) { - try { - let code = phase.formula.code - formulaValue = eval(code) - addCodeToSnapshot(code) - if (formulaValue === Infinity) { - formulaValue = MAX_TAKE_PROFIT_VALUE - if (takeProfitStage === 'Open Stage') { - formulaError = 'WARNING: Formula evaluates to Infinity.' - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> initialDefinition.takeProfit -> MAX_TAKE_PROFIT_VALUE -> formulaError = ' + formulaError) } - } - } - } catch (err) { - if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { + if (phase.formula !== undefined) { + try { + let code = phase.formula.code + formulaValue = eval(code) + addCodeToSnapshot(code) + if (formulaValue === Infinity) { + formulaValue = MAX_TAKE_PROFIT_VALUE + if (takeProfitStage === 'Open Stage') { + formulaError = 'WARNING: Formula evaluates to Infinity.' + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> initialDefinition.takeProfit -> MAX_TAKE_PROFIT_VALUE -> formulaError = ' + formulaError) } + } + } + } catch (err) { + if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { /* We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. */ - } else { - formulaError = err.message - } - } - if (isNaN(formulaValue)) { formulaValue = 0 } - if (formulaValue < MIN_TAKE_PROFIT_VALUE) { - formulaValue = MIN_TAKE_PROFIT_VALUE - if (takeProfitStage === 'Open Stage') { - formulaError = 'WARNING: Formula is evaluating below the MIN_TAKE_PROFIT_VALUE.' - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> initialDefinition.takeProfit -> MIN_TAKE_PROFIT_VALUE -> formulaError = ' + formulaError) } - } - } + } else { + formulaError = err.message + } + } + if (isNaN(formulaValue)) { formulaValue = 0 } + if (formulaValue < MIN_TAKE_PROFIT_VALUE) { + formulaValue = MIN_TAKE_PROFIT_VALUE + if (takeProfitStage === 'Open Stage') { + formulaError = 'WARNING: Formula is evaluating below the MIN_TAKE_PROFIT_VALUE.' + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> initialDefinition.takeProfit -> MIN_TAKE_PROFIT_VALUE -> formulaError = ' + formulaError) } + } + } - formulasErrors.push('"' + formulaError + '"') - formulasValues.push(formulaValue) - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p - formulas.set(key, formulaValue) - } + formulasErrors.push('"' + formulaError + '"') + formulasValues.push(formulaValue) + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + formulas.set(key, formulaValue) + } /* next phase event */ - let nextPhaseEvent = phase.nextPhaseEvent - if (nextPhaseEvent !== undefined) { + let nextPhaseEvent = phase.nextPhaseEvent + if (nextPhaseEvent !== undefined) { - for (let k = 0; k < nextPhaseEvent.situations.length; k++) { + for (let k = 0; k < nextPhaseEvent.situations.length; k++) { - let situation = nextPhaseEvent.situations[k] + let situation = nextPhaseEvent.situations[k] - for (let m = 0; m < situation.conditions.length; m++) { + for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m + let condition = situation.conditions[m] + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m - if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode, chart) - } - } - } - } + if (condition.javascriptCode !== undefined) { + newCondition(key, condition.javascriptCode, chart) + } + } + } + } /* move to phase events */ - for (let n = 0; n < phase.moveToPhaseEvents.length; n++) { - let moveToPhaseEvent = phase.moveToPhaseEvents[n] - if (moveToPhaseEvent !== undefined) { + for (let n = 0; n < phase.moveToPhaseEvents.length; n++) { + let moveToPhaseEvent = phase.moveToPhaseEvents[n] + if (moveToPhaseEvent !== undefined) { - for (let k = 0; k < moveToPhaseEvent.situations.length; k++) { + for (let k = 0; k < moveToPhaseEvent.situations.length; k++) { - let situation = moveToPhaseEvent.situations[k] + let situation = moveToPhaseEvent.situations[k] - for (let m = 0; m < situation.conditions.length; m++) { + for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + '-' + n + '-' + k + '-' + m + let condition = situation.conditions[m] + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + '-' + n + '-' + k + '-' + m - if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode, chart) - } - } - } - } - } - } - } - } + if (condition.javascriptCode !== undefined) { + newCondition(key, condition.javascriptCode, chart) + } + } + } + } + } + } + } + } - strategy.positionSize = positionSize - strategy.positionRate = positionRate - } + strategy.positionSize = positionSize + strategy.positionRate = positionRate + } - let manageStage = strategy.manageStage + let manageStage = strategy.manageStage - if (manageStage !== undefined) { - if (manageStage.stopLoss !== undefined) { - for (let p = 0; p < manageStage.stopLoss.phases.length; p++) { - let phase = manageStage.stopLoss.phases[p] + if (manageStage !== undefined) { + if (manageStage.stopLoss !== undefined) { + for (let p = 0; p < manageStage.stopLoss.phases.length; p++) { + let phase = manageStage.stopLoss.phases[p] /* Evaluate Formula */ - let formulaValue - let formulaError = '' + let formulaValue + let formulaError = '' - if (phase.formula !== undefined) { - try { - let code = phase.formula.code - formulaValue = eval(code) - addCodeToSnapshot(code) - if (formulaValue === Infinity) { - formulaError = '' - formulaValue = MAX_STOP_LOSS_VALUE - if (stopLossStage === 'Manage Stage') { - formulaError = 'WARNING: Formula evaluates to Infinity.' - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> manageStage.stopLoss -> MAX_STOP_LOSS_VALUE -> formulaError = ' + formulaError) } - } - } - } catch (err) { - if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { + if (phase.formula !== undefined) { + try { + let code = phase.formula.code + formulaValue = eval(code) + addCodeToSnapshot(code) + if (formulaValue === Infinity) { + formulaError = '' + formulaValue = MAX_STOP_LOSS_VALUE + if (variable.current.position.stopLossStage === 'Manage Stage') { + formulaError = 'WARNING: Formula evaluates to Infinity.' + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> manageStage.stopLoss -> MAX_STOP_LOSS_VALUE -> formulaError = ' + formulaError) } + } + } + } catch (err) { + if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { /* We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. */ - } else { - formulaError = err.message - } - } - if (isNaN(formulaValue)) { formulaValue = 0 } - if (formulaValue < MIN_STOP_LOSS_VALUE) { - formulaValue = MIN_STOP_LOSS_VALUE - if (stopLossStage === 'Manage Stage') { - formulaError = 'WARNING: Formula is evaluating below the MIN_STOP_LOSS_VALUE.' - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> manageStage.stopLoss -> MIN_STOP_LOSS_VALUE -> formulaError = ' + formulaError) } - } - } + } else { + formulaError = err.message + } + } + if (isNaN(formulaValue)) { formulaValue = 0 } + if (formulaValue < MIN_STOP_LOSS_VALUE) { + formulaValue = MIN_STOP_LOSS_VALUE + if (variable.current.position.stopLossStage === 'Manage Stage') { + formulaError = 'WARNING: Formula is evaluating below the MIN_STOP_LOSS_VALUE.' + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> manageStage.stopLoss -> MIN_STOP_LOSS_VALUE -> formulaError = ' + formulaError) } + } + } - formulasErrors.push('"' + formulaError + '"') - formulasValues.push(formulaValue) - let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p - formulas.set(key, formulaValue) - } + formulasErrors.push('"' + formulaError + '"') + formulasValues.push(formulaValue) + let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + formulas.set(key, formulaValue) + } /* next phase event */ - let nextPhaseEvent = phase.nextPhaseEvent - if (nextPhaseEvent !== undefined) { - for (let k = 0; k < nextPhaseEvent.situations.length; k++) { + let nextPhaseEvent = phase.nextPhaseEvent + if (nextPhaseEvent !== undefined) { + for (let k = 0; k < nextPhaseEvent.situations.length; k++) { - let situation = nextPhaseEvent.situations[k] + let situation = nextPhaseEvent.situations[k] - for (let m = 0; m < situation.conditions.length; m++) { + for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m + let condition = situation.conditions[m] + let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m - if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode, chart) - } - } - } - } + if (condition.javascriptCode !== undefined) { + newCondition(key, condition.javascriptCode, chart) + } + } + } + } /* move to phase events */ - for (let n = 0; n < phase.moveToPhaseEvents.length; n++) { - let moveToPhaseEvent = phase.moveToPhaseEvents[n] - if (moveToPhaseEvent !== undefined) { + for (let n = 0; n < phase.moveToPhaseEvents.length; n++) { + let moveToPhaseEvent = phase.moveToPhaseEvents[n] + if (moveToPhaseEvent !== undefined) { - for (let k = 0; k < moveToPhaseEvent.situations.length; k++) { + for (let k = 0; k < moveToPhaseEvent.situations.length; k++) { - let situation = moveToPhaseEvent.situations[k] + let situation = moveToPhaseEvent.situations[k] - for (let m = 0; m < situation.conditions.length; m++) { + for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + '-' + n + '-' + k + '-' + m + let condition = situation.conditions[m] + let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + '-' + n + '-' + k + '-' + m - if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode, chart) - } - } - } - } - } - } - } + if (condition.javascriptCode !== undefined) { + newCondition(key, condition.javascriptCode, chart) + } + } + } + } + } + } + } - if (manageStage.takeProfit !== undefined) { - for (let p = 0; p < manageStage.takeProfit.phases.length; p++) { - let phase = manageStage.takeProfit.phases[p] + if (manageStage.takeProfit !== undefined) { + for (let p = 0; p < manageStage.takeProfit.phases.length; p++) { + let phase = manageStage.takeProfit.phases[p] /* Evaluate Formula */ - let formulaValue - let formulaError = '' + let formulaValue + let formulaError = '' - if (phase.formula !== undefined) { - try { - let code = phase.formula.code - formulaValue = eval(code) - addCodeToSnapshot(code) - if (formulaValue === Infinity) { - formulaError = 'Formula evaluates to Infinity.' - formulaValue = MAX_TAKE_PROFIT_VALUE - if (takeProfitStage === 'Manage Stage') { - formulaError = 'WARNING: Formula evaluates to Infinity.' - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> manageStage.takeProfit -> MAX_TAKE_PROFIT_VALUE -> formulaError = ' + formulaError) } - } - } - } catch (err) { - if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { + if (phase.formula !== undefined) { + try { + let code = phase.formula.code + formulaValue = eval(code) + addCodeToSnapshot(code) + if (formulaValue === Infinity) { + formulaError = 'Formula evaluates to Infinity.' + formulaValue = MAX_TAKE_PROFIT_VALUE + if (takeProfitStage === 'Manage Stage') { + formulaError = 'WARNING: Formula evaluates to Infinity.' + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> manageStage.takeProfit -> MAX_TAKE_PROFIT_VALUE -> formulaError = ' + formulaError) } + } + } + } catch (err) { + if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { /* We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. */ - } else { - formulaError = err.message - } - } - if (isNaN(formulaValue)) { formulaValue = 0 } - if (formulaValue < MIN_TAKE_PROFIT_VALUE) { - formulaValue = MIN_TAKE_PROFIT_VALUE - if (takeProfitStage === 'Manage Stage') { - formulaError = 'WARNING: Formula is evaluating below the MIN_TAKE_PROFIT_VALUE.' - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> manageStage.takeProfit -> MIN_TAKE_PROFIT_VALUE -> formulaError = ' + formulaError) } - } - } + } else { + formulaError = err.message + } + } + if (isNaN(formulaValue)) { formulaValue = 0 } + if (formulaValue < MIN_TAKE_PROFIT_VALUE) { + formulaValue = MIN_TAKE_PROFIT_VALUE + if (takeProfitStage === 'Manage Stage') { + formulaError = 'WARNING: Formula is evaluating below the MIN_TAKE_PROFIT_VALUE.' + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> manageStage.takeProfit -> MIN_TAKE_PROFIT_VALUE -> formulaError = ' + formulaError) } + } + } - formulasErrors.push('"' + formulaError + '"') - formulasValues.push(formulaValue) - let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p - formulas.set(key, formulaValue) - } + formulasErrors.push('"' + formulaError + '"') + formulasValues.push(formulaValue) + let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + formulas.set(key, formulaValue) + } /* next phase event */ - let nextPhaseEvent = phase.nextPhaseEvent - if (nextPhaseEvent !== undefined) { - for (let k = 0; k < nextPhaseEvent.situations.length; k++) { + let nextPhaseEvent = phase.nextPhaseEvent + if (nextPhaseEvent !== undefined) { + for (let k = 0; k < nextPhaseEvent.situations.length; k++) { - let situation = nextPhaseEvent.situations[k] + let situation = nextPhaseEvent.situations[k] - for (let m = 0; m < situation.conditions.length; m++) { + for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m + let condition = situation.conditions[m] + let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m - if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode, chart) - } - } - } - } + if (condition.javascriptCode !== undefined) { + newCondition(key, condition.javascriptCode, chart) + } + } + } + } /* move to phase events */ - for (let n = 0; n < phase.moveToPhaseEvents.length; n++) { - let moveToPhaseEvent = phase.moveToPhaseEvents[n] - if (moveToPhaseEvent !== undefined) { + for (let n = 0; n < phase.moveToPhaseEvents.length; n++) { + let moveToPhaseEvent = phase.moveToPhaseEvents[n] + if (moveToPhaseEvent !== undefined) { - for (let k = 0; k < moveToPhaseEvent.situations.length; k++) { + for (let k = 0; k < moveToPhaseEvent.situations.length; k++) { - let situation = moveToPhaseEvent.situations[k] + let situation = moveToPhaseEvent.situations[k] - for (let m = 0; m < situation.conditions.length; m++) { + for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + '-' + n + '-' + k + '-' + m + let condition = situation.conditions[m] + let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + '-' + n + '-' + k + '-' + m - if (condition.javascriptCode !== undefined) { - newCondition(key, condition.javascriptCode, chart) - } - } - } - } - } - } - } - } + if (condition.javascriptCode !== undefined) { + newCondition(key, condition.javascriptCode, chart) + } + } + } + } + } + } + } + } - function newCondition (key, node, chart) { - let condition - let value + function newCondition(key, node, chart) { + let condition + let value - try { - let code = node.code - value = eval(code) - addCodeToSnapshot(code) - } catch (err) { + try { + let code = node.code + value = eval(code) + addCodeToSnapshot(code) + } catch (err) { /* One possible error is that the conditions references a .previous that is undefined. For this reason and others, we will simply set the value to false. */ - value = false + value = false - if (node.code.indexOf('previous') > -1 && err.message.indexOf('of undefined') > -1 || + if (node.code.indexOf('previous') > -1 && err.message.indexOf('of undefined') > -1 || node.code.indexOf('chart') > -1 && err.message.indexOf('of undefined') > -1 ) { /* We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. */ - } else { - node.error = err.message + ' @ ' + (new Date(candle.begin)).toLocaleString() - } - } + } else { + node.error = err.message + ' @ ' + (new Date(candle.begin)).toLocaleString() + } + } - condition = { - key: key, - value: value - } + condition = { + key: key, + value: value + } - conditions.set(condition.key, condition) + conditions.set(condition.key, condition) - if (condition.value) { - conditionsArrayValues.push(1) - } else { - conditionsArrayValues.push(0) - } - } - } + if (condition.value) { + conditionsArrayValues.push(1) + } else { + conditionsArrayValues.push(0) + } + } + } /* Trigger On Conditions */ - if ( + if ( variable.current.strategy.stage === 'No Stage' && variable.current.strategy.index === -1 ) { - let minimumBalance - let maximumBalance - let balance + let minimumBalance + let maximumBalance + let balance - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - balance = variable.current.balance.baseAsset - minimumBalance = variable.episode.parameters.minimum.balance.baseAsset - maximumBalance = variable.episode.parameters.maximum.balance.baseAsset - } else { - balance = variable.current.balance.quotedAsset - minimumBalance = variable.episode.parameters.minimum.balance.quotedAsset - maximumBalance = variable.episode.parameters.maximum.balance.quotedAsset - } + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + balance = variable.current.balance.baseAsset + minimumBalance = variable.episode.parameters.minimum.balance.baseAsset + maximumBalance = variable.episode.parameters.maximum.balance.baseAsset + } else { + balance = variable.current.balance.quotedAsset + minimumBalance = variable.episode.parameters.minimum.balance.quotedAsset + maximumBalance = variable.episode.parameters.maximum.balance.quotedAsset + } - let stopRunningDate = new Date(candle.begin) - if (balance <= minimumBalance) { - tradingSystem.error = 'Min Balance @ ' + stopRunningDate.toLocaleString() - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> ' + tradingSystem.error) } - afterLoop() - return - } + let stopRunningDate = new Date(candle.begin) + if (balance <= minimumBalance) { + tradingSystem.error = 'Min Balance @ ' + stopRunningDate.toLocaleString() + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> ' + tradingSystem.error) } + afterLoop() + return + } - if (balance >= maximumBalance) { - tradingSystem.error = 'Max Balance @ ' + stopRunningDate.toLocaleString() - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> ' + tradingSystem.error) } - afterLoop() - return - } + if (balance >= maximumBalance) { + tradingSystem.error = 'Max Balance @ ' + stopRunningDate.toLocaleString() + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> ' + tradingSystem.error) } + afterLoop() + return + } /* Here we need to pick a strategy, or if there is not suitable strategy for the current market conditions, we pass until the next period. - + To pick a new strategy we will evaluate what we call the trigger on. Once we enter into one strategy, we will ignore market conditions for others. However there is also a strategy trigger off which can be hit before taking a position. If hit, we would be outside a strategy again and looking for the condition to enter all over again. - + */ - for (let j = 0; j < tradingSystem.strategies.length; j++) { - if ( + for (let j = 0; j < tradingSystem.strategies.length; j++) { + if ( strategyStage !== 'No Stage' || currentStrategyIndex !== -1 ) { continue } - let strategy = tradingSystem.strategies[j] + let strategy = tradingSystem.strategies[j] - let triggerStage = strategy.triggerStage + let triggerStage = strategy.triggerStage - if (triggerStage !== undefined) { - if (triggerStage.triggerOn !== undefined) { - for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { - let situation = triggerStage.triggerOn.situations[k] - let passed - if (situation.conditions.length > 0) { - passed = true - } + if (triggerStage !== undefined) { + if (triggerStage.triggerOn !== undefined) { + for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { + let situation = triggerStage.triggerOn.situations[k] + let passed + if (situation.conditions.length > 0) { + passed = true + } - for (let m = 0; m < situation.conditions.length; m++) { + for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m + let condition = situation.conditions[m] + let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m - let value = false - if (conditions.get(key) !== undefined) { - value = conditions.get(key).value - } + let value = false + if (conditions.get(key) !== undefined) { + value = conditions.get(key).value + } - if (value === false) { passed = false } - } + if (value === false) { passed = false } + } - if (passed) { + if (passed) { - variable.current.strategy.stage = 'Trigger Stage' - checkAnnouncements(triggerStage) + variable.current.strategy.stage = 'Trigger Stage' + checkAnnouncements(triggerStage) - variable.current.strategy.index = j - variable.current.strategy.begin = candle.begin - variable.current.strategy.beginRate = candle.min - variable.current.strategy.endRate = candle.min // In case the strategy does not get exited - variable.current.strategy.situationName = situation.name + variable.current.strategy.index = j + variable.current.strategy.begin = candle.begin + variable.current.strategy.beginRate = candle.min + variable.current.strategy.endRate = candle.min // In case the strategy does not get exited + variable.current.strategy.situationName = situation.name - variable.current.distance.toEvent.triggerOn = 1 + variable.current.distance.toEvent.triggerOn = 1 - checkAnnouncements(triggerStage.triggerOn) - saveAsLastTriggerOnSnapshot = true + checkAnnouncements(triggerStage.triggerOn) + saveAsLastTriggerOnSnapshot = true - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Switching to Trigger Stage because conditions at Trigger On Event were met.') } - break - } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Switching to Trigger Stage because conditions at Trigger On Event were met.') } + break + } + } + } + } + } } - } - } - } - } /* Trigger Off Condition */ - if (variable.current.strategy.stage === 'Trigger Stage') { - let strategy = tradingSystem.strategies[strategyIndex] + if (variable.current.strategy.stage === 'Trigger Stage') { + let strategy = tradingSystem.strategies[strategyIndex] - let triggerStage = strategy.triggerStage + let triggerStage = strategy.triggerStage - if (triggerStage !== undefined) { - if (triggerStage.triggerOff !== undefined) { - for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { - let situation = triggerStage.triggerOff.situations[k] - let passed - if (situation.conditions.length > 0) { - passed = true + if (triggerStage !== undefined) { + if (triggerStage.triggerOff !== undefined) { + for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { + let situation = triggerStage.triggerOff.situations[k] + let passed + if (situation.conditions.length > 0) { + passed = true + } + + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + let key = variable.current.strategy.index + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m + + let value = false + if (conditions.get(key) !== undefined) { + value = conditions.get(key).value + } + + if (value === false) { passed = false } + } + + if (passed) { + variable.current.strategy.number = variable.current.strategy.index + variable.current.strategy.end = candle.end + variable.current.strategy.endRate = candle.min + variable.current.strategy.status = 1 // This means the strategy is closed, i.e. that has a begin and end. + variable.current.strategy.stage = 'No Stage' + variable.current.strategy.index = -1 + + variable.current.distance.toEvent.triggerOff = 1 + + checkAnnouncements(triggerStage.triggerOff) + + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Switching to No Stage because conditions at the Trigger Off Event were met.') } + break + } + } + } + } } - for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = variable.current.strategy.index + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m - - let value = false - if (conditions.get(key) !== undefined) { - value = conditions.get(key).value - } - - if (value === false) { passed = false } - } - - if (passed) { - variable.current.strategy.number = variable.current.strategy.index - variable.current.strategy.end = candle.end - variable.current.strategy.endRate = candle.min - variable.current.strategy.status = 1 // This means the strategy is closed, i.e. that has a begin and end. - variable.current.strategy.stage = 'No Stage' - variable.current.strategy.index = -1 - - variable.current.distance.toEvent.triggerOff = 1 - - checkAnnouncements(triggerStage.triggerOff) - - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Switching to No Stage because conditions at the Trigger Off Event were met.') } - break - } - } - } - } - } - /* Take Position Condition */ - if (variable.current.strategy.stage === 'Trigger Stage') { - let strategy = tradingSystem.strategies[strategyIndex] + if (variable.current.strategy.stage === 'Trigger Stage') { + let strategy = tradingSystem.strategies[strategyIndex] - let triggerStage = strategy.triggerStage + let triggerStage = strategy.triggerStage - if (triggerStage !== undefined) { - if (triggerStage.takePosition !== undefined) { - for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { - let situation = triggerStage.takePosition.situations[k] - let passed - if (situation.conditions.length > 0) { - passed = true + if (triggerStage !== undefined) { + if (triggerStage.takePosition !== undefined) { + for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { + let situation = triggerStage.takePosition.situations[k] + let passed + if (situation.conditions.length > 0) { + passed = true + } + + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + let key = variable.current.strategy.index + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m + + let value = false + if (conditions.get(key) !== undefined) { + value = conditions.get(key).value + } + + if (value === false) { passed = false } + } + + if (passed) { + variable.current.strategy.stage = 'Open Stage' + checkAnnouncements(strategy.openStage) + + variable.current.position.stopLossStage = 'Open Stage' + variable.current.position.takeProfitStage = 'Open Stage' + variable.current.position.stopLossPhase = 0 + variable.current.position.takeProfitPhase = 0 + + takePositionNow = true + variable.current.position.situationName = situation.name + + checkAnnouncements(triggerStage.takePosition) + saveAsLastTakePositionSnapshot = true + + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Conditions at the Take Position Event were met.') } + break + } + } + } + } } - for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = variable.current.strategy.index + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m - - let value = false - if (conditions.get(key) !== undefined) { - value = conditions.get(key).value - } - - if (value === false) { passed = false } - } - - if (passed) { - variable.current.strategy.stage = 'Open Stage' - checkAnnouncements(strategy.openStage) - - variable.current.position.stopLossStage = 'Open Stage' - variable.current.position.takeProfitStage = 'Open Stage' - variable.current.position.stopLossPhase = 0 - variable.current.position.takeProfitPhase = 0 - - takePositionNow = true - variable.current.position.situationName = situation.name - - checkAnnouncements(triggerStage.takePosition) - saveAsLastTakePositionSnapshot = true - - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Conditions at the Take Position Event were met.') } - break - } - } - } - } - } - /* Stop Loss Management */ - if ( + if ( (variable.current.strategy.stage === 'Open Stage' || variable.current.strategy.stage === 'Manage Stage') && takePositionNow !== true ) { - checkStopPhases() - calculateStopLoss() - } + checkStopPhases() + calculateStopLoss() + } - function checkStopPhases () { - let strategy = tradingSystem.strategies[strategyIndex] + function checkStopPhases() { + let strategy = tradingSystem.strategies[strategyIndex] - let openStage = strategy.openStage - let manageStage = strategy.manageStage - let parentNode - let j = variable.current.strategy.index - let stageKey - let initialDefinitionKey = '' - let p + let openStage = strategy.openStage + let manageStage = strategy.manageStage + let parentNode + let j = variable.current.strategy.index + let stageKey + let initialDefinitionKey = '' + let p - if (stopLossStage === 'Open Stage' && openStage !== undefined) { - if (openStage.initialDefinition !== undefined) { - if (openStage.initialDefinition.stopLoss !== undefined) { - parentNode = openStage.initialDefinition - initialDefinitionKey = '-' + 'initialDefinition' - stageKey = 'openStage' - p = variable.current.position.stopLossPhase - } - } - } + if (variable.current.position.stopLossStage === 'Open Stage' && openStage !== undefined) { + if (openStage.initialDefinition !== undefined) { + if (openStage.initialDefinition.stopLoss !== undefined) { + parentNode = openStage.initialDefinition + initialDefinitionKey = '-' + 'initialDefinition' + stageKey = 'openStage' + p = variable.current.position.stopLossPhase + } + } + } - if (stopLossStage === 'Manage Stage' && manageStage !== undefined) { - if (manageStage.stopLoss !== undefined) { - parentNode = manageStage - stageKey = 'manageStage' - p = variable.current.position.stopLossPhase - 1 - } - } + if (variable.current.position.stopLossStage === 'Manage Stage' && manageStage !== undefined) { + if (manageStage.stopLoss !== undefined) { + parentNode = manageStage + stageKey = 'manageStage' + p = variable.current.position.stopLossPhase - 1 + } + } - if (parentNode !== undefined) { - let phase = parentNode.stopLoss.phases[p] + if (parentNode !== undefined) { + let phase = parentNode.stopLoss.phases[p] /* Check the next Phase Event. */ - let nextPhaseEvent = phase.nextPhaseEvent - if (nextPhaseEvent !== undefined) { - for (let k = 0; k < nextPhaseEvent.situations.length; k++) { - let situation = nextPhaseEvent.situations[k] - let passed - if (situation.conditions.length > 0) { - passed = true - } + let nextPhaseEvent = phase.nextPhaseEvent + if (nextPhaseEvent !== undefined) { + for (let k = 0; k < nextPhaseEvent.situations.length; k++) { + let situation = nextPhaseEvent.situations[k] + let passed + if (situation.conditions.length > 0) { + passed = true + } - for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m - let value = false - if (conditions.get(key) !== undefined) { - value = conditions.get(key).value - } + let value = false + if (conditions.get(key) !== undefined) { + value = conditions.get(key).value + } - if (value === false) { passed = false } - } + if (value === false) { passed = false } + } - if (passed) { - variable.current.position.stopLossPhase++ - variable.current.position.stopLossStage = 'Manage Stage' - if (takeProfitPhase > 0) { - variable.current.strategy.stage = 'Manage Stage' - checkAnnouncements(manageStage, 'Take Profit') - } + if (passed) { + variable.current.position.stopLossPhase++ + variable.current.position.stopLossStage = 'Manage Stage' + if (takeProfitPhase > 0) { + variable.current.strategy.stage = 'Manage Stage' + checkAnnouncements(manageStage, 'Take Profit') + } - checkAnnouncements(nextPhaseEvent) - return - } - } - } + checkAnnouncements(nextPhaseEvent) + return + } + } + } /* Check the Move to Phase Events. */ - for (let n = 0; n < phase.moveToPhaseEvents.length; n++) { - let moveToPhaseEvent = phase.moveToPhaseEvents[n] - if (moveToPhaseEvent !== undefined) { - for (let k = 0; k < moveToPhaseEvent.situations.length; k++) { - let situation = moveToPhaseEvent.situations[k] - let passed - if (situation.conditions.length > 0) { - passed = true - } + for (let n = 0; n < phase.moveToPhaseEvents.length; n++) { + let moveToPhaseEvent = phase.moveToPhaseEvents[n] + if (moveToPhaseEvent !== undefined) { + for (let k = 0; k < moveToPhaseEvent.situations.length; k++) { + let situation = moveToPhaseEvent.situations[k] + let passed + if (situation.conditions.length > 0) { + passed = true + } - for (let m = 0; m < situation.conditions.length; m++) { + for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'stopLoss' + '-' + p + '-' + n + '-' + k + '-' + m + let condition = situation.conditions[m] + let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'stopLoss' + '-' + p + '-' + n + '-' + k + '-' + m - let value = false - if (conditions.get(key) !== undefined) { - value = conditions.get(key).value - } + let value = false + if (conditions.get(key) !== undefined) { + value = conditions.get(key).value + } - if (value === false) { passed = false } - } + if (value === false) { passed = false } + } - if (passed) { + if (passed) { - let moveToPhase = moveToPhaseEvent.referenceParent - if (moveToPhase !== undefined) { - for (let q = 0; q < parentNode.stopLoss.phases.length; q++) { - if (parentNode.stopLoss.phases[q].id === moveToPhase.id) { - variable.current.position.stopLossPhase = q + 1 - } - } - } else { - moveToPhaseEvent.error = 'This Node needs to reference a Phase.' - continue - } + let moveToPhase = moveToPhaseEvent.referenceParent + if (moveToPhase !== undefined) { + for (let q = 0; q < parentNode.stopLoss.phases.length; q++) { + if (parentNode.stopLoss.phases[q].id === moveToPhase.id) { + variable.current.position.stopLossPhase = q + 1 + } + } + } else { + moveToPhaseEvent.error = 'This Node needs to reference a Phase.' + continue + } - variable.current.position.stopLossStage = 'Manage Stage' - if (takeProfitPhase > 0) { - variable.current.strategy.stage = 'Manage Stage' - checkAnnouncements(manageStage, 'Take Profit') - } + variable.current.position.stopLossStage = 'Manage Stage' + if (takeProfitPhase > 0) { + variable.current.strategy.stage = 'Manage Stage' + checkAnnouncements(manageStage, 'Take Profit') + } - checkAnnouncements(moveToPhaseEvent) - return - } + checkAnnouncements(moveToPhaseEvent) + return + } + } + } + } + } } - } - } - } - } - function calculateStopLoss () { - let strategy = tradingSystem.strategies[strategyIndex] - let openStage = strategy.openStage - let manageStage = strategy.manageStage - let phase - let key + function calculateStopLoss() { + let strategy = tradingSystem.strategies[strategyIndex] + let openStage = strategy.openStage + let manageStage = strategy.manageStage + let phase + let key - if (stopLossStage === 'Open Stage' && openStage !== undefined) { - if (openStage.initialDefinition !== undefined) { - if (openStage.initialDefinition.stopLoss !== undefined) { - phase = openStage.initialDefinition.stopLoss.phases[stopLossPhase] - key = variable.current.strategy.index + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + (stopLossPhase) - } - } - } + if (variable.current.position.stopLossStage === 'Open Stage' && openStage !== undefined) { + if (openStage.initialDefinition !== undefined) { + if (openStage.initialDefinition.stopLoss !== undefined) { + phase = openStage.initialDefinition.stopLoss.phases[stopLossPhase] + key = variable.current.strategy.index + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + (stopLossPhase) + } + } + } - if (stopLossStage === 'Manage Stage' && manageStage !== undefined) { - if (manageStage.stopLoss !== undefined) { - phase = manageStage.stopLoss.phases[stopLossPhase - 1] - key = variable.current.strategy.index + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + (stopLossPhase - 1) - } - } + if (variable.current.position.stopLossStage === 'Manage Stage' && manageStage !== undefined) { + if (manageStage.stopLoss !== undefined) { + phase = manageStage.stopLoss.phases[stopLossPhase - 1] + key = variable.current.strategy.index + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + (stopLossPhase - 1) + } + } - if (phase !== undefined) { - if (phase.formula !== undefined) { - let previousValue = variable.current.position.stopLoss + if (phase !== undefined) { + if (phase.formula !== undefined) { + let previousValue = variable.current.position.stopLoss - variable.current.position.stopLoss = formulas.get(key) + variable.current.position.stopLoss = formulas.get(key) - if (stopLoss !== previousValue) { - checkAnnouncements(phase, variable.current.position.stopLoss) - } - } - } - } + if (stopLoss !== previousValue) { + checkAnnouncements(phase, variable.current.position.stopLoss) + } + } + } + } /* Take Profit Management */ - if ( + if ( (variable.current.strategy.stage === 'Open Stage' || variable.current.strategy.stage === 'Manage Stage') && takePositionNow !== true ) { - checkTakeProfitPhases() - calculateTakeProfit() - } + checkTakeProfitPhases() + calculateTakeProfit() + } - function checkTakeProfitPhases () { - let strategy = tradingSystem.strategies[strategyIndex] + function checkTakeProfitPhases() { + let strategy = tradingSystem.strategies[strategyIndex] - let openStage = strategy.openStage - let manageStage = strategy.manageStage - let parentNode - let j = variable.current.strategy.index - let stageKey - let initialDefinitionKey = '' - let p + let openStage = strategy.openStage + let manageStage = strategy.manageStage + let parentNode + let j = variable.current.strategy.index + let stageKey + let initialDefinitionKey = '' + let p - if (takeProfitStage === 'Open Stage' && openStage !== undefined) { - if (openStage.initialDefinition !== undefined) { - if (openStage.initialDefinition.takeProfit !== undefined) { - parentNode = openStage.initialDefinition - initialDefinitionKey = '-' + 'initialDefinition' - stageKey = 'openStage' - p = variable.current.position.takeProfitPhase - } - } - } + if (takeProfitStage === 'Open Stage' && openStage !== undefined) { + if (openStage.initialDefinition !== undefined) { + if (openStage.initialDefinition.takeProfit !== undefined) { + parentNode = openStage.initialDefinition + initialDefinitionKey = '-' + 'initialDefinition' + stageKey = 'openStage' + p = variable.current.position.takeProfitPhase + } + } + } - if (takeProfitStage === 'Manage Stage' && manageStage !== undefined) { - if (manageStage.takeProfit !== undefined) { - parentNode = manageStage - stageKey = 'manageStage' - p = variable.current.position.takeProfitPhase - 1 - } - } + if (takeProfitStage === 'Manage Stage' && manageStage !== undefined) { + if (manageStage.takeProfit !== undefined) { + parentNode = manageStage + stageKey = 'manageStage' + p = variable.current.position.takeProfitPhase - 1 + } + } - if (parentNode !== undefined) { - let phase = parentNode.takeProfit.phases[p] - if (phase === undefined) { return } // trying to jump to a phase that does not exists. + if (parentNode !== undefined) { + let phase = parentNode.takeProfit.phases[p] + if (phase === undefined) { return } // trying to jump to a phase that does not exists. /* Check the next Phase Event. */ - let nextPhaseEvent = phase.nextPhaseEvent - if (nextPhaseEvent !== undefined) { - for (let k = 0; k < nextPhaseEvent.situations.length; k++) { - let situation = nextPhaseEvent.situations[k] - let passed - if (situation.conditions.length > 0) { - passed = true - } + let nextPhaseEvent = phase.nextPhaseEvent + if (nextPhaseEvent !== undefined) { + for (let k = 0; k < nextPhaseEvent.situations.length; k++) { + let situation = nextPhaseEvent.situations[k] + let passed + if (situation.conditions.length > 0) { + passed = true + } - for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m - let value = false - if (conditions.get(key) !== undefined) { - value = conditions.get(key).value - } + let value = false + if (conditions.get(key) !== undefined) { + value = conditions.get(key).value + } - if (value === false) { passed = false } - } + if (value === false) { passed = false } + } - if (passed) { - variable.current.position.takeProfitPhase++ - variable.current.position.takeProfitStage = 'Manage Stage' - if (stopLossPhase > 0) { - variable.current.strategy.stage = 'Manage Stage' - checkAnnouncements(manageStage, 'Stop') - } + if (passed) { + variable.current.position.takeProfitPhase++ + variable.current.position.takeProfitStage = 'Manage Stage' + if (stopLossPhase > 0) { + variable.current.strategy.stage = 'Manage Stage' + checkAnnouncements(manageStage, 'Stop') + } - checkAnnouncements(nextPhaseEvent) - return - } - } - } + checkAnnouncements(nextPhaseEvent) + return + } + } + } /* Check the Move to Phase Events. */ - for (let n = 0; n < phase.moveToPhaseEvents.length; n++) { - let moveToPhaseEvent = phase.moveToPhaseEvents[n] - if (moveToPhaseEvent !== undefined) { - for (let k = 0; k < moveToPhaseEvent.situations.length; k++) { - let situation = moveToPhaseEvent.situations[k] - let passed - if (situation.conditions.length > 0) { - passed = true - } + for (let n = 0; n < phase.moveToPhaseEvents.length; n++) { + let moveToPhaseEvent = phase.moveToPhaseEvents[n] + if (moveToPhaseEvent !== undefined) { + for (let k = 0; k < moveToPhaseEvent.situations.length; k++) { + let situation = moveToPhaseEvent.situations[k] + let passed + if (situation.conditions.length > 0) { + passed = true + } - for (let m = 0; m < situation.conditions.length; m++) { + for (let m = 0; m < situation.conditions.length; m++) { - let condition = situation.conditions[m] - let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'takeProfit' + '-' + p + '-' + n + '-' + k + '-' + m + let condition = situation.conditions[m] + let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'takeProfit' + '-' + p + '-' + n + '-' + k + '-' + m - let value = false - if (conditions.get(key) !== undefined) { - value = conditions.get(key).value - } + let value = false + if (conditions.get(key) !== undefined) { + value = conditions.get(key).value + } - if (value === false) { passed = false } - } + if (value === false) { passed = false } + } - if (passed) { + if (passed) { - let moveToPhase = moveToPhaseEvent.referenceParent - if (moveToPhase !== undefined) { - for (let q = 0; q < parentNode.takeProfit.phases.length; q++) { - if (parentNode.takeProfit.phases[q].id === moveToPhase.id) { - variable.current.position.takeProfitPhase = q + 1 - } - } - } else { - moveToPhaseEvent.error = 'This Node needs to reference a Phase.' - continue - } + let moveToPhase = moveToPhaseEvent.referenceParent + if (moveToPhase !== undefined) { + for (let q = 0; q < parentNode.takeProfit.phases.length; q++) { + if (parentNode.takeProfit.phases[q].id === moveToPhase.id) { + variable.current.position.takeProfitPhase = q + 1 + } + } + } else { + moveToPhaseEvent.error = 'This Node needs to reference a Phase.' + continue + } - variable.current.position.takeProfitStage = 'Manage Stage' - if (stopLossPhase > 0) { - variable.current.strategy.stage = 'Manage Stage' - checkAnnouncements(manageStage, 'Stop') - } + variable.current.position.takeProfitStage = 'Manage Stage' + if (stopLossPhase > 0) { + variable.current.strategy.stage = 'Manage Stage' + checkAnnouncements(manageStage, 'Stop') + } - checkAnnouncements(moveToPhaseEvent) - return - } + checkAnnouncements(moveToPhaseEvent) + return + } + } + } + } + } } - } - } - } - } - function calculateTakeProfit () { - let strategy = tradingSystem.strategies[strategyIndex] - let openStage = strategy.openStage - let manageStage = strategy.manageStage - let phase - let key + function calculateTakeProfit() { + let strategy = tradingSystem.strategies[strategyIndex] + let openStage = strategy.openStage + let manageStage = strategy.manageStage + let phase + let key - if (takeProfitStage === 'Open Stage' && openStage !== undefined) { - if (openStage.initialDefinition !== undefined) { - if (openStage.initialDefinition.takeProfit !== undefined) { - phase = openStage.initialDefinition.takeProfit.phases[takeProfitPhase] - key = variable.current.strategy.index + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + (takeProfitPhase) - } - } - } + if (takeProfitStage === 'Open Stage' && openStage !== undefined) { + if (openStage.initialDefinition !== undefined) { + if (openStage.initialDefinition.takeProfit !== undefined) { + phase = openStage.initialDefinition.takeProfit.phases[takeProfitPhase] + key = variable.current.strategy.index + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + (takeProfitPhase) + } + } + } - if (takeProfitStage === 'Manage Stage' && manageStage !== undefined) { - if (manageStage.takeProfit !== undefined) { - phase = manageStage.takeProfit.phases[takeProfitPhase - 1] - key = variable.current.strategy.index + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 1) - } - } + if (takeProfitStage === 'Manage Stage' && manageStage !== undefined) { + if (manageStage.takeProfit !== undefined) { + phase = manageStage.takeProfit.phases[takeProfitPhase - 1] + key = variable.current.strategy.index + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 1) + } + } - if (phase !== undefined) { - if (phase.formula !== undefined) { - let previousValue = variable.current.position.stopLoss + if (phase !== undefined) { + if (phase.formula !== undefined) { + let previousValue = variable.current.position.stopLoss - variable.current.position.takeProfit = formulas.get(key) + variable.current.position.takeProfit = formulas.get(key) - if (takeProfit !== previousValue) { - checkAnnouncements(phase, variable.current.position.takeProfit) - } - } - } - } + if (takeProfit !== previousValue) { + checkAnnouncements(phase, variable.current.position.takeProfit) + } + } + } + } /* Keeping Position Counters Up-to-date */ - if ( + if ( (variable.current.strategy.stage === 'Open Stage' || variable.current.strategy.stage === 'Manage Stage') ) { - if (takePositionNow === true) { - variable.current.position.periods = 0 - } + if (takePositionNow === true) { + variable.current.position.periods = 0 + } - variable.current.position.periods++ - variable.positionDays = variable.current.position.periods * timeFrame / ONE_DAY_IN_MILISECONDS - } else { - variable.current.position.periods = 0 - variable.positionDays = 0 - } + variable.current.position.periods++ + variable.positionDays = variable.current.position.periods * variable.episode.parameters.timeFrame / ONE_DAY_IN_MILISECONDS + } else { + variable.current.position.periods = 0 + variable.positionDays = 0 + } /* Keeping Distance Counters Up-to-date */ - if ( + if ( variable.current.distance.toEvent.triggerOn > 0 // with this we avoind counting before the first event happens. ) { - variable.current.distance.toEvent.triggerOn++ - } + variable.current.distance.toEvent.triggerOn++ + } - if ( + if ( variable.current.distance.toEvent.triggerOff > 0 // with this we avoind counting before the first event happens. ) { - variable.current.distance.toEvent.triggerOff++ - } + variable.current.distance.toEvent.triggerOff++ + } - if ( + if ( variable.current.distance.toEvent.takePosition > 0 // with this we avoind counting before the first event happens. ) { - variable.current.distance.toEvent.takePosition++ - } + variable.current.distance.toEvent.takePosition++ + } - if ( + if ( variable.current.distance.toEvent.closePosition > 0 // with this we avoind counting before the first event happens. ) { - variable.current.distance.toEvent.closePosition++ - } + variable.current.distance.toEvent.closePosition++ + } /* Checking if Stop or Take Profit were hit */ - if ( + if ( (variable.current.strategy.stage === 'Open Stage' || variable.current.strategy.stage === 'Manage Stage') && takePositionNow !== true ) { - let strategy = tradingSystem.strategies[strategyIndex] + let strategy = tradingSystem.strategies[strategyIndex] /* Checking what happened since the last execution. We need to know if the Stop Loss or our Take Profit were hit. */ /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - if ((variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset && candle.max >= variable.current.position.stopLoss) || (variable.episode.parameters.baseAsset !== variable.episode.parameters.marketBaseAsset && candle.min <= variable.current.position.stopLoss)) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Stop Loss was hit.') } + if ((variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset && candle.max >= variable.current.position.stopLoss) || (variable.episode.parameters.baseAsset !== variable.episode.parameters.marketBaseAsset && candle.min <= variable.current.position.stopLoss)) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Stop Loss was hit.') } /* Hit Point Validation - + This prevents misscalculations when a formula places the stop loss in this case way beyond the market price. If we take the stop loss value at those situation would be a huge distortion of facts. */ - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - if (stopLoss < candle.min) { - variable.current.position.stopLoss = candle.min - } - } else { - if (stopLoss > candle.max) { - variable.current.position.stopLoss = candle.max - } - } + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + if (stopLoss < candle.min) { + variable.current.position.stopLoss = candle.min + } + } else { + if (stopLoss > candle.max) { + variable.current.position.stopLoss = candle.max + } + } - let slippedStopLoss = variable.current.position.stopLoss + let slippedStopLoss = variable.current.position.stopLoss /* Apply the Slippage */ - let slippageAmount = slippedStopLoss * bot.VALUES_TO_USE.slippage.stopLoss / 100 + let slippageAmount = slippedStopLoss * bot.VALUES_TO_USE.slippage.stopLoss / 100 - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - slippedStopLoss = slippedStopLoss + slippageAmount - } else { - slippedStopLoss = slippedStopLoss - slippageAmount - } + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + slippedStopLoss = slippedStopLoss + slippageAmount + } else { + slippedStopLoss = slippedStopLoss - slippageAmount + } - closeRate = slippedStopLoss + closeRate = slippedStopLoss - variable.current.strategy.stage = 'Close Stage' - checkAnnouncements(strategy.closeStage, 'Stop') + variable.current.strategy.stage = 'Close Stage' + checkAnnouncements(strategy.closeStage, 'Stop') - variable.current.position.stopLossStage = 'No Stage' - variable.current.position.takeProfitStage = 'No Stage' - variable.current.position.end = candle.end - variable.current.position.status = 1 - variable.current.position.exitType = 1 - variable.current.position.endRate = closeRate + variable.current.position.stopLossStage = 'No Stage' + variable.current.position.takeProfitStage = 'No Stage' + variable.current.position.end = candle.end + variable.current.position.status = 1 + variable.current.position.exitType = 1 + variable.current.position.endRate = closeRate - closePositionNow = true - } + closePositionNow = true + } /* Take Profit condition: Here we verify if the Take Profit was hit or not. */ - if ((variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset && candle.min <= variable.current.position.takeProfit) || (variable.episode.parameters.baseAsset !== variable.episode.parameters.marketBaseAsset && candle.max >= variable.current.position.takeProfit)) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Take Profit was hit.') } + if ((variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset && candle.min <= variable.current.position.takeProfit) || (variable.episode.parameters.baseAsset !== variable.episode.parameters.marketBaseAsset && candle.max >= variable.current.position.takeProfit)) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Take Profit was hit.') } /* Hit Point Validation: - + This prevents misscalculations when a formula places the take profit in this case way beyond the market price. If we take the stop loss value at those situation would be a huge distortion of facts. */ - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - if (takeProfit > candle.max) { - variable.current.position.takeProfit = candle.max - } - } else { - if (takeProfit < candle.min) { - variable.current.position.takeProfit = candle.min - } - } + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + if (takeProfit > candle.max) { + variable.current.position.takeProfit = candle.max + } + } else { + if (takeProfit < candle.min) { + variable.current.position.takeProfit = candle.min + } + } - let slippedTakeProfit = variable.current.position.takeProfit + let slippedTakeProfit = variable.current.position.takeProfit /* Apply the Slippage */ - let slippageAmount = slippedTakeProfit * bot.VALUES_TO_USE.slippage.takeProfit / 100 + let slippageAmount = slippedTakeProfit * bot.VALUES_TO_USE.slippage.takeProfit / 100 - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - slippedTakeProfit = slippedTakeProfit + slippageAmount - } else { - slippedTakeProfit = slippedTakeProfit - slippageAmount - } + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + slippedTakeProfit = slippedTakeProfit + slippageAmount + } else { + slippedTakeProfit = slippedTakeProfit - slippageAmount + } - closeRate = slippedTakeProfit + closeRate = slippedTakeProfit - variable.current.strategy.stage = 'Close Stage' - checkAnnouncements(strategy.closeStage, 'Take Profit') + variable.current.strategy.stage = 'Close Stage' + checkAnnouncements(strategy.closeStage, 'Take Profit') - variable.current.position.stopLossStage = 'No Stage' - variable.current.position.takeProfitStage = 'No Stage' + variable.current.position.stopLossStage = 'No Stage' + variable.current.position.takeProfitStage = 'No Stage' - variable.current.position.end = candle.end - variable.current.position.status = 1 - variable.current.position.exitType = 2 - variable.current.position.endRate = closeRate + variable.current.position.end = candle.end + variable.current.position.status = 1 + variable.current.position.exitType = 2 + variable.current.position.endRate = closeRate - closePositionNow = true - addToSnapshots = true - } - } + closePositionNow = true + addToSnapshots = true + } + } /* Taking a Position */ - if ( + if ( takePositionNow === true ) { - takePositionNow = false - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionNow -> Entering code block.') } + takePositionNow = false + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionNow -> Entering code block.') } /* Inicializing this counter */ - variable.current.distance.toEvent.takePosition = 1 + variable.current.distance.toEvent.takePosition = 1 /* Position size and rate */ - let strategy = tradingSystem.strategies[strategyIndex] + let strategy = tradingSystem.strategies[strategyIndex] - variable.current.position.size = strategy.positionSize - variable.current.position.rate = strategy.positionRate + variable.current.position.size = strategy.positionSize + variable.current.position.rate = strategy.positionRate /* We take what was calculated at the formula and apply the slippage. */ - let slippageAmount = variable.current.position.rate * bot.VALUES_TO_USE.slippage.positionRate / 100 + let slippageAmount = variable.current.position.rate * bot.VALUES_TO_USE.slippage.positionRate / 100 - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - variable.current.position.rate = variable.current.position.rate - slippageAmount - } else { - variable.current.position.rate = variable.current.position.rate + slippageAmount - } + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + variable.current.position.rate = variable.current.position.rate - slippageAmount + } else { + variable.current.position.rate = variable.current.position.rate + slippageAmount + } /* Update the trade record information. */ - variable.current.position.begin = candle.begin - variable.current.position.beginRate = variable.current.position.rate + variable.current.position.begin = candle.begin + variable.current.position.beginRate = variable.current.position.rate /* Check if we need to execute. */ - if (currentCandleIndex > candles.length - 10) { /* Only at the last candles makes sense to check if we are in live mode or not. */ + if (currentCandleIndex > candles.length - 10) { /* Only at the last candles makes sense to check if we are in live mode or not. */ /* Check that we are in LIVE MODE */ - if (bot.startMode === 'Live') { + if (bot.startMode === 'Live') { /* We see if we need to put the actual order at the exchange. */ - if (variable.executionContext !== undefined) { - switch (variable.executionContext.status) { - case 'Without a Position': { // We need to put the order because It was not put yet. - if (strategy.openStage !== undefined) { - if (strategy.openStage.openExecution !== undefined) { - putOpeningOrder() - return - } - } - break - } - case 'Position Closed': { // Waiting for a confirmation that the position was closed. - if (strategy.openStage !== undefined) { - if (strategy.openStage.openExecution !== undefined) { - putOpeningOrder() - return - } - } - break - } - case 'Taking Position': { // Waiting for a confirmation that the position was taken. - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionNow -> Exiting code block because status is Taking Position.') } - break - } - case 'In a Position': { // This should mean that we already put the order at the exchange. - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionNow -> Exiting code block because status is In a Position.') } - break - } - } - } else { // The context does not exist so it means we are not in a position. - if (strategy.openStage !== undefined) { - if (strategy.openStage.openExecution !== undefined) { - putOpeningOrder() + if (variable.executionContext !== undefined) { + switch (variable.executionContext.status) { + case 'Without a Position': { // We need to put the order because It was not put yet. + if (strategy.openStage !== undefined) { + if (strategy.openStage.openExecution !== undefined) { + putOpeningOrder() + return + } + } + break + } + case 'Position Closed': { // Waiting for a confirmation that the position was closed. + if (strategy.openStage !== undefined) { + if (strategy.openStage.openExecution !== undefined) { + putOpeningOrder() + return + } + } + break + } + case 'Taking Position': { // Waiting for a confirmation that the position was taken. + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionNow -> Exiting code block because status is Taking Position.') } + break + } + case 'In a Position': { // This should mean that we already put the order at the exchange. + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionNow -> Exiting code block because status is In a Position.') } + break + } + } + } else { // The context does not exist so it means we are not in a position. + if (strategy.openStage !== undefined) { + if (strategy.openStage.openExecution !== undefined) { + putOpeningOrder() + return + } + } + } + } else { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionNow -> Not trading live.') } + } + } else { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionNow -> Not the last closed candle.') } + } + + takePositionAtSimulation() + return - } - } - } - } else { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionNow -> Not trading live.') } - } - } else { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionNow -> Not the last closed candle.') } - } - takePositionAtSimulation() - - return - - function putOpeningOrder () { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Entering function.') } + function putOpeningOrder() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Entering function.') } /* We wont take a position unless we are withing the bot.VALUES_TO_USE.timeRange.initialDatetime and the bot.VALUES_TO_USE.timeRange.finalDatetime range */ - if (bot.VALUES_TO_USE.timeRange.initialDatetime !== undefined) { - if (candle.end < bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because current candle ends before the start date. -> bot.VALUES_TO_USE.timeRange.initialDatetime = ' + bot.VALUES_TO_USE.timeRange.initialDatetime) } - takePositionAtSimulation() - return - } - } + if (bot.VALUES_TO_USE.timeRange.initialDatetime !== undefined) { + if (candle.end < bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because current candle ends before the start date. -> bot.VALUES_TO_USE.timeRange.initialDatetime = ' + bot.VALUES_TO_USE.timeRange.initialDatetime) } + takePositionAtSimulation() + return + } + } /* We wont take a position if we are past the final datetime */ - if (bot.VALUES_TO_USE.timeRange.finalDatetime !== undefined) { - if (candle.begin > bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because current candle begins after the end date. -> bot.VALUES_TO_USE.timeRange.finalDatetime = ' + bot.VALUES_TO_USE.timeRange.finalDatetime) } - takePositionAtSimulation() - return - } - } + if (bot.VALUES_TO_USE.timeRange.finalDatetime !== undefined) { + if (candle.begin > bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because current candle begins after the end date. -> bot.VALUES_TO_USE.timeRange.finalDatetime = ' + bot.VALUES_TO_USE.timeRange.finalDatetime) } + takePositionAtSimulation() + return + } + } /* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */ - if (variable.executionContext !== undefined) { - if (variable.executionContext.periods !== undefined) { - if (variable.episode.count.periods <= variable.executionContext.periods) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because it was already placed at a previous execution.') } - takePositionAtSimulation() - return - } - } - } + if (variable.executionContext !== undefined) { + if (variable.executionContext.periods !== undefined) { + if (variable.episode.count.periods <= variable.executionContext.periods) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because it was already placed at a previous execution.') } + takePositionAtSimulation() + return + } + } + } /* We are not going to place orders based on outdated information. The next filter prevents firing orders when backtesting. */ - if (currentDay) { - let today = new Date(Math.trunc((new Date().valueOf()) / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) - let processDay = new Date(Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) - if (today.valueOf() !== processDay.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because the current candle belongs to the previous day and that is considered simulation and not live trading.') } - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> today = ' + today) } - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> processDay = ' + processDay) } - takePositionAtSimulation() - return - } - } + if (currentDay) { + let today = new Date(Math.trunc((new Date().valueOf()) / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) + let processDay = new Date(Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) + if (today.valueOf() !== processDay.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because the current candle belongs to the previous day and that is considered simulation and not live trading.') } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> today = ' + today) } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> processDay = ' + processDay) } + takePositionAtSimulation() + return + } + } - let orderPrice - let amountA - let amountB - let orderSide + let orderPrice + let amountA + let amountB + let orderSide - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - orderSide = 'sell' + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + orderSide = 'sell' - orderPrice = variable.current.position.rate + orderPrice = variable.current.position.rate - amountA = variable.current.position.size * orderPrice - amountB = variable.current.position.size - } else { - orderSide = 'buy' + amountA = variable.current.position.size * orderPrice + amountB = variable.current.position.size + } else { + orderSide = 'buy' - orderPrice = variable.current.position.rate + orderPrice = variable.current.position.rate - amountA = variable.current.position.size - amountB = variable.current.position.size / orderPrice - } + amountA = variable.current.position.size + amountB = variable.current.position.size / orderPrice + } - variable.executionContext = { - status: 'Taking Position', - periods: variable.episode.count.periods - } + variable.executionContext = { + status: 'Taking Position', + periods: variable.episode.count.periods + } - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Ready to create order.') } - exchangeAPI.createOrder(bot.market, orderSide, orderPrice, amountA, amountB, onOrderCreated) + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Ready to create order.') } + exchangeAPI.createOrder(bot.market, orderSide, orderPrice, amountA, amountB, onOrderCreated) - function onOrderCreated (err, order) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> Entering function.') } + function onOrderCreated(err, order) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> Entering function.') } - try { - switch (err.result) { - case global.DEFAULT_OK_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_OK_RESPONSE ') } - variable.executionContext = { - status: 'In a Position', - periods: variable.episode.count.periods, - amountA: amountA, - amountB: amountB, - orderId: order.id - } - takePositionAtSimulation() - return - } - case global.DEFAULT_FAIL_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_FAIL_RESPONSE ') } - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> Message = ' + err.message) } - strategy.openStage.openExecution.error = err.message - afterLoop() - return - } - case global.DEFAULT_RETRY_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_RETRY_RESPONSE ') } - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> Message = ' + err.message) } - strategy.openStage.openExecution.error = err.message - afterLoop() - return - } - } - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> Unexpected Response -> Message = ' + err.message) } - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - return - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - return - } - } - } + try { + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_OK_RESPONSE ') } + variable.executionContext = { + status: 'In a Position', + periods: variable.episode.count.periods, + amountA: amountA, + amountB: amountB, + orderId: order.id + } + takePositionAtSimulation() + return + } + case global.DEFAULT_FAIL_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_FAIL_RESPONSE ') } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> Message = ' + err.message) } + strategy.openStage.openExecution.error = err.message + afterLoop() + return + } + case global.DEFAULT_RETRY_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_RETRY_RESPONSE ') } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> Message = ' + err.message) } + strategy.openStage.openExecution.error = err.message + afterLoop() + return + } + } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> Unexpected Response -> Message = ' + err.message) } + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + return + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + return + } + } + } - function takePositionAtSimulation () { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionAtSimulation -> Entering function.') } + function takePositionAtSimulation() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionAtSimulation -> Entering function.') } /* Continue with the simulation */ - calculateTakeProfit() - calculateStopLoss() + calculateTakeProfit() + calculateStopLoss() - variable.previous.balance.baseAsset = variable.current.balance.baseAsset - variable.previous.balance.quotedAsset = variable.current.balance.quotedAsset + variable.previous.balance.baseAsset = variable.current.balance.baseAsset + variable.previous.balance.quotedAsset = variable.current.balance.quotedAsset - variable.last.position.profitLoss = 0 - variable.last.position.ROI = 0 + variable.last.position.profitLoss = 0 + variable.last.position.ROI = 0 - let feePaid = 0 + let feePaid = 0 - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - feePaid = variable.current.position.size * variable.current.position.rate * bot.VALUES_TO_USE.feeStructure.taker / 100 + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + feePaid = variable.current.position.size * variable.current.position.rate * bot.VALUES_TO_USE.feeStructure.taker / 100 - variable.current.balance.quotedAsset = variable.current.balance.quotedAsset + variable.current.position.size * variable.current.position.rate - feePaid - variable.current.balance.baseAsset = variable.current.balance.baseAsset - variable.current.position.size - } else { - feePaid = variable.current.position.size / variable.current.position.rate * bot.VALUES_TO_USE.feeStructure.taker / 100 + variable.current.balance.quotedAsset = variable.current.balance.quotedAsset + variable.current.position.size * variable.current.position.rate - feePaid + variable.current.balance.baseAsset = variable.current.balance.baseAsset - variable.current.position.size + } else { + feePaid = variable.current.position.size / variable.current.position.rate * bot.VALUES_TO_USE.feeStructure.taker / 100 - variable.current.balance.baseAsset = variable.current.balance.baseAsset + variable.current.position.size / variable.current.position.rate - feePaid - variable.current.balance.quotedAsset = variable.current.balance.quotedAsset - variable.current.position.size - } + variable.current.balance.baseAsset = variable.current.balance.baseAsset + variable.current.position.size / variable.current.position.rate - feePaid + variable.current.balance.quotedAsset = variable.current.balance.quotedAsset - variable.current.position.size + } - addRecord() - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionAtSimulation -> Exiting Loop Body after taking position at simulation.') } - controlLoop() - return - } - } + addRecord() + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionAtSimulation -> Exiting Loop Body after taking position at simulation.') } + controlLoop() + return + } + } - if (closePositionNow === true) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Closing a Position -> Entering code block.') } + if (closePositionNow === true) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Closing a Position -> Entering code block.') } - closePositionNow = false + closePositionNow = false /* Inicializing this counter */ - variable.current.distance.toEvent.closePosition = 1 + variable.current.distance.toEvent.closePosition = 1 /* Position size and rate */ - let strategy = tradingSystem.strategies[strategyIndex] + let strategy = tradingSystem.strategies[strategyIndex] - if (currentCandleIndex > candles.length - 10) { /* Only at the last candles makes sense to check if we are in live mode or not. */ + if (currentCandleIndex > candles.length - 10) { /* Only at the last candles makes sense to check if we are in live mode or not. */ /* Check that we are in LIVE MODE */ - if (bot.startMode === 'Live') { + if (bot.startMode === 'Live') { /* We see if we need to put the actual order at the exchange. */ - if (variable.executionContext !== undefined) { - switch (variable.executionContext.status) { - case 'Without a Position': { // No way to close anything at the exchange. - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Closing a Position -> Exiting code block because status is Without a Position.') } - break - } - case 'In a Position': { // This should mean that we already put the order at the exchange. - if (strategy.closeStage !== undefined) { - if (strategy.closeStage.closeExecution !== undefined) { - putClosingOrder() - return - } - } - break - } - case 'Closing Position': { // Waiting for a confirmation that the position was taken. - if (strategy.closeStage !== undefined) { - if (strategy.closeStage.closeExecution !== undefined) { - putClosingOrder() - return - } - } - break - } + if (variable.executionContext !== undefined) { + switch (variable.executionContext.status) { + case 'Without a Position': { // No way to close anything at the exchange. + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Closing a Position -> Exiting code block because status is Without a Position.') } + break + } + case 'In a Position': { // This should mean that we already put the order at the exchange. + if (strategy.closeStage !== undefined) { + if (strategy.closeStage.closeExecution !== undefined) { + putClosingOrder() + return + } + } + break + } + case 'Closing Position': { // Waiting for a confirmation that the position was taken. + if (strategy.closeStage !== undefined) { + if (strategy.closeStage.closeExecution !== undefined) { + putClosingOrder() + return + } + } + break + } - case 'Position Closed': { // - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Closing a Position -> Exiting code block because status is Position Closed.') } - break - } - } - } - } - } else { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Closing a Position -> Not within the last 10 candles.') } - } + case 'Position Closed': { // + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Closing a Position -> Exiting code block because status is Position Closed.') } + break + } + } + } + } + } else { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Closing a Position -> Not within the last 10 candles.') } + } - closePositionAtSimulation() - return - - function putClosingOrder () { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> putClosingOrder -> Entering function.') } - - /* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */ - if (variable.executionContext !== undefined) { - if (variable.executionContext.periods !== undefined) { - if (variable.episode.count.periods <= variable.executionContext.periods) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putClosingOrder -> Exiting function because this closing was already submited at a previous execution.') } - closePositionAtSimulation() - return - } - } - } - - let orderPrice - let amountA - let amountB - let orderSide - - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - orderSide = 'buy' - - orderPrice = ticker.last + 100 // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. - - amountA = variable.current.balance.quotedAsset - amountB = variable.current.balance.quotedAsset / orderPrice - } else { - orderSide = 'sell' - - orderPrice = ticker.last - 100 // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. - - amountA = variable.current.balance.baseAsset * orderPrice - amountB = variable.current.balance.baseAsset - } - - variable.executionContext = { - status: 'Closing Position', - periods: variable.episode.count.periods - } - - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putClosingOrder -> About to close position at the exchange.') } - exchangeAPI.createOrder(bot.market, orderSide, orderPrice, amountA, amountB, onOrderCreated) - - function onOrderCreated (err, order) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> Entering function.') } - - try { - switch (err.result) { - case global.DEFAULT_OK_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> DEFAULT_OK_RESPONSE ') } - variable.executionContext = { - status: 'Position Closed', - periods: variable.episode.count.periods, - amountA: amountA, - amountB: amountB, - orderId: order.id - } closePositionAtSimulation() return - } - case global.DEFAULT_FAIL_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> DEFAULT_FAIL_RESPONSE ') } + + function putClosingOrder() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> putClosingOrder -> Entering function.') } + + /* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */ + if (variable.executionContext !== undefined) { + if (variable.executionContext.periods !== undefined) { + if (variable.episode.count.periods <= variable.executionContext.periods) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putClosingOrder -> Exiting function because this closing was already submited at a previous execution.') } + closePositionAtSimulation() + return + } + } + } + + let orderPrice + let amountA + let amountB + let orderSide + + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + orderSide = 'buy' + + orderPrice = ticker.last + 100 // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. + + amountA = variable.current.balance.quotedAsset + amountB = variable.current.balance.quotedAsset / orderPrice + } else { + orderSide = 'sell' + + orderPrice = ticker.last - 100 // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. + + amountA = variable.current.balance.baseAsset * orderPrice + amountB = variable.current.balance.baseAsset + } + + variable.executionContext = { + status: 'Closing Position', + periods: variable.episode.count.periods + } + + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putClosingOrder -> About to close position at the exchange.') } + exchangeAPI.createOrder(bot.market, orderSide, orderPrice, amountA, amountB, onOrderCreated) + + function onOrderCreated(err, order) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> Entering function.') } + + try { + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> DEFAULT_OK_RESPONSE ') } + variable.executionContext = { + status: 'Position Closed', + periods: variable.episode.count.periods, + amountA: amountA, + amountB: amountB, + orderId: order.id + } + closePositionAtSimulation() + return + } + case global.DEFAULT_FAIL_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> DEFAULT_FAIL_RESPONSE ') } /* We will assume that the problem is temporary, and expect that it will work at the next execution. */ - strategy.closeStage.closeExecution.error = err.message - afterLoop() - return - } - case global.DEFAULT_RETRY_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_RETRY_RESPONSE ') } - strategy.closeStage.closeExecution.error = err.message - afterLoop() - return - } + strategy.closeStage.closeExecution.error = err.message + afterLoop() + return + } + case global.DEFAULT_RETRY_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderCreated -> DEFAULT_RETRY_RESPONSE ') } + strategy.closeStage.closeExecution.error = err.message + afterLoop() + return + } + } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> Unexpected Response -> Message = ' + err.message) } + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + return + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + return + } + } + } + + function closePositionAtSimulation() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> closePositionAtSimulation -> Entering function.') } + + variable.episode.count.positions++ + + let feePaid = 0 + + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + strategy.positionSize = variable.current.balance.quotedAsset / closeRate + strategy.positionRate = closeRate + + feePaid = variable.current.balance.quotedAsset / closeRate * bot.VALUES_TO_USE.feeStructure.taker / 100 + + variable.current.balance.baseAsset = variable.current.balance.baseAsset + variable.current.balance.quotedAsset / closeRate - feePaid + variable.current.balance.quotedAsset = 0 + } else { + strategy.positionSize = variable.current.balance.baseAsset * closeRate + strategy.positionRate = closeRate + + feePaid = variable.current.balance.baseAsset * closeRate * bot.VALUES_TO_USE.feeStructure.taker / 100 + + variable.current.balance.quotedAsset = variable.current.balance.quotedAsset + variable.current.balance.baseAsset * closeRate - feePaid + variable.current.balance.baseAsset = 0 + } + + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + variable.last.position.profitLoss = variable.current.balance.baseAsset - variable.previous.balance.baseAsset + variable.last.position.ROI = variable.last.position.profitLoss * 100 / variable.current.position.size + if (isNaN(lastTradeROI)) { variable.last.position.ROI = 0 } + variable.episode.stat.profitLoss = variable.current.balance.baseAsset - variable.episode.parameters.initial.balance.baseAsset + } else { + variable.last.position.profitLoss = variable.current.balance.quotedAsset - variable.previous.balance.quotedAsset + variable.last.position.ROI = variable.last.position.profitLoss * 100 / variable.current.position.size + if (isNaN(lastTradeROI)) { variable.last.position.ROI = 0 } + variable.episode.stat.profitLoss = variable.current.balance.quotedAsset - variable.episode.parameters.initial.balance.quotedAsset + } + + variable.current.position.lastTradeROI = variable.last.position.ROI + + if (variable.last.position.profitLoss > 0) { + variable.episode.count.hits++ + } else { + variable.episode.count.fails++ + } + + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + variable.episode.stat.ROI = (variable.episode.parameters.initial.balance.baseAsset + variable.episode.stat.profitLoss) / variable.episode.parameters.initial.balance.baseAsset - 1 + variable.episode.stat.hitRatio = variable.episode.count.hits / variable.episode.count.positions + variable.episode.stat.anualizedRateOfReturn = variable.episode.stat.ROI / variable.episode.stat.days * 365 + } else { + variable.episode.stat.ROI = (variable.episode.parameters.initial.balance.quotedAsset + variable.episode.stat.profitLoss) / variable.episode.parameters.initial.balance.quotedAsset - 1 + variable.episode.stat.hitRatio = variable.episode.count.hits / variable.episode.count.positions + variable.episode.stat.anualizedRateOfReturn = variable.episode.stat.ROI / variable.episode.stat.days * 365 + } + + addRecord() + + variable.current.position.stopLoss = 0 + variable.current.position.takeProfit = 0 + + variable.current.position.rate = 0 + variable.current.position.size = 0 + + timerToCloseStage = candle.begin + variable.current.position.stopLossStage = 'No Stage' + variable.current.position.takeProfitStage = 'No Stage' + variable.current.position.stopLossPhase = -1 + variable.current.position.takeProfitPhase = -1 + + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> closePositionAtSimulation -> Exiting Loop Body after closing position at simulation.') } + controlLoop() + return + } } - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> Unexpected Response -> Message = ' + err.message) } - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - return - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] runSimulation -> loop -> putClosingOrder -> onOrderCreated -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - return - } - } - } - - function closePositionAtSimulation () { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> closePositionAtSimulation -> Entering function.') } - - variable.episode.count.positions++ - - let feePaid = 0 - - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - strategy.positionSize = variable.current.balance.quotedAsset / closeRate - strategy.positionRate = closeRate - - feePaid = variable.current.balance.quotedAsset / closeRate * bot.VALUES_TO_USE.feeStructure.taker / 100 - - variable.current.balance.baseAsset = variable.current.balance.baseAsset + variable.current.balance.quotedAsset / closeRate - feePaid - variable.current.balance.quotedAsset = 0 - } else { - strategy.positionSize = variable.current.balance.baseAsset * closeRate - strategy.positionRate = closeRate - - feePaid = variable.current.balance.baseAsset * closeRate * bot.VALUES_TO_USE.feeStructure.taker / 100 - - variable.current.balance.quotedAsset = variable.current.balance.quotedAsset + variable.current.balance.baseAsset * closeRate - feePaid - variable.current.balance.baseAsset = 0 - } - - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - variable.last.position.profitLoss = variable.current.balance.baseAsset - variable.previous.balance.baseAsset - variable.last.position.ROI = variable.last.position.profitLoss * 100 / variable.current.position.size - if (isNaN(lastTradeROI)) { variable.last.position.ROI = 0 } - variable.episode.stat.profitLoss = variable.current.balance.baseAsset - variable.episode.parameters.initial.balance.baseAsset - } else { - variable.last.position.profitLoss = variable.current.balance.quotedAsset - variable.previous.balance.quotedAsset - variable.last.position.ROI = variable.last.position.profitLoss * 100 / variable.current.position.size - if (isNaN(lastTradeROI)) { variable.last.position.ROI = 0 } - variable.episode.stat.profitLoss = variable.current.balance.quotedAsset - variable.episode.parameters.initial.balance.quotedAsset - } - - variable.current.position.lastTradeROI = variable.last.position.ROI - - if (variable.last.position.profitLoss > 0) { - variable.episode.count.hits++ - } else { - variable.episode.count.fails++ - } - - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - variable.episode.stat.ROI = (variable.episode.parameters.initial.balance.baseAsset + variable.episode.stat.profitLoss) / variable.episode.parameters.initial.balance.baseAsset - 1 - variable.episode.stat.hitRatio = variable.episode.count.hits / variable.episode.count.positions - variable.episode.stat.anualizedRateOfReturn = variable.episode.stat.ROI / variable.episode.stat.days * 365 - } else { - variable.episode.stat.ROI = (variable.episode.parameters.initial.balance.quotedAsset + variable.episode.stat.profitLoss) / variable.episode.parameters.initial.balance.quotedAsset - 1 - variable.episode.stat.hitRatio = variable.episode.count.hits / variable.episode.count.positions - variable.episode.stat.anualizedRateOfReturn = variable.episode.stat.ROI / variable.episode.stat.days * 365 - } - - addRecord() - - variable.current.position.stopLoss = 0 - variable.current.position.takeProfit = 0 - - variable.current.position.rate = 0 - variable.current.position.size = 0 - - timerToCloseStage = candle.begin - variable.current.position.stopLossStage = 'No Stage' - variable.current.position.takeProfitStage = 'No Stage' - variable.current.position.stopLossPhase = -1 - variable.current.position.takeProfitPhase = -1 - - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> closePositionAtSimulation -> Exiting Loop Body after closing position at simulation.') } - controlLoop() - return - } - } /* Closing the Closing Stage */ - if (variable.current.strategy.stage === 'Close Stage') { - if (candle.begin - 5 * 60 * 1000 > timerToCloseStage) { - variable.current.strategy.number = variable.current.strategy.index - variable.current.strategy.end = candle.end - variable.current.strategy.endRate = candle.min - variable.current.strategy.status = 1 // This means the strategy is closed, i.e. that has a begin and end. + if (variable.current.strategy.stage === 'Close Stage') { + if (candle.begin - 5 * 60 * 1000 > timerToCloseStage) { + variable.current.strategy.number = variable.current.strategy.index + variable.current.strategy.end = candle.end + variable.current.strategy.endRate = candle.min + variable.current.strategy.status = 1 // This means the strategy is closed, i.e. that has a begin and end. - variable.current.strategy.index = -1 - variable.current.strategy.stage = 'No Stage' + variable.current.strategy.index = -1 + variable.current.strategy.stage = 'No Stage' - timerToCloseStage = 0 - variable.current.distance.toEvent.triggerOff = 1 + timerToCloseStage = 0 + variable.current.distance.toEvent.triggerOff = 1 - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Closing the Closing Stage -> Exiting Close Stage.') } - } else { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Closing the Closing Stage -> Waiting for timer.') } - } - } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Closing the Closing Stage -> Exiting Close Stage.') } + } else { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Closing the Closing Stage -> Waiting for timer.') } + } + } /* Not a buy or sell condition */ - addRecord() - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Exiting Loop Body after adding a record.') } - controlLoop() - return + addRecord() + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Exiting Loop Body after adding a record.') } + controlLoop() + return - function addRecord () { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> addRecord -> Entering function.') } - let simulationRecord + function addRecord() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> addRecord -> Entering function.') } + let simulationRecord - if (variable.current.balance.baseAsset === Infinity) { - variable.current.balance.baseAsset = Number.MAX_SAFE_INTEGER - } + if (variable.current.balance.baseAsset === Infinity) { + variable.current.balance.baseAsset = Number.MAX_SAFE_INTEGER + } - if (variable.current.balance.quotedAsset === Infinity) { - variable.current.balance.quotedAsset = Number.MAX_SAFE_INTEGER - } + if (variable.current.balance.quotedAsset === Infinity) { + variable.current.balance.quotedAsset = Number.MAX_SAFE_INTEGER + } - simulationRecord = { - begin: candle.begin, - end: candle.end, - balanceBaseAsset: variable.current.balance.baseAsset, - balanceQuotedAsset: variable.current.balance.quotedAsset, - accumulatedProfitLoss: variable.episode.stat.profitLoss, - lastTradeProfitLoss: variable.last.position.profitLoss, - stopLoss: variable.current.position.stopLoss, - tradesCount: variable.episode.count.positions, - hits: variable.episode.count.hits, - fails: variable.episode.count.fails, - hitRatio: variable.episode.stat.hitRatio, - ROI: variable.episode.stat.ROI, - periods: variable.episode.count.periods, - days: variable.episode.stat.days, - anualizedRateOfReturn: variable.episode.stat.anualizedRateOfReturn, - positionRate: variable.current.position.rate, - lastTradeROI: variable.last.position.ROI, - strategy: variable.current.strategy.index, - takeProfit: variable.current.position.takeProfit, - stopLossPhase: variable.current.position.stopLossPhase, - takeProfitPhase: variable.current.position.takeProfitPhase, - positionSize: variable.current.position.size, - initialBalanceA: variable.episode.parameters.initial.balance.baseAsset, - minimumBalanceA: variable.episode.parameters.minimum.balance.baseAsset, - maximumBalanceA: variable.episode.parameters.maximum.balance.baseAsset, - initialBalanceB: variable.episode.parameters.initial.balance.quotedAsset, - minimumBalanceB: variable.episode.parameters.minimum.balance.quotedAsset, - maximumBalanceB: variable.episode.parameters.maximum.balance.quotedAsset, - baseAsset: '"' + variable.episode.parameters.baseAsset + '"', - quotedAsset: '"' + variable.episode.parameters.quotedAsset + '"', - marketBaseAsset: '"' + variable.episode.parameters.marketBaseAsset + '"', - marketQuotedAsset: '"' + variable.episode.parameters.marketQuotedAsset + '"', - positionPeriods: variable.current.position.periods, - positionDays: variable.positionDays, - distanceToEventTriggerOn: variable.current.distance.toEvent.triggerOn, - distanceToEventTriggerOff: variable.current.distance.toEvent.triggerOff, - distanceToEventTakePosition: variable.current.distance.toEvent.takePosition, - distanceToEventClosePosition: variable.current.distance.toEvent.closePosition - } + simulationRecord = { + begin: candle.begin, + end: candle.end, + balanceBaseAsset: variable.current.balance.baseAsset, + balanceQuotedAsset: variable.current.balance.quotedAsset, + accumulatedProfitLoss: variable.episode.stat.profitLoss, + lastTradeProfitLoss: variable.last.position.profitLoss, + stopLoss: variable.current.position.stopLoss, + tradesCount: variable.episode.count.positions, + hits: variable.episode.count.hits, + fails: variable.episode.count.fails, + hitRatio: variable.episode.stat.hitRatio, + ROI: variable.episode.stat.ROI, + periods: variable.episode.count.periods, + days: variable.episode.stat.days, + anualizedRateOfReturn: variable.episode.stat.anualizedRateOfReturn, + positionRate: variable.current.position.rate, + lastTradeROI: variable.last.position.ROI, + strategy: variable.current.strategy.index, + takeProfit: variable.current.position.takeProfit, + stopLossPhase: variable.current.position.stopLossPhase, + takeProfitPhase: variable.current.position.takeProfitPhase, + positionSize: variable.current.position.size, + initialBalanceA: variable.episode.parameters.initial.balance.baseAsset, + minimumBalanceA: variable.episode.parameters.minimum.balance.baseAsset, + maximumBalanceA: variable.episode.parameters.maximum.balance.baseAsset, + initialBalanceB: variable.episode.parameters.initial.balance.quotedAsset, + minimumBalanceB: variable.episode.parameters.minimum.balance.quotedAsset, + maximumBalanceB: variable.episode.parameters.maximum.balance.quotedAsset, + baseAsset: '"' + variable.episode.parameters.baseAsset + '"', + quotedAsset: '"' + variable.episode.parameters.quotedAsset + '"', + marketBaseAsset: '"' + variable.episode.parameters.marketBaseAsset + '"', + marketQuotedAsset: '"' + variable.episode.parameters.marketQuotedAsset + '"', + positionPeriods: variable.current.position.periods, + positionDays: variable.positionDays, + distanceToEventTriggerOn: variable.current.distance.toEvent.triggerOn, + distanceToEventTriggerOff: variable.current.distance.toEvent.triggerOff, + distanceToEventTakePosition: variable.current.distance.toEvent.takePosition, + distanceToEventClosePosition: variable.current.distance.toEvent.closePosition + } - recordsArray.push(simulationRecord) + recordsArray.push(simulationRecord) /* Prepare the information for the Conditions File */ - conditionsArrayRecord.push(strategyIndex) - conditionsArrayRecord.push(stopLossPhase) - conditionsArrayRecord.push(takeProfitPhase) - conditionsArrayRecord.push(conditionsArrayValues) - conditionsArrayRecord.push(formulasErrors) - conditionsArrayRecord.push(formulasValues) + conditionsArrayRecord.push(strategyIndex) + conditionsArrayRecord.push(stopLossPhase) + conditionsArrayRecord.push(takeProfitPhase) + conditionsArrayRecord.push(conditionsArrayValues) + conditionsArrayRecord.push(formulasErrors) + conditionsArrayRecord.push(formulasValues) - conditionsArray.push(conditionsArrayRecord) + conditionsArray.push(conditionsArrayRecord) /* Lets see if there will be an open strategy ... Except if we are at the head of the market (remember we skipped the last candle for not being closed.) */ - if (variable.current.strategy.begin !== 0 && variable.current.strategy.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { - variable.current.strategy.status = 2 // This means the strategy is open, i.e. that has a begin but no end. - variable.current.strategy.end = candle.end - } + if (variable.current.strategy.begin !== 0 && variable.current.strategy.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { + variable.current.strategy.status = 2 // This means the strategy is open, i.e. that has a begin but no end. + variable.current.strategy.end = candle.end + } /* Prepare the information for the Strategies File */ - if (variable.current.strategy.begin !== 0 && variable.current.strategy.end !== 0) { - let currentStrategyRecord = { - begin: variable.current.strategy.begin, - end: variable.current.strategy.end, - status: variable.current.strategy.status, - number: variable.current.strategy.number, - beginRate: variable.current.strategy.beginRate, - endRate: variable.current.strategy.endRate, - situationName: variable.current.strategy.situationName - } + if (variable.current.strategy.begin !== 0 && variable.current.strategy.end !== 0) { + let currentStrategyRecord = { + begin: variable.current.strategy.begin, + end: variable.current.strategy.end, + status: variable.current.strategy.status, + number: variable.current.strategy.number, + beginRate: variable.current.strategy.beginRate, + endRate: variable.current.strategy.endRate, + situationName: variable.current.strategy.situationName + } - strategiesArray.push(currentStrategyRecord) + strategiesArray.push(currentStrategyRecord) - inializeCurrentStrategy() - } + inializeCurrentStrategy() + } /* Lets see if there will be an open trade ... Except if we are at the head of the market (remember we skipped the last candle for not being closed.) */ - if (variable.current.position.begin !== 0 && variable.current.position.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { - variable.current.position.status = 2 // This means the trade is open - variable.current.position.end = candle.end - variable.current.position.endRate = candle.close + if (variable.current.position.begin !== 0 && variable.current.position.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { + variable.current.position.status = 2 // This means the trade is open + variable.current.position.end = candle.end + variable.current.position.endRate = candle.close /* Here we will calculate the ongoing variable.episode.stat.ROI */ - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - variable.current.position.lastTradeROI = (variable.current.position.rate - candle.close) / variable.current.position.rate * 100 - } else { - variable.current.position.lastTradeROI = (candle.close - variable.current.position.rate) / variable.current.position.rate * 100 - } - } + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + variable.current.position.lastTradeROI = (variable.current.position.rate - candle.close) / variable.current.position.rate * 100 + } else { + variable.current.position.lastTradeROI = (candle.close - variable.current.position.rate) / variable.current.position.rate * 100 + } + } /* Snapshots Management (before we generate the trade record and delete that info) */ - if (saveAsLastTriggerOnSnapshot === true) { - snapshots.lastTriggerOn = snapshotDataRecord - saveAsLastTriggerOnSnapshot = false - } + if (saveAsLastTriggerOnSnapshot === true) { + snapshots.lastTriggerOn = snapshotDataRecord + saveAsLastTriggerOnSnapshot = false + } - if (saveAsLastTakePositionSnapshot === true) { - snapshots.lastTakePosition = snapshotDataRecord - saveAsLastTakePositionSnapshot = false - } + if (saveAsLastTakePositionSnapshot === true) { + snapshots.lastTakePosition = snapshotDataRecord + saveAsLastTakePositionSnapshot = false + } - if (addToSnapshots === true) { - let closeValues = [ - roundtrips, // Trade Number - (new Date(candle.begin)).toISOString(), // Datetime - tradingSystem.strategies[currentStrategyIndex].name, // Strategy - currentStrategy.triggerOnSituation, // Trigger On Situation - currentTrade.takePositionSituation, // Take Position Situation - hitOrFial(), // Result - lastTradeROI, // ROI - simulationRecord.type.replace(/"/g, '') // Exit Type - ] + if (addToSnapshots === true) { + let closeValues = [ + roundtrips, // Trade Number + (new Date(candle.begin)).toISOString(), // Datetime + tradingSystem.strategies[currentStrategyIndex].name, // Strategy + currentStrategy.triggerOnSituation, // Trigger On Situation + currentTrade.takePositionSituation, // Take Position Situation + hitOrFial(), // Result + lastTradeROI, // ROI + simulationRecord.type.replace(/"/g, '') // Exit Type + ] - function hitOrFial () { - if (lastTradeROI > 0) { return 'HIT' } else { return 'FAIL' } - } + function hitOrFial() { + if (lastTradeROI > 0) { return 'HIT' } else { return 'FAIL' } + } - if (positionedAtYesterday === false) { - snapshots.triggerOn.push(closeValues.concat(snapshots.lastTriggerOn)) - snapshots.takePosition.push(closeValues.concat(snapshots.lastTakePosition)) - } - snapshots.lastTriggerOn = undefined - snapshots.lastTakePosition = undefined - addToSnapshots = false - } + if (positionedAtYesterday === false) { + snapshots.triggerOn.push(closeValues.concat(snapshots.lastTriggerOn)) + snapshots.takePosition.push(closeValues.concat(snapshots.lastTakePosition)) + } + snapshots.lastTriggerOn = undefined + snapshots.lastTakePosition = undefined + addToSnapshots = false + } - let closeHeaders = ['Trade Number', 'Close Datetime', 'Strategy', 'Trigger On Situation', 'Take Position Situation', 'Result', 'ROI', 'Exit Type'] - if (snapshots.headers === undefined) { - snapshots.headers = closeHeaders.concat(JSON.parse(JSON.stringify(snapshotLoopHeaders))) - } + let closeHeaders = ['Trade Number', 'Close Datetime', 'Strategy', 'Trigger On Situation', 'Take Position Situation', 'Result', 'ROI', 'Exit Type'] + if (snapshots.headers === undefined) { + snapshots.headers = closeHeaders.concat(JSON.parse(JSON.stringify(snapshotLoopHeaders))) + } - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.snapshots.headers = snapshots.headers - yesterday.snapshots.triggerOn = snapshots.triggerOn - yesterday.snapshots.takePosition = snapshots.takePosition - yesterday.snapshots.lastTriggerOn = snapshots.lastTriggerOn - yesterday.snapshots.lastTakePosition = snapshots.lastTakePosition - } - } + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.snapshots.headers = snapshots.headers + yesterday.snapshots.triggerOn = snapshots.triggerOn + yesterday.snapshots.takePosition = snapshots.takePosition + yesterday.snapshots.lastTriggerOn = snapshots.lastTriggerOn + yesterday.snapshots.lastTakePosition = snapshots.lastTakePosition + } + } /* Prepare the information for the Trades File */ - if (variable.current.position.begin !== 0 && variable.current.position.end !== 0) { - let currentPositionRecord = { - begin: variable.current.position.begin, - end: variable.current.position.end, - status: variable.current.position.status, - lastTradeROI: variable.current.position.lastTradeROI, - exitType: variable.current.position.exitType, - beginRate: variable.current.position.beginRate, - endRate: variable.current.position.endRate, - situationName: variable.current.position.situationName - } + if (variable.current.position.begin !== 0 && variable.current.position.end !== 0) { + let currentPositionRecord = { + begin: variable.current.position.begin, + end: variable.current.position.end, + status: variable.current.position.status, + lastTradeROI: variable.current.position.lastTradeROI, + exitType: variable.current.position.exitType, + beginRate: variable.current.position.beginRate, + endRate: variable.current.position.endRate, + situationName: variable.current.position.situationName + } - tradesArray.push(currentPositionRecord) + positionsArray.push(currentPositionRecord) - initializeCurrentPosition() - } + initializeCurrentPosition() + } /* After everything at the simulation level was done, we will do the annoucements that are pending. */ - makeAnnoucements() - } + makeAnnoucements() + } - function checkAnnouncements (node, value) { + function checkAnnouncements(node, value) { /* Value is an optional parameter that represents the value that the announcement is monitoring for change (for numeric values only). If we do receive this value, we will only make the annoucement if the variance is grater than the user pre-defined value for this variance. */ - if (node.announcements !== undefined) { - for (let i = 0; i < node.announcements.length; i++) { - let announcement = node.announcements[i] - let key = node.type + '-' + announcement.name + '-' + announcement.id + if (node.announcements !== undefined) { + for (let i = 0; i < node.announcements.length; i++) { + let announcement = node.announcements[i] + let key = node.type + '-' + announcement.name + '-' + announcement.id - let lastPeriodAnnounced = -1 - let newAnnouncementRecord = {} + let lastPeriodAnnounced = -1 + let newAnnouncementRecord = {} - for (let j = 0; j < variable.announcements.length; j++) { - let announcementRecord = variable.announcements[j] - if (announcementRecord.key === key) { - lastPeriodAnnounced = announcementRecord.periods - newAnnouncementRecord = announcementRecord - break - } - } + for (let j = 0; j < variable.announcements.length; j++) { + let announcementRecord = variable.announcements[j] + if (announcementRecord.key === key) { + lastPeriodAnnounced = announcementRecord.periods + newAnnouncementRecord = announcementRecord + break + } + } - if (variable.episode.count.periods > lastPeriodAnnounced) { - if (isNaN(value) === false) { + if (variable.episode.count.periods > lastPeriodAnnounced) { + if (isNaN(value) === false) { /* The Value Variation is what tells us how much the value already announced must change in order to annouce it again. */ - let valueVariation + let valueVariation - let code = announcement.code - valueVariation = code.valueVariation + let code = announcement.code + valueVariation = code.valueVariation - if (newAnnouncementRecord.value !== undefined && valueVariation !== undefined) { - let upperLimit = newAnnouncementRecord.value + newAnnouncementRecord.value * valueVariation / 100 - let lowerLimit = newAnnouncementRecord.value - newAnnouncementRecord.value * valueVariation / 100 - if (value > lowerLimit && value < upperLimit) { + if (newAnnouncementRecord.value !== undefined && valueVariation !== undefined) { + let upperLimit = newAnnouncementRecord.value + newAnnouncementRecord.value * valueVariation / 100 + let lowerLimit = newAnnouncementRecord.value - newAnnouncementRecord.value * valueVariation / 100 + if (value > lowerLimit && value < upperLimit) { /* There is not enough variation to announce this again. */ - return - } - } - } + return + } + } + } /* We store the announcement temporarily at an Array to differ its execution, becasue we need to evaulate its formula and at this point in time the potential variables used at the formula are still not set. */ - announcement.value = value - announcementsToBeMade.push(announcement) + announcement.value = value + announcementsToBeMade.push(announcement) /* Next, we will remmeber this announcement was already done, so that it is not announced again in further processing of the same day. */ - if (newAnnouncementRecord.periods !== undefined) { - newAnnouncementRecord.periods = variable.episode.count.periods - newAnnouncementRecord.value = value - } else { - newAnnouncementRecord = { - key: key, - periods: variable.episode.count.periods, - value: value - } - variable.announcements.push(newAnnouncementRecord) + if (newAnnouncementRecord.periods !== undefined) { + newAnnouncementRecord.periods = variable.episode.count.periods + newAnnouncementRecord.value = value + } else { + newAnnouncementRecord = { + key: key, + periods: variable.episode.count.periods, + value: value + } + variable.announcements.push(newAnnouncementRecord) + } + } + } + } } - } - } - } - } - function makeAnnoucements () { + function makeAnnoucements() { /* Here we go through all the annoucements that need to be done during this loop, and we just do them. */ - for (let i = 0; i < announcementsToBeMade.length; i++) { - announcement = announcementsToBeMade[i] + for (let i = 0; i < announcementsToBeMade.length; i++) { + announcement = announcementsToBeMade[i] /* Here we check if there is a formula attached to the annoucement, we evaluate it to get the annoucement text. */ - let formulaValue - if (announcement.formula !== undefined) { - try { - let value = announcement.value - formulaValue = eval(announcement.formula.code) - } catch (err) { - announcement.formula.error = err.message - } - } - announcement.formulaValue = formulaValue + let formulaValue + if (announcement.formula !== undefined) { + try { + let value = announcement.value + formulaValue = eval(announcement.formula.code) + } catch (err) { + announcement.formula.error = err.message + } + } + announcement.formulaValue = formulaValue - if (bot.SESSION.socialBots !== undefined) { - bot.SESSION.socialBots.announce(announcement) - } - } - } - - function addCodeToSnapshot (code) { - if (code === undefined) { return } - - try { - let instructionsArray = code.split(' ') - for (let i = 0; i < instructionsArray.length; i++) { - let instruction = instructionsArray[i] - instruction = instruction.replace('(', '') - instruction = instruction.replace(')', '') - instruction = instruction.replace(//g, '') - instruction = instruction.replace(/<=/g, '') - instruction = instruction.replace(/>=/g, '') - instruction = instruction.replace(/!=/g, '') - instruction = instruction.replace(/!==/g, '') - instruction = instruction.replace(/==/g, '') - instruction = instruction.replace(/===/g, '') - instruction = instruction.replace(/{/g, '') - instruction = instruction.replace(/}/g, '') - if (instruction.indexOf('chart') >= 0) { - let parts = instruction.split('.') - let timeFrame = parts[1] - let product = parts[2] - let property - checkPrevious(3) - function checkPrevious (index) { - property = parts[index] - if (property === 'previous') { - product = product + '.previous' - checkPrevious(index + 1) - } + if (bot.SESSION.socialBots !== undefined) { + bot.SESSION.socialBots.announce(announcement) + } + } } + function addCodeToSnapshot(code) { + if (code === undefined) { return } + + try { + let instructionsArray = code.split(' ') + for (let i = 0; i < instructionsArray.length; i++) { + let instruction = instructionsArray[i] + instruction = instruction.replace('(', '') + instruction = instruction.replace(')', '') + instruction = instruction.replace(//g, '') + instruction = instruction.replace(/<=/g, '') + instruction = instruction.replace(/>=/g, '') + instruction = instruction.replace(/!=/g, '') + instruction = instruction.replace(/!==/g, '') + instruction = instruction.replace(/==/g, '') + instruction = instruction.replace(/===/g, '') + instruction = instruction.replace(/{/g, '') + instruction = instruction.replace(/}/g, '') + if (instruction.indexOf('chart') >= 0) { + let parts = instruction.split('.') + let variable.episode.parameters.timeFrame = parts[1] + let product = parts[2] + let property + checkPrevious(3) + function checkPrevious(index) { + property = parts[index] + if (property === 'previous') { + product = product + '.previous' + checkPrevious(index + 1) + } + } + // Example: chart.at01hs.popularSMA.sma200 - chart.at01hs.popularSMA.sma100 < 10 - if (timeFrame !== 'atAnyTimeFrame') { - timeFrame = timeFrame.substring(2, 4) + '-' + timeFrame.substring(4, 7) - } - let key = timeFrame + '-' + product + '-' + property - let existingKey = snapshotKeys.get(key) + if (variable.episode.parameters.timeFrame !== 'atAnyvariable.episode.parameters.timeFrame') { + variable.episode.parameters.timeFrame = variable.episode.parameters.timeFrame.substring(2, 4) + '-' + variable.episode.parameters.timeFrame.substring(4, 7) + } + let key = variable.episode.parameters.timeFrame + '-' + product + '-' + property + let existingKey = snapshotKeys.get(key) - if (existingKey === undefined) { // means that at the current loop this property of this product was not used before. - snapshotKeys.set(key, key) - snapshotLoopHeaders.push(key) + if (existingKey === undefined) { // means that at the current loop this property of this product was not used before. + snapshotKeys.set(key, key) + snapshotLoopHeaders.push(key) - let value = eval(instruction) - snapshotDataRecord.push(value) + let value = eval(instruction) + snapshotDataRecord.push(value) + } + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] runSimulation -> addCodeToSnapshot -> code = ' + code) + logger.write(MODULE_NAME, '[ERROR] runSimulation -> addCodeToSnapshot -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } } - } } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] runSimulation -> addCodeToSnapshot -> code = ' + code) - logger.write(MODULE_NAME, '[ERROR] runSimulation -> addCodeToSnapshot -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } - function controlLoop () { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> controlLoop -> Entering function.') } + function controlLoop() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> controlLoop -> Entering function.') } /* Checking if we should continue processing this loop or not. */ - if (bot.STOP_SESSION === true) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing this session.') } - console.log('[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing this session.') - afterLoop() - return - } + if (bot.STOP_SESSION === true) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing this session.') } + console.log('[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing this session.') + afterLoop() + return + } - if (global.STOP_TASK_GRACEFULLY === true) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing this task.') } - console.log('[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing this task.') - afterLoop() - return - } + if (global.STOP_TASK_GRACEFULLY === true) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing this task.') } + console.log('[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing this task.') + afterLoop() + return + } - currentCandleIndex++ - if (currentCandleIndex < candles.length) { - setImmediate(loop) // This will execute the next loop in the next iteration of the NodeJs event loop allowing for other callbacks to be executed. - } else { - afterLoop() - } - } + currentCandleIndex++ + if (currentCandleIndex < candles.length) { + setImmediate(loop) // This will execute the next loop in the next iteration of the NodeJs event loop allowing for other callbacks to be executed. + } else { + afterLoop() + } + } - function afterLoop () { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> afterLoop -> Entering function.') } + function afterLoop() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> afterLoop -> Entering function.') } /* Before returning we need to see if we have to record some of our counters at the variable. To do that, the condition to be met is that this execution must include all candles of the current day. */ - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> callback -> recordsArray.length = ' + recordsArray.length) } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> callback -> recordsArray.length = ' + recordsArray.length) } - callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, tradesArray, snapshots.headers, snapshots.triggerOn, snapshots.takePosition) - } + callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, positionsArray, snapshots.headers, snapshots.triggerOn, snapshots.takePosition) + } - function getElement (pArray, currentCandle, datasetName) { - if (pArray === undefined) { return } - try { - let element - for (let i = 0; i < pArray.length; i++) { - element = pArray[i] + function getElement(pArray, currentCandle, datasetName) { + if (pArray === undefined) { return } + try { + let element + for (let i = 0; i < pArray.length; i++) { + element = pArray[i] - if (currentCandle.end === element.end) { // when there is an exact match at the end we take that element - return element - } else { - if ( + if (currentCandle.end === element.end) { // when there is an exact match at the end we take that element + return element + } else { + if ( i > 0 && element.end > currentCandle.end ) { - let previousElement = pArray[i - 1] - if (previousElement.end < currentCandle.end) { - return previousElement // If one elements goes into the future of currentCandle, then we stop and take the previous element. - } else { - return - } - } - if ( + let previousElement = pArray[i - 1] + if (previousElement.end < currentCandle.end) { + return previousElement // If one elements goes into the future of currentCandle, then we stop and take the previous element. + } else { + return + } + } + if ( i === pArray.length - 1 // If we reach the end of the array, then we return the last element. && element.end < currentCandle.end ) { - return element - } + return element + } + } + } + return + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] runSimulation -> getElement -> datasetName = ' + datasetName) + logger.write(MODULE_NAME, '[ERROR] runSimulation -> getElement -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } } - } - return } catch (err) { - logger.write(MODULE_NAME, '[ERROR] runSimulation -> getElement -> datasetName = ' + datasetName) - logger.write(MODULE_NAME, '[ERROR] runSimulation -> getElement -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) + logger.write(MODULE_NAME, '[ERROR] runSimulation -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) } - } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] runSimulation -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) } - } } From fc0825758e0a5511d5f8bb4a315637c383338de9 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 20 May 2020 14:39:32 +0200 Subject: [PATCH 25/44] Debugged 10% --- TradingSimulation.js | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index be9153fbb..b7ccf0d39 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -32,7 +32,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT try { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> Entering function.') } let processingDailyFiles - if (variable.episode.parameters.timeFrame > global.dailyFilePeriods[0][0]) { + if (timeFrame > global.dailyFilePeriods[0][0]) { processingDailyFiles = false } else { processingDailyFiles = true @@ -105,11 +105,11 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.episode.parameters = {} // Parameters give you access to information received by the Simulation as parameters. variable.episode.parameters.initial = {} // Everything in here means the status at the begining of the episode received as a parameter of the Sumulation. - variable.episode.parameters.minimun = {} // Everything in here means the minimun in the whole episode received as a parameter of the Sumulation. - variable.episode.parameters.maximun = {} // Everything in here means the maximun in the whole episode received as a parameter of the Sumulation. + variable.episode.parameters.minimum = {} // Everything in here means the minimum in the whole episode received as a parameter of the Sumulation. + variable.episode.parameters.maximum = {} // Everything in here means the maximum in the whole episode received as a parameter of the Sumulation. variable.episode.parameters.initial.balance = {} - variable.episode.parameters.minimun.balance = {} - variable.episode.parameters.maximun.balance = {} + variable.episode.parameters.minimum.balance = {} + variable.episode.parameters.maximum.balance = {} variable.episode.parameters.baseAsset = bot.VALUES_TO_USE.baseAsset variable.episode.parameters.quotedAsset = bot.VALUES_TO_USE.quotedAsset @@ -287,7 +287,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } } - let propertyName = 'atAnyvariable.episode.parameters.timeFrame' + let propertyName = 'atAnyTimeFrame' let thisChart = chart[propertyName] for (let k = 0; k < dataDependencies.length; k++) { @@ -604,7 +604,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT addCodeToSnapshot(code) if (formulaValue === Infinity) { formulaValue = MAX_TAKE_PROFIT_VALUE - if (takeProfitStage === 'Open Stage') { + if (variable.current.position.takeProfitStage === 'Open Stage') { formulaError = 'WARNING: Formula evaluates to Infinity.' if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> initialDefinition.takeProfit -> MAX_TAKE_PROFIT_VALUE -> formulaError = ' + formulaError) } } @@ -621,7 +621,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (isNaN(formulaValue)) { formulaValue = 0 } if (formulaValue < MIN_TAKE_PROFIT_VALUE) { formulaValue = MIN_TAKE_PROFIT_VALUE - if (takeProfitStage === 'Open Stage') { + if (variable.current.position.takeProfitStage === 'Open Stage') { formulaError = 'WARNING: Formula is evaluating below the MIN_TAKE_PROFIT_VALUE.' if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> initialDefinition.takeProfit -> MIN_TAKE_PROFIT_VALUE -> formulaError = ' + formulaError) } } @@ -789,7 +789,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (formulaValue === Infinity) { formulaError = 'Formula evaluates to Infinity.' formulaValue = MAX_TAKE_PROFIT_VALUE - if (takeProfitStage === 'Manage Stage') { + if (variable.current.position.takeProfitStage === 'Manage Stage') { formulaError = 'WARNING: Formula evaluates to Infinity.' if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> manageStage.takeProfit -> MAX_TAKE_PROFIT_VALUE -> formulaError = ' + formulaError) } } @@ -806,7 +806,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (isNaN(formulaValue)) { formulaValue = 0 } if (formulaValue < MIN_TAKE_PROFIT_VALUE) { formulaValue = MIN_TAKE_PROFIT_VALUE - if (takeProfitStage === 'Manage Stage') { + if (variable.current.position.takeProfitStage === 'Manage Stage') { formulaError = 'WARNING: Formula is evaluating below the MIN_TAKE_PROFIT_VALUE.' if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> manageStage.takeProfit -> MIN_TAKE_PROFIT_VALUE -> formulaError = ' + formulaError) } } @@ -1289,7 +1289,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT let initialDefinitionKey = '' let p - if (takeProfitStage === 'Open Stage' && openStage !== undefined) { + if (variable.current.position.takeProfitStage === 'Open Stage' && openStage !== undefined) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.takeProfit !== undefined) { parentNode = openStage.initialDefinition @@ -1300,7 +1300,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } } - if (takeProfitStage === 'Manage Stage' && manageStage !== undefined) { + if (variable.current.position.takeProfitStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.takeProfit !== undefined) { parentNode = manageStage stageKey = 'manageStage' @@ -1408,7 +1408,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT let phase let key - if (takeProfitStage === 'Open Stage' && openStage !== undefined) { + if (variable.current.position.takeProfitStage === 'Open Stage' && openStage !== undefined) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.takeProfit !== undefined) { phase = openStage.initialDefinition.takeProfit.phases[takeProfitPhase] @@ -1417,7 +1417,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } } - if (takeProfitStage === 'Manage Stage' && manageStage !== undefined) { + if (variable.current.position.takeProfitStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.takeProfit !== undefined) { phase = manageStage.takeProfit.phases[takeProfitPhase - 1] key = variable.current.strategy.index + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 1) @@ -2348,7 +2348,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT instruction = instruction.replace(/}/g, '') if (instruction.indexOf('chart') >= 0) { let parts = instruction.split('.') - let variable.episode.parameters.timeFrame = parts[1] + let timeFrame = parts[1] let product = parts[2] let property checkPrevious(3) @@ -2361,10 +2361,10 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } // Example: chart.at01hs.popularSMA.sma200 - chart.at01hs.popularSMA.sma100 < 10 - if (variable.episode.parameters.timeFrame !== 'atAnyvariable.episode.parameters.timeFrame') { - variable.episode.parameters.timeFrame = variable.episode.parameters.timeFrame.substring(2, 4) + '-' + variable.episode.parameters.timeFrame.substring(4, 7) + if (timeFrame !== 'atAnyvariable.timeFrame') { + timeFrame = timeFrame.substring(2, 4) + '-' + timeFrame.substring(4, 7) } - let key = variable.episode.parameters.timeFrame + '-' + product + '-' + property + let key = timeFrame + '-' + product + '-' + property let existingKey = snapshotKeys.get(key) if (existingKey === undefined) { // means that at the current loop this property of this product was not used before. From 62ae81a93665ec26d9b66ad7cf9bd3645b567926 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 20 May 2020 14:56:36 +0200 Subject: [PATCH 26/44] more variable refactoring --- TradingSimulation.js | 184 ++++++++++++++++++++++--------------------- 1 file changed, 94 insertions(+), 90 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index b7ccf0d39..fbff629a9 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -144,39 +144,43 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } function inializeCurrentStrategy() { - variable.current.strategy = { - index: -1, - stage: 'No Stage', - begin: 0, - end: 0, - status: 0, - number: 0, - beginRate: 0, - endRate: 0, - situationName: '' - } + + variable.current.strategy.index = -1 + variable.current.strategy.stage = 'No Stage' + variable.current.strategy.begin = 0 + variable.current.strategy.end = 0 + variable.current.strategy.status = 0 + variable.current.strategy.number = 0 + variable.current.strategy.beginRate = 0 + variable.current.strategy.endRate = 0 + variable.current.strategy.situationName = '' + } function initializeCurrentPosition() { - variable.current.position = { - begin: 0, - end: 0, - rate: 0, - size: 0, - stopLoss: 0, - takeProfit: 0, - status: 0, - profit: 0, - exitType: 0, - beginRate: 0, - endRate: 0, - periods: 0, - situationName: '', - stopLossPhase: -1, - stopLossStage: 'No Stage', - takeProfitPhase: -1, - takeProfitStage: 'No Stage' - } + + variable.current.position.begin = 0 + variable.current.position.end = 0 + variable.current.position.rate = 0 + variable.current.position.size = 0 + variable.current.position.status = 0 + variable.current.position.profit = 0 + variable.current.position.exitType = 0 + variable.current.position.beginRate = 0 + variable.current.position.endRate = 0 + variable.current.position.periods = 0 + variable.current.position.situationName = '' + + variable.current.position.stopLoss = {} + variable.current.position.stopLoss.value = 0 + variable.current.position.stopLoss.phase = -1 + variable.current.position.stopLoss.stage = 'No Stage' + + variable.current.position.takeProfit = {} + variable.current.position.takeProfit.value = 0 + variable.current.position.takeProfit.phase = -1 + variable.current.position.takeProfit.stage = 'No Stage' + } /* Main Array and Maps */ @@ -516,7 +520,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (formulaValue === Infinity) { formulaError = 'Formula evaluates to Infinity.' formulaValue = MAX_STOP_LOSS_VALUE - if (variable.current.position.stopLossStage === 'Open Stage') { + if (variable.current.position.stopLoss.stage === 'Open Stage') { formulaError = 'WARNING: Formula evaluates to Infinity.' if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> initialDefinition.stopLoss -> MAX_STOP_LOSS_VALUE -> formulaError = ' + formulaError) } } @@ -533,7 +537,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (isNaN(formulaValue)) { formulaValue = 0 } if (formulaValue < MIN_STOP_LOSS_VALUE) { formulaValue = MIN_STOP_LOSS_VALUE - if (variable.current.position.stopLossStage === 'Open Stage') { + if (variable.current.position.stopLoss.stage === 'Open Stage') { formulaError = 'WARNING: Formula is evaluating below the MIN_STOP_LOSS_VALUE.' if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> initialDefinition.stopLoss -> MIN_STOP_LOSS_VALUE -> formulaError = ' + formulaError) } } @@ -604,7 +608,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT addCodeToSnapshot(code) if (formulaValue === Infinity) { formulaValue = MAX_TAKE_PROFIT_VALUE - if (variable.current.position.takeProfitStage === 'Open Stage') { + if (variable.current.position.takeProfit.stage === 'Open Stage') { formulaError = 'WARNING: Formula evaluates to Infinity.' if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> initialDefinition.takeProfit -> MAX_TAKE_PROFIT_VALUE -> formulaError = ' + formulaError) } } @@ -621,7 +625,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (isNaN(formulaValue)) { formulaValue = 0 } if (formulaValue < MIN_TAKE_PROFIT_VALUE) { formulaValue = MIN_TAKE_PROFIT_VALUE - if (variable.current.position.takeProfitStage === 'Open Stage') { + if (variable.current.position.takeProfit.stage === 'Open Stage') { formulaError = 'WARNING: Formula is evaluating below the MIN_TAKE_PROFIT_VALUE.' if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> initialDefinition.takeProfit -> MIN_TAKE_PROFIT_VALUE -> formulaError = ' + formulaError) } } @@ -701,7 +705,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (formulaValue === Infinity) { formulaError = '' formulaValue = MAX_STOP_LOSS_VALUE - if (variable.current.position.stopLossStage === 'Manage Stage') { + if (variable.current.position.stopLoss.stage === 'Manage Stage') { formulaError = 'WARNING: Formula evaluates to Infinity.' if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> manageStage.stopLoss -> MAX_STOP_LOSS_VALUE -> formulaError = ' + formulaError) } } @@ -718,7 +722,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (isNaN(formulaValue)) { formulaValue = 0 } if (formulaValue < MIN_STOP_LOSS_VALUE) { formulaValue = MIN_STOP_LOSS_VALUE - if (variable.current.position.stopLossStage === 'Manage Stage') { + if (variable.current.position.stopLoss.stage === 'Manage Stage') { formulaError = 'WARNING: Formula is evaluating below the MIN_STOP_LOSS_VALUE.' if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> manageStage.stopLoss -> MIN_STOP_LOSS_VALUE -> formulaError = ' + formulaError) } } @@ -789,7 +793,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (formulaValue === Infinity) { formulaError = 'Formula evaluates to Infinity.' formulaValue = MAX_TAKE_PROFIT_VALUE - if (variable.current.position.takeProfitStage === 'Manage Stage') { + if (variable.current.position.takeProfit.stage === 'Manage Stage') { formulaError = 'WARNING: Formula evaluates to Infinity.' if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> manageStage.takeProfit -> MAX_TAKE_PROFIT_VALUE -> formulaError = ' + formulaError) } } @@ -806,7 +810,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (isNaN(formulaValue)) { formulaValue = 0 } if (formulaValue < MIN_TAKE_PROFIT_VALUE) { formulaValue = MIN_TAKE_PROFIT_VALUE - if (variable.current.position.takeProfitStage === 'Manage Stage') { + if (variable.current.position.takeProfit.stage === 'Manage Stage') { formulaError = 'WARNING: Formula is evaluating below the MIN_TAKE_PROFIT_VALUE.' if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> loop -> manageStage.takeProfit -> MIN_TAKE_PROFIT_VALUE -> formulaError = ' + formulaError) } } @@ -1083,10 +1087,10 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.strategy.stage = 'Open Stage' checkAnnouncements(strategy.openStage) - variable.current.position.stopLossStage = 'Open Stage' - variable.current.position.takeProfitStage = 'Open Stage' - variable.current.position.stopLossPhase = 0 - variable.current.position.takeProfitPhase = 0 + variable.current.position.stopLoss.stage = 'Open Stage' + variable.current.position.takeProfit.stage = 'Open Stage' + variable.current.position.stopLoss.phase = 0 + variable.current.position.takeProfit.phase = 0 takePositionNow = true variable.current.position.situationName = situation.name @@ -1122,22 +1126,22 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT let initialDefinitionKey = '' let p - if (variable.current.position.stopLossStage === 'Open Stage' && openStage !== undefined) { + if (variable.current.position.stopLoss.stage === 'Open Stage' && openStage !== undefined) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.stopLoss !== undefined) { parentNode = openStage.initialDefinition initialDefinitionKey = '-' + 'initialDefinition' stageKey = 'openStage' - p = variable.current.position.stopLossPhase + p = variable.current.position.stopLoss.phase } } } - if (variable.current.position.stopLossStage === 'Manage Stage' && manageStage !== undefined) { + if (variable.current.position.stopLoss.stage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.stopLoss !== undefined) { parentNode = manageStage stageKey = 'manageStage' - p = variable.current.position.stopLossPhase - 1 + p = variable.current.position.stopLoss.phase - 1 } } @@ -1167,8 +1171,8 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } if (passed) { - variable.current.position.stopLossPhase++ - variable.current.position.stopLossStage = 'Manage Stage' + variable.current.position.stopLoss.phase++ + variable.current.position.stopLoss.stage = 'Manage Stage' if (takeProfitPhase > 0) { variable.current.strategy.stage = 'Manage Stage' checkAnnouncements(manageStage, 'Take Profit') @@ -1210,7 +1214,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (moveToPhase !== undefined) { for (let q = 0; q < parentNode.stopLoss.phases.length; q++) { if (parentNode.stopLoss.phases[q].id === moveToPhase.id) { - variable.current.position.stopLossPhase = q + 1 + variable.current.position.stopLoss.phase = q + 1 } } } else { @@ -1218,7 +1222,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT continue } - variable.current.position.stopLossStage = 'Manage Stage' + variable.current.position.stopLoss.stage = 'Manage Stage' if (takeProfitPhase > 0) { variable.current.strategy.stage = 'Manage Stage' checkAnnouncements(manageStage, 'Take Profit') @@ -1240,7 +1244,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT let phase let key - if (variable.current.position.stopLossStage === 'Open Stage' && openStage !== undefined) { + if (variable.current.position.stopLoss.stage === 'Open Stage' && openStage !== undefined) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.stopLoss !== undefined) { phase = openStage.initialDefinition.stopLoss.phases[stopLossPhase] @@ -1249,7 +1253,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } } - if (variable.current.position.stopLossStage === 'Manage Stage' && manageStage !== undefined) { + if (variable.current.position.stopLoss.stage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.stopLoss !== undefined) { phase = manageStage.stopLoss.phases[stopLossPhase - 1] key = variable.current.strategy.index + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + (stopLossPhase - 1) @@ -1258,12 +1262,12 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (phase !== undefined) { if (phase.formula !== undefined) { - let previousValue = variable.current.position.stopLoss + let previousValue = variable.current.position.stopLoss.value - variable.current.position.stopLoss = formulas.get(key) + variable.current.position.stopLoss.value = formulas.get(key) if (stopLoss !== previousValue) { - checkAnnouncements(phase, variable.current.position.stopLoss) + checkAnnouncements(phase, variable.current.position.stopLoss.value) } } } @@ -1289,22 +1293,22 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT let initialDefinitionKey = '' let p - if (variable.current.position.takeProfitStage === 'Open Stage' && openStage !== undefined) { + if (variable.current.position.takeProfit.stage === 'Open Stage' && openStage !== undefined) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.takeProfit !== undefined) { parentNode = openStage.initialDefinition initialDefinitionKey = '-' + 'initialDefinition' stageKey = 'openStage' - p = variable.current.position.takeProfitPhase + p = variable.current.position.takeProfit.phase } } } - if (variable.current.position.takeProfitStage === 'Manage Stage' && manageStage !== undefined) { + if (variable.current.position.takeProfit.stage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.takeProfit !== undefined) { parentNode = manageStage stageKey = 'manageStage' - p = variable.current.position.takeProfitPhase - 1 + p = variable.current.position.takeProfit.phase - 1 } } @@ -1335,8 +1339,8 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } if (passed) { - variable.current.position.takeProfitPhase++ - variable.current.position.takeProfitStage = 'Manage Stage' + variable.current.position.takeProfit.phase++ + variable.current.position.takeProfit.stage = 'Manage Stage' if (stopLossPhase > 0) { variable.current.strategy.stage = 'Manage Stage' checkAnnouncements(manageStage, 'Stop') @@ -1378,7 +1382,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (moveToPhase !== undefined) { for (let q = 0; q < parentNode.takeProfit.phases.length; q++) { if (parentNode.takeProfit.phases[q].id === moveToPhase.id) { - variable.current.position.takeProfitPhase = q + 1 + variable.current.position.takeProfit.phase = q + 1 } } } else { @@ -1386,7 +1390,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT continue } - variable.current.position.takeProfitStage = 'Manage Stage' + variable.current.position.takeProfit.stage = 'Manage Stage' if (stopLossPhase > 0) { variable.current.strategy.stage = 'Manage Stage' checkAnnouncements(manageStage, 'Stop') @@ -1408,7 +1412,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT let phase let key - if (variable.current.position.takeProfitStage === 'Open Stage' && openStage !== undefined) { + if (variable.current.position.takeProfit.stage === 'Open Stage' && openStage !== undefined) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.takeProfit !== undefined) { phase = openStage.initialDefinition.takeProfit.phases[takeProfitPhase] @@ -1417,7 +1421,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } } - if (variable.current.position.takeProfitStage === 'Manage Stage' && manageStage !== undefined) { + if (variable.current.position.takeProfit.stage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.takeProfit !== undefined) { phase = manageStage.takeProfit.phases[takeProfitPhase - 1] key = variable.current.strategy.index + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 1) @@ -1426,12 +1430,12 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (phase !== undefined) { if (phase.formula !== undefined) { - let previousValue = variable.current.position.stopLoss + let previousValue = variable.current.position.stopLoss.value - variable.current.position.takeProfit = formulas.get(key) + variable.current.position.takeProfit.value = formulas.get(key) if (takeProfit !== previousValue) { - checkAnnouncements(phase, variable.current.position.takeProfit) + checkAnnouncements(phase, variable.current.position.takeProfit.value) } } } @@ -1489,7 +1493,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - if ((variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset && candle.max >= variable.current.position.stopLoss) || (variable.episode.parameters.baseAsset !== variable.episode.parameters.marketBaseAsset && candle.min <= variable.current.position.stopLoss)) { + if ((variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset && candle.max >= variable.current.position.stopLoss.value) || (variable.episode.parameters.baseAsset !== variable.episode.parameters.marketBaseAsset && candle.min <= variable.current.position.stopLoss.value)) { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Stop Loss was hit.') } /* Hit Point Validation @@ -1500,15 +1504,15 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { if (stopLoss < candle.min) { - variable.current.position.stopLoss = candle.min + variable.current.position.stopLoss.value = candle.min } } else { if (stopLoss > candle.max) { - variable.current.position.stopLoss = candle.max + variable.current.position.stopLoss.value = candle.max } } - let slippedStopLoss = variable.current.position.stopLoss + let slippedStopLoss = variable.current.position.stopLoss.value /* Apply the Slippage */ let slippageAmount = slippedStopLoss * bot.VALUES_TO_USE.slippage.stopLoss / 100 @@ -1524,8 +1528,8 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.strategy.stage = 'Close Stage' checkAnnouncements(strategy.closeStage, 'Stop') - variable.current.position.stopLossStage = 'No Stage' - variable.current.position.takeProfitStage = 'No Stage' + variable.current.position.stopLoss.stage = 'No Stage' + variable.current.position.takeProfit.stage = 'No Stage' variable.current.position.end = candle.end variable.current.position.status = 1 variable.current.position.exitType = 1 @@ -1536,7 +1540,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT /* Take Profit condition: Here we verify if the Take Profit was hit or not. */ - if ((variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset && candle.min <= variable.current.position.takeProfit) || (variable.episode.parameters.baseAsset !== variable.episode.parameters.marketBaseAsset && candle.max >= variable.current.position.takeProfit)) { + if ((variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset && candle.min <= variable.current.position.takeProfit.value) || (variable.episode.parameters.baseAsset !== variable.episode.parameters.marketBaseAsset && candle.max >= variable.current.position.takeProfit.value)) { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Take Profit was hit.') } /* Hit Point Validation: @@ -1547,15 +1551,15 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { if (takeProfit > candle.max) { - variable.current.position.takeProfit = candle.max + variable.current.position.takeProfit.value = candle.max } } else { if (takeProfit < candle.min) { - variable.current.position.takeProfit = candle.min + variable.current.position.takeProfit.value = candle.min } } - let slippedTakeProfit = variable.current.position.takeProfit + let slippedTakeProfit = variable.current.position.takeProfit.value /* Apply the Slippage */ let slippageAmount = slippedTakeProfit * bot.VALUES_TO_USE.slippage.takeProfit / 100 @@ -1570,8 +1574,8 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.strategy.stage = 'Close Stage' checkAnnouncements(strategy.closeStage, 'Take Profit') - variable.current.position.stopLossStage = 'No Stage' - variable.current.position.takeProfitStage = 'No Stage' + variable.current.position.stopLoss.stage = 'No Stage' + variable.current.position.takeProfit.stage = 'No Stage' variable.current.position.end = candle.end variable.current.position.status = 1 @@ -2012,17 +2016,17 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT addRecord() - variable.current.position.stopLoss = 0 - variable.current.position.takeProfit = 0 + variable.current.position.stopLoss.value = 0 + variable.current.position.takeProfit.value = 0 variable.current.position.rate = 0 variable.current.position.size = 0 timerToCloseStage = candle.begin - variable.current.position.stopLossStage = 'No Stage' - variable.current.position.takeProfitStage = 'No Stage' - variable.current.position.stopLossPhase = -1 - variable.current.position.takeProfitPhase = -1 + variable.current.position.stopLoss.stage = 'No Stage' + variable.current.position.takeProfit.stage = 'No Stage' + variable.current.position.stopLoss.phase = -1 + variable.current.position.takeProfit.phase = -1 if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> closePositionAtSimulation -> Exiting Loop Body after closing position at simulation.') } controlLoop() @@ -2076,7 +2080,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT balanceQuotedAsset: variable.current.balance.quotedAsset, accumulatedProfitLoss: variable.episode.stat.profitLoss, lastTradeProfitLoss: variable.last.position.profitLoss, - stopLoss: variable.current.position.stopLoss, + stopLoss: variable.current.position.stopLoss.value, tradesCount: variable.episode.count.positions, hits: variable.episode.count.hits, fails: variable.episode.count.fails, @@ -2088,9 +2092,9 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT positionRate: variable.current.position.rate, lastTradeROI: variable.last.position.ROI, strategy: variable.current.strategy.index, - takeProfit: variable.current.position.takeProfit, - stopLossPhase: variable.current.position.stopLossPhase, - takeProfitPhase: variable.current.position.takeProfitPhase, + takeProfit: variable.current.position.takeProfit.value, + stopLossPhase: variable.current.position.stopLoss.phase, + takeProfitPhase: variable.current.position.takeProfit.phase, positionSize: variable.current.position.size, initialBalanceA: variable.episode.parameters.initial.balance.baseAsset, minimumBalanceA: variable.episode.parameters.minimum.balance.baseAsset, From 9f071082010809ca3724d1205802a0b233ba89b5 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 20 May 2020 16:23:05 +0200 Subject: [PATCH 27/44] Debugging several loops --- TradingBot.js | 8 ++-- TradingSimulation.js | 97 ++++++++++++++++++++++---------------------- 2 files changed, 52 insertions(+), 53 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index 8af541f99..4a71b8b6b 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -194,8 +194,8 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR record.lastTradeROI + ',' + record.strategy + ',' + record.takeProfit + ',' + - record.stopLossPhase + ',' + - record.takeProfitPhase + ',' + + record.variable_current_position_stopLoss_phase + ',' + + record.variable_current_position_stopLoss_phase + ',' + record.positionSize + ',' + record.initialBalanceA + ',' + record.minimumBalanceA + ',' + @@ -555,8 +555,8 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR record.lastTradeROI + ',' + record.strategy + ',' + record.takeProfit + ',' + - record.stopLossPhase + ',' + - record.takeProfitPhase + ',' + + record.variable_current_position_stopLoss_phase + ',' + + record.variable_current_position_stopLoss_phase + ',' + record.positionSize + ',' + record.initialBalanceA + ',' + record.minimumBalanceA + ',' + diff --git a/TradingSimulation.js b/TradingSimulation.js index fbff629a9..95045e46b 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -43,6 +43,15 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT let strategiesArray = [] let positionsArray = [] + /* Snapshots of Trigger On and Take Positions */ + let snapshots = { + headers: undefined, + triggerOn: [], + takePosition: [], + lastTriggerOn: undefined, + lastTakePosition: undefined + } + let tradingSystem = bot.TRADING_SYSTEM if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> bot.VALUES_TO_USE.timeRange.initialDatetime = ' + bot.VALUES_TO_USE.timeRange.initialDatetime) } @@ -954,8 +963,8 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT for (let j = 0; j < tradingSystem.strategies.length; j++) { if ( - strategyStage !== 'No Stage' || - currentStrategyIndex !== -1 + variable.current.strategy.stage !== 'No Stage' || + variable.current.strategy.index !== -1 ) { continue } let strategy = tradingSystem.strategies[j] @@ -1011,7 +1020,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT /* Trigger Off Condition */ if (variable.current.strategy.stage === 'Trigger Stage') { - let strategy = tradingSystem.strategies[strategyIndex] + let strategy = tradingSystem.strategies[variable.current.strategy.index] let triggerStage = strategy.triggerStage @@ -1058,7 +1067,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT /* Take Position Condition */ if (variable.current.strategy.stage === 'Trigger Stage') { - let strategy = tradingSystem.strategies[strategyIndex] + let strategy = tradingSystem.strategies[variable.current.strategy.index] let triggerStage = strategy.triggerStage @@ -1116,7 +1125,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } function checkStopPhases() { - let strategy = tradingSystem.strategies[strategyIndex] + let strategy = tradingSystem.strategies[variable.current.strategy.index] let openStage = strategy.openStage let manageStage = strategy.manageStage @@ -1173,7 +1182,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (passed) { variable.current.position.stopLoss.phase++ variable.current.position.stopLoss.stage = 'Manage Stage' - if (takeProfitPhase > 0) { + if (variable.current.position.takeProfit.phase > 0) { variable.current.strategy.stage = 'Manage Stage' checkAnnouncements(manageStage, 'Take Profit') } @@ -1223,7 +1232,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } variable.current.position.stopLoss.stage = 'Manage Stage' - if (takeProfitPhase > 0) { + if (variable.current.position.takeProfit.phase > 0) { variable.current.strategy.stage = 'Manage Stage' checkAnnouncements(manageStage, 'Take Profit') } @@ -1238,7 +1247,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } function calculateStopLoss() { - let strategy = tradingSystem.strategies[strategyIndex] + let strategy = tradingSystem.strategies[variable.current.strategy.index] let openStage = strategy.openStage let manageStage = strategy.manageStage let phase @@ -1247,16 +1256,16 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (variable.current.position.stopLoss.stage === 'Open Stage' && openStage !== undefined) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.stopLoss !== undefined) { - phase = openStage.initialDefinition.stopLoss.phases[stopLossPhase] - key = variable.current.strategy.index + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + (stopLossPhase) + phase = openStage.initialDefinition.stopLoss.phases[variable.current.position.stopLoss.phase] + key = variable.current.strategy.index + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + (variable.current.position.stopLoss.phase) } } } if (variable.current.position.stopLoss.stage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.stopLoss !== undefined) { - phase = manageStage.stopLoss.phases[stopLossPhase - 1] - key = variable.current.strategy.index + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + (stopLossPhase - 1) + phase = manageStage.stopLoss.phases[variable.current.position.stopLoss.phase - 1] + key = variable.current.strategy.index + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + (variable.current.position.stopLoss.phase - 1) } } @@ -1266,7 +1275,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.position.stopLoss.value = formulas.get(key) - if (stopLoss !== previousValue) { + if (variable.current.position.stopLoss.value !== previousValue) { checkAnnouncements(phase, variable.current.position.stopLoss.value) } } @@ -1283,7 +1292,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } function checkTakeProfitPhases() { - let strategy = tradingSystem.strategies[strategyIndex] + let strategy = tradingSystem.strategies[variable.current.strategy.index] let openStage = strategy.openStage let manageStage = strategy.manageStage @@ -1341,7 +1350,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (passed) { variable.current.position.takeProfit.phase++ variable.current.position.takeProfit.stage = 'Manage Stage' - if (stopLossPhase > 0) { + if (variable.current.position.stopLoss.phase > 0) { variable.current.strategy.stage = 'Manage Stage' checkAnnouncements(manageStage, 'Stop') } @@ -1391,7 +1400,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } variable.current.position.takeProfit.stage = 'Manage Stage' - if (stopLossPhase > 0) { + if (variable.current.position.stopLoss.phase > 0) { variable.current.strategy.stage = 'Manage Stage' checkAnnouncements(manageStage, 'Stop') } @@ -1406,7 +1415,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } function calculateTakeProfit() { - let strategy = tradingSystem.strategies[strategyIndex] + let strategy = tradingSystem.strategies[variable.current.strategy.index] let openStage = strategy.openStage let manageStage = strategy.manageStage let phase @@ -1415,16 +1424,16 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (variable.current.position.takeProfit.stage === 'Open Stage' && openStage !== undefined) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.takeProfit !== undefined) { - phase = openStage.initialDefinition.takeProfit.phases[takeProfitPhase] - key = variable.current.strategy.index + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + (takeProfitPhase) + phase = openStage.initialDefinition.takeProfit.phases[variable.current.position.takeProfit.phase] + key = variable.current.strategy.index + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + (variable.current.position.takeProfit.phase) } } } if (variable.current.position.takeProfit.stage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.takeProfit !== undefined) { - phase = manageStage.takeProfit.phases[takeProfitPhase - 1] - key = variable.current.strategy.index + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 1) + phase = manageStage.takeProfit.phases[variable.current.position.takeProfit.phase - 1] + key = variable.current.strategy.index + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (variable.current.position.takeProfit.phase - 1) } } @@ -1434,7 +1443,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.position.takeProfit.value = formulas.get(key) - if (takeProfit !== previousValue) { + if (variable.current.position.takeProfit.value !== previousValue) { checkAnnouncements(phase, variable.current.position.takeProfit.value) } } @@ -1486,7 +1495,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT (variable.current.strategy.stage === 'Open Stage' || variable.current.strategy.stage === 'Manage Stage') && takePositionNow !== true ) { - let strategy = tradingSystem.strategies[strategyIndex] + let strategy = tradingSystem.strategies[variable.current.strategy.index] /* Checking what happened since the last execution. We need to know if the Stop Loss or our Take Profit were hit. */ @@ -1503,11 +1512,11 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT */ if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - if (stopLoss < candle.min) { + if (variable.current.position.stopLoss.value < candle.min) { variable.current.position.stopLoss.value = candle.min } } else { - if (stopLoss > candle.max) { + if (variable.current.position.stopLoss.value > candle.max) { variable.current.position.stopLoss.value = candle.max } } @@ -1550,11 +1559,11 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT */ if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - if (takeProfit > candle.max) { + if (variable.current.position.takeProfit.value > candle.max) { variable.current.position.takeProfit.value = candle.max } } else { - if (takeProfit < candle.min) { + if (variable.current.position.takeProfit.value < candle.min) { variable.current.position.takeProfit.value = candle.min } } @@ -1598,7 +1607,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.distance.toEvent.takePosition = 1 /* Position size and rate */ - let strategy = tradingSystem.strategies[strategyIndex] + let strategy = tradingSystem.strategies[variable.current.strategy.index] variable.current.position.size = strategy.positionSize variable.current.position.rate = strategy.positionRate @@ -1829,7 +1838,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.distance.toEvent.closePosition = 1 /* Position size and rate */ - let strategy = tradingSystem.strategies[strategyIndex] + let strategy = tradingSystem.strategies[variable.current.strategy.index] if (currentCandleIndex > candles.length - 10) { /* Only at the last candles makes sense to check if we are in live mode or not. */ /* Check that we are in LIVE MODE */ @@ -1987,12 +1996,12 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { variable.last.position.profitLoss = variable.current.balance.baseAsset - variable.previous.balance.baseAsset variable.last.position.ROI = variable.last.position.profitLoss * 100 / variable.current.position.size - if (isNaN(lastTradeROI)) { variable.last.position.ROI = 0 } + if (isNaN(variable.last.position.ROI)) { variable.last.position.ROI = 0 } variable.episode.stat.profitLoss = variable.current.balance.baseAsset - variable.episode.parameters.initial.balance.baseAsset } else { variable.last.position.profitLoss = variable.current.balance.quotedAsset - variable.previous.balance.quotedAsset variable.last.position.ROI = variable.last.position.profitLoss * 100 / variable.current.position.size - if (isNaN(lastTradeROI)) { variable.last.position.ROI = 0 } + if (isNaN(variable.last.position.ROI)) { variable.last.position.ROI = 0 } variable.episode.stat.profitLoss = variable.current.balance.quotedAsset - variable.episode.parameters.initial.balance.quotedAsset } @@ -2093,8 +2102,8 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT lastTradeROI: variable.last.position.ROI, strategy: variable.current.strategy.index, takeProfit: variable.current.position.takeProfit.value, - stopLossPhase: variable.current.position.stopLoss.phase, - takeProfitPhase: variable.current.position.takeProfit.phase, + variable_current_position_stopLoss_phase: variable.current.position.stopLoss.phase, + variable_current_position_takeProfit_phase: variable.current.position.takeProfit.phase, positionSize: variable.current.position.size, initialBalanceA: variable.episode.parameters.initial.balance.baseAsset, minimumBalanceA: variable.episode.parameters.minimum.balance.baseAsset, @@ -2118,9 +2127,9 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT /* Prepare the information for the Conditions File */ - conditionsArrayRecord.push(strategyIndex) - conditionsArrayRecord.push(stopLossPhase) - conditionsArrayRecord.push(takeProfitPhase) + conditionsArrayRecord.push(variable.current.strategy.index) + conditionsArrayRecord.push(variable.current.position.stopLoss.phase) + conditionsArrayRecord.push(variable.current.position.takeProfit.phase) conditionsArrayRecord.push(conditionsArrayValues) conditionsArrayRecord.push(formulasErrors) conditionsArrayRecord.push(formulasValues) @@ -2183,9 +2192,9 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (addToSnapshots === true) { let closeValues = [ - roundtrips, // Trade Number + variable.episode.count.positions, // Position Number (new Date(candle.begin)).toISOString(), // Datetime - tradingSystem.strategies[currentStrategyIndex].name, // Strategy + tradingSystem.strategies[variable.current.strategy.index].name, // Strategy Name currentStrategy.triggerOnSituation, // Trigger On Situation currentTrade.takePositionSituation, // Take Position Situation hitOrFial(), // Result @@ -2194,7 +2203,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT ] function hitOrFial() { - if (lastTradeROI > 0) { return 'HIT' } else { return 'FAIL' } + if (variable.last.position.ROI > 0) { return 'HIT' } else { return 'FAIL' } } if (positionedAtYesterday === false) { @@ -2211,16 +2220,6 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT snapshots.headers = closeHeaders.concat(JSON.parse(JSON.stringify(snapshotLoopHeaders))) } - if (processingDailyFiles) { - if (positionedAtYesterday) { - yesterday.snapshots.headers = snapshots.headers - yesterday.snapshots.triggerOn = snapshots.triggerOn - yesterday.snapshots.takePosition = snapshots.takePosition - yesterday.snapshots.lastTriggerOn = snapshots.lastTriggerOn - yesterday.snapshots.lastTakePosition = snapshots.lastTakePosition - } - } - /* Prepare the information for the Trades File */ if (variable.current.position.begin !== 0 && variable.current.position.end !== 0) { let currentPositionRecord = { From 395bd4230c336dd762e11ce80fb00e7656fe306e Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 20 May 2020 16:56:01 +0200 Subject: [PATCH 28/44] Running without crashing --- TradingSimulation.js | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index 95045e46b..5cc2ae5c4 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -174,6 +174,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.position.size = 0 variable.current.position.status = 0 variable.current.position.profit = 0 + variable.current.position.ROI = 0 variable.current.position.exitType = 0 variable.current.position.beginRate = 0 variable.current.position.endRate = 0 @@ -2005,7 +2006,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.episode.stat.profitLoss = variable.current.balance.quotedAsset - variable.episode.parameters.initial.balance.quotedAsset } - variable.current.position.lastTradeROI = variable.last.position.ROI + variable.current.position.ROI = variable.last.position.ROI if (variable.last.position.profitLoss > 0) { variable.episode.count.hits++ @@ -2171,11 +2172,11 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.position.end = candle.end variable.current.position.endRate = candle.close - /* Here we will calculate the ongoing variable.episode.stat.ROI */ + /* Here we will calculate the ongoing ROI */ if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - variable.current.position.lastTradeROI = (variable.current.position.rate - candle.close) / variable.current.position.rate * 100 + variable.current.position.ROI = (variable.current.position.rate - candle.close) / variable.current.position.rate * 100 } else { - variable.current.position.lastTradeROI = (candle.close - variable.current.position.rate) / variable.current.position.rate * 100 + variable.current.position.ROI = (candle.close - variable.current.position.rate) / variable.current.position.rate * 100 } } @@ -2195,17 +2196,25 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.episode.count.positions, // Position Number (new Date(candle.begin)).toISOString(), // Datetime tradingSystem.strategies[variable.current.strategy.index].name, // Strategy Name - currentStrategy.triggerOnSituation, // Trigger On Situation - currentTrade.takePositionSituation, // Take Position Situation + variable.current.strategy.situationName, // Trigger On Situation + variable.current.position.situationName, // Take Position Situation hitOrFial(), // Result - lastTradeROI, // ROI - simulationRecord.type.replace(/"/g, '') // Exit Type + variable.last.position.ROI, // ROI + exitType() // Exit Type ] function hitOrFial() { if (variable.last.position.ROI > 0) { return 'HIT' } else { return 'FAIL' } } + function exitType() { + switch (variable.current.position.exitType) { + case 1: return 'Stop' + case 2: return 'Take Profit' + } + } + + if (positionedAtYesterday === false) { snapshots.triggerOn.push(closeValues.concat(snapshots.lastTriggerOn)) snapshots.takePosition.push(closeValues.concat(snapshots.lastTakePosition)) @@ -2226,7 +2235,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT begin: variable.current.position.begin, end: variable.current.position.end, status: variable.current.position.status, - lastTradeROI: variable.current.position.lastTradeROI, + lastTradeROI: variable.current.position.ROI, exitType: variable.current.position.exitType, beginRate: variable.current.position.beginRate, endRate: variable.current.position.endRate, From ff9cc8012f7bd029f8fcc91af0bf2ce176f6839f Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 20 May 2020 18:49:02 +0200 Subject: [PATCH 29/44] Refactoring all records --- TradingBot.js | 202 +++++++++++++++++++++---------------------- TradingSimulation.js | 88 ++++++++++--------- 2 files changed, 147 insertions(+), 143 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index 4a71b8b6b..e74a06eb6 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -120,7 +120,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR let recordsArray let conditionsArray let strategiesArray - let tradesArray + let positionsArray let snapshotHeaders let triggerOnSnapshot @@ -139,12 +139,12 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR writeFiles, callBackFunction) - function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pSnapshotHeaders, pTriggerOnSnapshot, pTakePositionSnapshot) { + function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pPositionsArray, pSnapshotHeaders, pTriggerOnSnapshot, pTakePositionSnapshot) { tradingSystem = pTradingSystem recordsArray = pRecordsArray conditionsArray = pConditionsArray strategiesArray = pStrategiesArray - tradesArray = pTradesArray + positionsArray = pPositionsArray snapshotHeaders = pSnapshotHeaders triggerOnSnapshot = pTriggerOnSnapshot @@ -177,42 +177,42 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR fileContent = fileContent + separator + '[' + record.begin + ',' + record.end + ',' + - record.balanceBaseAsset + ',' + - record.balanceQuotedAsset + ',' + - record.accumulatedProfitLoss + ',' + - record.lastTradeProfitLoss + ',' + - record.stopLoss + ',' + - record.tradesCount + ',' + - record.hits + ',' + - record.fails + ',' + - record.hitRatio + ',' + - record.ROI + ',' + - record.periods + ',' + - record.days + ',' + - record.anualizedRateOfReturn + ',' + - record.positionRate + ',' + - record.lastTradeROI + ',' + - record.strategy + ',' + - record.takeProfit + ',' + + record.variable_current_balance_baseAsset + ',' + + record.variable_current_balance_quotedAsset + ',' + + record.variable_episode_stat_profitLoss + ',' + + record.variable_last_position_profitLoss + ',' + + record.variable_current_position_stopLoss_value + ',' + + record.variable_episode_count_positions + ',' + + record.variable_episode_count_hits + ',' + + record.variable_episode_count_fails + ',' + + record.variable_episode_stat_hitRatio + ',' + + record.variable_episode_stat_ROI + ',' + + record.variable_episode_count_periods + ',' + + record.variable_episode_stat_days + ',' + + record.variable_episode_stat_anualizedRateOfReturn + ',' + + record.variable_current_position_rate + ',' + + record.variable_last_position_ROI + ',' + + record.variable_current_strategy_index + ',' + + record.variable_current_position_takeProfit_value + ',' + record.variable_current_position_stopLoss_phase + ',' + record.variable_current_position_stopLoss_phase + ',' + - record.positionSize + ',' + - record.initialBalanceA + ',' + - record.minimumBalanceA + ',' + - record.maximumBalanceA + ',' + - record.initialBalanceB + ',' + - record.minimumBalanceB + ',' + - record.maximumBalanceB + ',' + - record.baseAsset + ',' + - record.quotedAsset + ',' + - record.marketBaseAsset + ',' + - record.marketQuotedAsset + ',' + - record.positionPeriods + ',' + - record.positionDays + ',' + - record.distanceToLastTriggerOn + ',' + - record.distanceToLastTriggerOff + ',' + - record.distanceToLastTakePosition + ',' + - record.distanceToLastClosePosition + ']' + record.variable_current_position_size + ',' + + record.variable_episode_parameters_initial_balance_baseAsset + ',' + + record.variable_episode_parameters_minimum_balance_baseAsset + ',' + + record.variable_episode_parameters_maximum_balance_baseAsset + ',' + + record.variable_episode_parameters_initial_balance_quotedAsset + ',' + + record.variable_episode_parameters_minimum_balance_quotedAsset + ',' + + record.variable_episode_parameters_maximum_balance_quotedAsset + ',' + + record.variable_episode_parameters_baseAsset + ',' + + record.variable_episode_parameters_quotedAsset + ',' + + record.variable_episode_parameters_marketBaseAsset + ',' + + record.variable_episode_parameters_marketQuotedAsset + ',' + + record.variable_current_position_periods + ',' + + record.variable_current_position_days + ',' + + record.variable_current_distance_toEvent_triggerOn + ',' + + record.variable_current_distance_toEvent_triggerOff + ',' + + record.variable_current_distance_toEvent_takePosition + ',' + + record.variable_current_distance_toEvent_closePosition + ']' if (separator === '') { separator = ',' } @@ -338,7 +338,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR record.number + ',' + record.beginRate + ',' + record.endRate + ',' + - '"' + record.triggerOnSituation + '"' + ',' + + '"' + record.situationName + '"' + ',' + '"' + record.name + '"' + ']' if (separator === '') { separator = ',' } @@ -368,7 +368,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR return } - writeTradesFile() + writePositionsFile() } catch (err) { logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> err = ' + err.stack) callBackFunction(global.DEFAULT_FAIL_RESPONSE) @@ -380,28 +380,28 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR } } - function writeTradesFile() { + function writePositionsFile() { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeTradesFile -> Entering function.') } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writePositionsFile -> Entering function.') } let separator = '' let fileRecordCounter = 0 let fileContent = '' - for (let i = 0; i < tradesArray.length; i++) { - let record = tradesArray[i] + for (let i = 0; i < positionsArray.length; i++) { + let record = positionsArray[i] if (record.stopRate === undefined) { record.stopRate = 0 } fileContent = fileContent + separator + '[' + record.begin + ',' + record.end + ',' + record.status + ',' + - record.lastTradeROI + ',' + + record.ROI + ',' + record.beginRate + ',' + record.endRate + ',' + record.exitType + ',' + - '"' + record.takePositionSituation + '"' + ']' + '"' + record.situationName + '"' + ']' if (separator === '') { separator = ',' } @@ -418,13 +418,13 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR function onFileCreated(err) { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> Entering function.') } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> fileContent = ' + fileContent) } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writePositionsFile -> onFileCreated -> Entering function.') } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writePositionsFile -> onFileCreated -> fileContent = ' + fileContent) } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writePositionsFile -> onFileCreated -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writePositionsFile -> onFileCreated -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writePositionsFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) callBackFunction(err) return @@ -432,12 +432,12 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR writeSnapshotFiles() } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writePositionsFile -> onFileCreated -> err = ' + err.stack) callBackFunction(global.DEFAULT_FAIL_RESPONSE) } } } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writeTradesFile -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> writeMarketFiles -> writePositionsFile -> err = ' + err.stack) callBackFunction(global.DEFAULT_FAIL_RESPONSE) } } @@ -538,42 +538,42 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR fileContent = fileContent + separator + '[' + record.begin + ',' + record.end + ',' + - record.balanceBaseAsset + ',' + - record.balanceQuotedAsset + ',' + - record.accumulatedProfitLoss + ',' + - record.lastTradeProfitLoss + ',' + - record.stopLoss + ',' + - record.tradesCount + ',' + - record.hits + ',' + - record.fails + ',' + - record.hitRatio + ',' + - record.ROI + ',' + - record.periods + ',' + - record.days + ',' + - record.anualizedRateOfReturn + ',' + - record.positionRate + ',' + - record.lastTradeROI + ',' + - record.strategy + ',' + - record.takeProfit + ',' + + record.variable_current_balance_baseAsset + ',' + + record.variable_current_balance_quotedAsset + ',' + + record.variable_episode_stat_profitLoss + ',' + + record.variable_last_position_profitLoss + ',' + + record.variable_current_position_stopLoss_value + ',' + + record.variable_episode_count_positions + ',' + + record.variable_episode_count_hits + ',' + + record.variable_episode_count_fails + ',' + + record.variable_episode_stat_hitRatio + ',' + + record.variable_episode_stat_ROI + ',' + + record.variable_episode_count_periods + ',' + + record.variable_episode_stat_days + ',' + + record.variable_episode_stat_anualizedRateOfReturn + ',' + + record.variable_current_position_rate + ',' + + record.variable_last_position_ROI + ',' + + record.variable_current_strategy_index + ',' + + record.variable_current_position_takeProfit_value + ',' + record.variable_current_position_stopLoss_phase + ',' + record.variable_current_position_stopLoss_phase + ',' + - record.positionSize + ',' + - record.initialBalanceA + ',' + - record.minimumBalanceA + ',' + - record.maximumBalanceA + ',' + - record.initialBalanceB + ',' + - record.minimumBalanceB + ',' + - record.maximumBalanceB + ',' + - record.baseAsset + ',' + - record.quotedAsset + ',' + - record.marketBaseAsset + ',' + - record.marketQuotedAsset + ',' + - record.positionPeriods + ',' + - record.positionDays + ',' + - record.distanceToLastTriggerOn + ',' + - record.distanceToLastTriggerOff + ',' + - record.distanceToLastTakePosition + ',' + - record.distanceToLastClosePosition + ']' + record.variable_current_position_size + ',' + + record.variable_episode_parameters_initial_balance_baseAsset + ',' + + record.variable_episode_parameters_minimum_balance_baseAsset + ',' + + record.variable_episode_parameters_maximum_balance_baseAsset + ',' + + record.variable_episode_parameters_initial_balance_quotedAsset + ',' + + record.variable_episode_parameters_minimum_balance_quotedAsset + ',' + + record.variable_episode_parameters_maximum_balance_quotedAsset + ',' + + record.variable_episode_parameters_baseAsset + ',' + + record.variable_episode_parameters_quotedAsset + ',' + + record.variable_episode_parameters_marketBaseAsset + ',' + + record.variable_episode_parameters_marketQuotedAsset + ',' + + record.variable_current_position_periods + ',' + + record.variable_current_position_days + ',' + + record.variable_current_distance_toEvent_triggerOn + ',' + + record.variable_current_distance_toEvent_triggerOff + ',' + + record.variable_current_distance_toEvent_takePosition + ',' + + record.variable_current_distance_toEvent_closePosition + ']' if (separator === '') { separator = ',' } @@ -714,7 +714,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR record.number + ',' + record.beginRate + ',' + record.endRate + ',' + - '"' + record.triggerOnSituation + '"' + ',' + + '"' + record.situationName + '"' + ',' + '"' + record.name + '"' + ']' if (separator === '') { separator = ',' } @@ -745,7 +745,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR return } - writeTradesFile() + writePositionsFile() } catch (err) { logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> err = ' + err.stack) callBackFunction(global.DEFAULT_FAIL_RESPONSE) @@ -757,17 +757,17 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR } } - function writeTradesFile() { + function writePositionsFile() { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeTradesFile -> Entering function.') } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writePositionsFile -> Entering function.') } let separator = '' let fileRecordCounter = 0 let fileContent = '' - for (let i = 0; i < tradesArray.length; i++) { - let record = tradesArray[i] + for (let i = 0; i < positionsArray.length; i++) { + let record = positionsArray[i] /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends at the current date. */ @@ -779,11 +779,11 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR record.begin + ',' + record.end + ',' + record.status + ',' + - record.lastTradeROI + ',' + + record.ROI + ',' + record.beginRate + ',' + record.endRate + ',' + record.exitType + ',' + - '"' + record.takePositionSituation + '"' + ']' + '"' + record.situationName + '"' + ']' if (separator === '') { separator = ',' } @@ -801,13 +801,13 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR function onFileCreated(err) { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> Entering function.') } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> fileContent = ' + fileContent) } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writePositionsFile -> onFileCreated -> Entering function.') } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writePositionsFile -> onFileCreated -> fileContent = ' + fileContent) } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writePositionsFile -> onFileCreated -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writePositionsFile -> onFileCreated -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writePositionsFile -> onFileCreated -> market = ' + market.baseAsset + '_' + market.quotedAsset) callBackFunction(err) return @@ -815,12 +815,12 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR writeSnapshotFiles() } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writePositionsFile -> onFileCreated -> err = ' + err.stack) callBackFunction(global.DEFAULT_FAIL_RESPONSE) } } } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writeTradesFile -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> writeDailyFiles -> writePositionsFile -> err = ' + err.stack) callBackFunction(global.DEFAULT_FAIL_RESPONSE) } } diff --git a/TradingSimulation.js b/TradingSimulation.js index 5cc2ae5c4..b79982219 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -154,6 +154,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT function inializeCurrentStrategy() { + variable.current.strategy.name = '' variable.current.strategy.index = -1 variable.current.strategy.stage = 'No Stage' variable.current.strategy.begin = 0 @@ -179,6 +180,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.position.beginRate = 0 variable.current.position.endRate = 0 variable.current.position.periods = 0 + variable.current.position.days = 0 variable.current.position.situationName = '' variable.current.position.stopLoss = {} @@ -381,7 +383,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT let conditions = new Map() // Here we store the conditions values that will be use in the simulator for decision making. let formulas = new Map() let conditionsArrayRecord = [] // These are the records that will be saved in a file for the plotter to consume. - let conditionsArrayValues = [] // Here we store the conditions values that will be written on file for the plotter. + let conditionsValues = [] // Here we store the conditions values that will be written on file for the plotter. let formulasErrors = [] // Here we store the errors produced by all phase formulas. let formulasValues = [] // Here we store the values produced by all phase formulas. @@ -910,9 +912,9 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT conditions.set(condition.key, condition) if (condition.value) { - conditionsArrayValues.push(1) + conditionsValues.push(1) } else { - conditionsArrayValues.push(0) + conditionsValues.push(0) } } } @@ -1004,6 +1006,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.strategy.beginRate = candle.min variable.current.strategy.endRate = candle.min // In case the strategy does not get exited variable.current.strategy.situationName = situation.name + variable.current.strategy.name = strategy.name variable.current.distance.toEvent.triggerOn = 1 @@ -1460,10 +1463,10 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } variable.current.position.periods++ - variable.positionDays = variable.current.position.periods * variable.episode.parameters.timeFrame / ONE_DAY_IN_MILISECONDS + variable.current.position.days = variable.current.position.periods * variable.episode.parameters.timeFrame / ONE_DAY_IN_MILISECONDS } else { variable.current.position.periods = 0 - variable.positionDays = 0 + variable.current.position.days = 0 } /* Keeping Distance Counters Up-to-date */ @@ -2086,42 +2089,42 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT simulationRecord = { begin: candle.begin, end: candle.end, - balanceBaseAsset: variable.current.balance.baseAsset, - balanceQuotedAsset: variable.current.balance.quotedAsset, - accumulatedProfitLoss: variable.episode.stat.profitLoss, - lastTradeProfitLoss: variable.last.position.profitLoss, - stopLoss: variable.current.position.stopLoss.value, - tradesCount: variable.episode.count.positions, - hits: variable.episode.count.hits, - fails: variable.episode.count.fails, - hitRatio: variable.episode.stat.hitRatio, - ROI: variable.episode.stat.ROI, - periods: variable.episode.count.periods, - days: variable.episode.stat.days, - anualizedRateOfReturn: variable.episode.stat.anualizedRateOfReturn, - positionRate: variable.current.position.rate, - lastTradeROI: variable.last.position.ROI, - strategy: variable.current.strategy.index, - takeProfit: variable.current.position.takeProfit.value, + variable_current_balance_baseAsset: variable.current.balance.baseAsset, + variable_current_balance_quotedAsset: variable.current.balance.quotedAsset, + variable_episode_stat_profitLoss: variable.episode.stat.profitLoss, + variable_last_position_profitLoss: variable.last.position.profitLoss, + variable_current_position_stopLoss_value: variable.current.position.stopLoss.value, + variable_episode_count_positions: variable.episode.count.positions, + variable_episode_count_hits: variable.episode.count.hits, + variable_episode_count_fails: variable.episode.count.fails, + variable_episode_stat_hitRatio: variable.episode.stat.hitRatio, + variable_episode_stat_ROI: variable.episode.stat.ROI, + variable_episode_count_periods: variable.episode.count.periods, + variable_episode_stat_days: variable.episode.stat.days, + variable_episode_stat_anualizedRateOfReturn: variable.episode.stat.anualizedRateOfReturn, + variable_current_position_rate: variable.current.position.rate, + variable_last_position_ROI: variable.last.position.ROI, + variable_current_strategy_index: variable.current.strategy.index, + variable_current_position_takeProfit_value: variable.current.position.takeProfit.value, variable_current_position_stopLoss_phase: variable.current.position.stopLoss.phase, variable_current_position_takeProfit_phase: variable.current.position.takeProfit.phase, - positionSize: variable.current.position.size, - initialBalanceA: variable.episode.parameters.initial.balance.baseAsset, - minimumBalanceA: variable.episode.parameters.minimum.balance.baseAsset, - maximumBalanceA: variable.episode.parameters.maximum.balance.baseAsset, - initialBalanceB: variable.episode.parameters.initial.balance.quotedAsset, - minimumBalanceB: variable.episode.parameters.minimum.balance.quotedAsset, - maximumBalanceB: variable.episode.parameters.maximum.balance.quotedAsset, - baseAsset: '"' + variable.episode.parameters.baseAsset + '"', - quotedAsset: '"' + variable.episode.parameters.quotedAsset + '"', - marketBaseAsset: '"' + variable.episode.parameters.marketBaseAsset + '"', - marketQuotedAsset: '"' + variable.episode.parameters.marketQuotedAsset + '"', - positionPeriods: variable.current.position.periods, - positionDays: variable.positionDays, - distanceToEventTriggerOn: variable.current.distance.toEvent.triggerOn, - distanceToEventTriggerOff: variable.current.distance.toEvent.triggerOff, - distanceToEventTakePosition: variable.current.distance.toEvent.takePosition, - distanceToEventClosePosition: variable.current.distance.toEvent.closePosition + variable_current_position_size: variable.current.position.size, + variable_episode_parameters_initial_balance_baseAsset: variable.episode.parameters.initial.balance.baseAsset, + variable_episode_parameters_minimum_balance_baseAsset: variable.episode.parameters.minimum.balance.baseAsset, + variable_episode_parameters_maximum_balance_baseAsset: variable.episode.parameters.maximum.balance.baseAsset, + variable_episode_parameters_initial_balance_quotedAsset: variable.episode.parameters.initial.balance.quotedAsset, + variable_episode_parameters_minimum_balance_quotedAsset: variable.episode.parameters.minimum.balance.quotedAsset, + variable_episode_parameters_maximum_balance_quotedAsset: variable.episode.parameters.maximum.balance.quotedAsset, + variable_episode_parameters_baseAsset: '"' + variable.episode.parameters.baseAsset + '"', + variable_episode_parameters_quotedAsset: '"' + variable.episode.parameters.quotedAsset + '"', + variable_episode_parameters_marketBaseAsset: '"' + variable.episode.parameters.marketBaseAsset + '"', + variable_episode_parameters_marketQuotedAsset: '"' + variable.episode.parameters.marketQuotedAsset + '"', + variable_current_position_periods: variable.current.position.periods, + variable_current_position_days: variable.current.position.days, + variable_current_distance_toEvent_triggerOn: variable.current.distance.toEvent.triggerOn, + variable_current_distance_toEvent_triggerOff: variable.current.distance.toEvent.triggerOff, + variable_current_distance_toEvent_takePosition: variable.current.distance.toEvent.takePosition, + variable_current_distance_toEvent_closePosition: variable.current.distance.toEvent.closePosition } recordsArray.push(simulationRecord) @@ -2131,7 +2134,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT conditionsArrayRecord.push(variable.current.strategy.index) conditionsArrayRecord.push(variable.current.position.stopLoss.phase) conditionsArrayRecord.push(variable.current.position.takeProfit.phase) - conditionsArrayRecord.push(conditionsArrayValues) + conditionsArrayRecord.push(conditionsValues) conditionsArrayRecord.push(formulasErrors) conditionsArrayRecord.push(formulasValues) @@ -2155,7 +2158,8 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT number: variable.current.strategy.number, beginRate: variable.current.strategy.beginRate, endRate: variable.current.strategy.endRate, - situationName: variable.current.strategy.situationName + situationName: variable.current.strategy.situationName, + name: variable.current.strategy.name } strategiesArray.push(currentStrategyRecord) @@ -2235,7 +2239,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT begin: variable.current.position.begin, end: variable.current.position.end, status: variable.current.position.status, - lastTradeROI: variable.current.position.ROI, + ROI: variable.current.position.ROI, exitType: variable.current.position.exitType, beginRate: variable.current.position.beginRate, endRate: variable.current.position.endRate, From 2d052a1fd8b380323fae79148cec0a631639f559 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 20 May 2020 19:00:46 +0200 Subject: [PATCH 30/44] Update TradingSimulation.js --- TradingSimulation.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index b79982219..e28dcb675 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -174,7 +174,6 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.position.rate = 0 variable.current.position.size = 0 variable.current.position.status = 0 - variable.current.position.profit = 0 variable.current.position.ROI = 0 variable.current.position.exitType = 0 variable.current.position.beginRate = 0 @@ -183,6 +182,8 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.position.days = 0 variable.current.position.situationName = '' + variable.current.position.stat = {} + variable.current.position.stopLoss = {} variable.current.position.stopLoss.value = 0 variable.current.position.stopLoss.phase = -1 From fe550c235d28a8b20e2b59a0a3a18446574834fa Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 20 May 2020 19:36:23 +0200 Subject: [PATCH 31/44] Running WHB with things to fix --- TradingBot.js | 8 ++++---- TradingSimulation.js | 30 ++++++++++++++++-------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index e74a06eb6..8340f8a2c 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -207,8 +207,8 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR record.variable_episode_parameters_quotedAsset + ',' + record.variable_episode_parameters_marketBaseAsset + ',' + record.variable_episode_parameters_marketQuotedAsset + ',' + - record.variable_current_position_periods + ',' + - record.variable_current_position_days + ',' + + record.variable_current_position_count_periods + ',' + + record.variable_current_position_stat_days + ',' + record.variable_current_distance_toEvent_triggerOn + ',' + record.variable_current_distance_toEvent_triggerOff + ',' + record.variable_current_distance_toEvent_takePosition + ',' + @@ -568,8 +568,8 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR record.variable_episode_parameters_quotedAsset + ',' + record.variable_episode_parameters_marketBaseAsset + ',' + record.variable_episode_parameters_marketQuotedAsset + ',' + - record.variable_current_position_periods + ',' + - record.variable_current_position_days + ',' + + record.variable_current_position_count_periods + ',' + + record.variable_current_position_stat_days + ',' + record.variable_current_distance_toEvent_triggerOn + ',' + record.variable_current_distance_toEvent_triggerOff + ',' + record.variable_current_distance_toEvent_takePosition + ',' + diff --git a/TradingSimulation.js b/TradingSimulation.js index e28dcb675..4d301209b 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -174,15 +174,17 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.position.rate = 0 variable.current.position.size = 0 variable.current.position.status = 0 - variable.current.position.ROI = 0 variable.current.position.exitType = 0 variable.current.position.beginRate = 0 variable.current.position.endRate = 0 - variable.current.position.periods = 0 - variable.current.position.days = 0 variable.current.position.situationName = '' variable.current.position.stat = {} + variable.current.position.stat.ROI = 0 + variable.current.position.stat.days = 0 + + variable.current.position.count = {} + variable.current.position.count.periods = 0 variable.current.position.stopLoss = {} variable.current.position.stopLoss.value = 0 @@ -1460,14 +1462,14 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT (variable.current.strategy.stage === 'Open Stage' || variable.current.strategy.stage === 'Manage Stage') ) { if (takePositionNow === true) { - variable.current.position.periods = 0 + variable.current.position.count.periods = 0 } - variable.current.position.periods++ - variable.current.position.days = variable.current.position.periods * variable.episode.parameters.timeFrame / ONE_DAY_IN_MILISECONDS + variable.current.position.count.periods++ + variable.current.position.stat.days = variable.current.position.count.periods * variable.episode.parameters.timeFrame / ONE_DAY_IN_MILISECONDS } else { - variable.current.position.periods = 0 - variable.current.position.days = 0 + variable.current.position.count.periods = 0 + variable.current.position.stat.days = 0 } /* Keeping Distance Counters Up-to-date */ @@ -2010,7 +2012,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.episode.stat.profitLoss = variable.current.balance.quotedAsset - variable.episode.parameters.initial.balance.quotedAsset } - variable.current.position.ROI = variable.last.position.ROI + variable.current.position.stat.ROI = variable.last.position.ROI if (variable.last.position.profitLoss > 0) { variable.episode.count.hits++ @@ -2120,8 +2122,8 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable_episode_parameters_quotedAsset: '"' + variable.episode.parameters.quotedAsset + '"', variable_episode_parameters_marketBaseAsset: '"' + variable.episode.parameters.marketBaseAsset + '"', variable_episode_parameters_marketQuotedAsset: '"' + variable.episode.parameters.marketQuotedAsset + '"', - variable_current_position_periods: variable.current.position.periods, - variable_current_position_days: variable.current.position.days, + variable_current_position_count_periods: variable.current.position.count.periods, + variable_current_position_stat_days: variable.current.position.stat.days, variable_current_distance_toEvent_triggerOn: variable.current.distance.toEvent.triggerOn, variable_current_distance_toEvent_triggerOff: variable.current.distance.toEvent.triggerOff, variable_current_distance_toEvent_takePosition: variable.current.distance.toEvent.takePosition, @@ -2179,9 +2181,9 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT /* Here we will calculate the ongoing ROI */ if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - variable.current.position.ROI = (variable.current.position.rate - candle.close) / variable.current.position.rate * 100 + variable.current.position.stat.ROI = (variable.current.position.rate - candle.close) / variable.current.position.rate * 100 } else { - variable.current.position.ROI = (candle.close - variable.current.position.rate) / variable.current.position.rate * 100 + variable.current.position.stat.ROI = (candle.close - variable.current.position.rate) / variable.current.position.rate * 100 } } @@ -2240,7 +2242,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT begin: variable.current.position.begin, end: variable.current.position.end, status: variable.current.position.status, - ROI: variable.current.position.ROI, + ROI: variable.current.position.stat.ROI, exitType: variable.current.position.exitType, beginRate: variable.current.position.beginRate, endRate: variable.current.position.endRate, From 543c8134ecd6ebb12b8bcf36f7be43faec82b8c4 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 21 May 2020 11:01:57 +0200 Subject: [PATCH 32/44] Cleaning --- TradingBot.js | 14 ++------------ TradingSimulation.js | 7 +------ 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index 8340f8a2c..c971aa23f 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -192,7 +192,6 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR record.variable_episode_stat_anualizedRateOfReturn + ',' + record.variable_current_position_rate + ',' + record.variable_last_position_ROI + ',' + - record.variable_current_strategy_index + ',' + record.variable_current_position_takeProfit_value + ',' + record.variable_current_position_stopLoss_phase + ',' + record.variable_current_position_stopLoss_phase + ',' + @@ -208,11 +207,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR record.variable_episode_parameters_marketBaseAsset + ',' + record.variable_episode_parameters_marketQuotedAsset + ',' + record.variable_current_position_count_periods + ',' + - record.variable_current_position_stat_days + ',' + - record.variable_current_distance_toEvent_triggerOn + ',' + - record.variable_current_distance_toEvent_triggerOff + ',' + - record.variable_current_distance_toEvent_takePosition + ',' + - record.variable_current_distance_toEvent_closePosition + ']' + record.variable_current_position_stat_days + ']' if (separator === '') { separator = ',' } @@ -553,7 +548,6 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR record.variable_episode_stat_anualizedRateOfReturn + ',' + record.variable_current_position_rate + ',' + record.variable_last_position_ROI + ',' + - record.variable_current_strategy_index + ',' + record.variable_current_position_takeProfit_value + ',' + record.variable_current_position_stopLoss_phase + ',' + record.variable_current_position_stopLoss_phase + ',' + @@ -569,11 +563,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR record.variable_episode_parameters_marketBaseAsset + ',' + record.variable_episode_parameters_marketQuotedAsset + ',' + record.variable_current_position_count_periods + ',' + - record.variable_current_position_stat_days + ',' + - record.variable_current_distance_toEvent_triggerOn + ',' + - record.variable_current_distance_toEvent_triggerOff + ',' + - record.variable_current_distance_toEvent_takePosition + ',' + - record.variable_current_distance_toEvent_closePosition + ']' + record.variable_current_position_stat_days + ']' if (separator === '') { separator = ',' } diff --git a/TradingSimulation.js b/TradingSimulation.js index 4d301209b..754368378 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -2107,7 +2107,6 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable_episode_stat_anualizedRateOfReturn: variable.episode.stat.anualizedRateOfReturn, variable_current_position_rate: variable.current.position.rate, variable_last_position_ROI: variable.last.position.ROI, - variable_current_strategy_index: variable.current.strategy.index, variable_current_position_takeProfit_value: variable.current.position.takeProfit.value, variable_current_position_stopLoss_phase: variable.current.position.stopLoss.phase, variable_current_position_takeProfit_phase: variable.current.position.takeProfit.phase, @@ -2123,11 +2122,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable_episode_parameters_marketBaseAsset: '"' + variable.episode.parameters.marketBaseAsset + '"', variable_episode_parameters_marketQuotedAsset: '"' + variable.episode.parameters.marketQuotedAsset + '"', variable_current_position_count_periods: variable.current.position.count.periods, - variable_current_position_stat_days: variable.current.position.stat.days, - variable_current_distance_toEvent_triggerOn: variable.current.distance.toEvent.triggerOn, - variable_current_distance_toEvent_triggerOff: variable.current.distance.toEvent.triggerOff, - variable_current_distance_toEvent_takePosition: variable.current.distance.toEvent.takePosition, - variable_current_distance_toEvent_closePosition: variable.current.distance.toEvent.closePosition + variable_current_position_stat_days: variable.current.position.stat.days } recordsArray.push(simulationRecord) From 2abe045c9ac73206b4da9b54d883971dbccc14db Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 21 May 2020 19:00:25 +0200 Subject: [PATCH 33/44] Creating the readFiles Functions --- TradingBot.js | 430 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 420 insertions(+), 10 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index c971aa23f..c114034d1 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -128,16 +128,426 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR let tradingSystem = {} - tradingSimulation.runSimulation( - chart, - dataDependencies, - timeFrame, - timeFrameLabel, - currentDay, - variable, - exchangeAPI, - writeFiles, - callBackFunction) + function runSimulation() { + tradingSimulation.runSimulation( + chart, + dataDependencies, + timeFrame, + timeFrameLabel, + currentDay, + variable, + exchangeAPI, + writeFiles, + callBackFunction) + } + + function readFiles() { + + if (timeFrame > global.dailyFilePeriods[0][0]) { + readMarketFiles(runSimulation) + } else { + readDailyFiles(runSimulation) + } + } + + function readMarketFiles(callBack) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> Entering function.') } + + readRecordsFile() + + function readRecordsFile() { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> readRecordsFile -> Entering function.') } + + let fileName = 'Data.json' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + SIMULATED_RECORDS_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel + filePath += '/' + fileName + + fileStorage.getTextFile(filePath, onFileRead, true) + + function onFileRead(err, text) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> readRecordsFile -> onFileRead -> Entering function.') } + + if (err.message === 'File does not exist.') { + recordsArray = [] + readConditionsFile() + return + } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readRecordsFile -> onFileRead -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readRecordsFile -> onFileRead -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readRecordsFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) + + callBackFunction(err) + return + } + + recordsArray = JSON.parse(text) + readConditionsFile() + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readRecordsFile -> onFileRead -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readRecordsFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + + function readConditionsFile() { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> readConditionsFile -> Entering function.') } + + let fileName = 'Data.json' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + CONDITIONS_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel + filePath += '/' + fileName + + fileStorage.getTextFile(filePath, onFileRead, true) + + function onFileRead(err, text) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> readConditionsFile -> onFileRead -> Entering function.') } + + if (err.message === 'File does not exist.') { + conditionsArray = [] + readStrategiesFile() + return + } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readConditionsFile -> onFileRead -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readConditionsFile -> onFileRead -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readConditionsFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) + + callBackFunction(err) + return + } + + conditionsArray = JSON.parse(text) + readStrategiesFile() + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readConditionsFile -> onFileRead -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readConditionsFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + + function readStrategiesFile() { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> readStrategiesFile -> Entering function.') } + + let fileName = 'Data.json' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + STRATEGIES_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel + filePath += '/' + fileName + + fileStorage.getTextFile(filePath, onFileRead, true) + + function onFileRead(err, text) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> readStrategiesFile -> onFileRead -> Entering function.') } + + if (err.message === 'File does not exist.') { + strategiesArray = [] + readPositionsFile() + return + } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readStrategiesFile -> onFileRead -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readStrategiesFile -> onFileRead -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readStrategiesFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) + + callBackFunction(err) + return + } + + strategiesArray = JSON.parse(text) + readPositionsFile() + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readStrategiesFile -> onFileRead -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readStrategiesFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + + function readPositionsFile() { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> readPositionsFile -> Entering function.') } + + let fileName = 'Data.json' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + TRADES_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel + filePath += '/' + fileName + + fileStorage.getTextFile(filePath, onFileRead, true) + + function onFileRead(err, text) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> readPositionsFile -> onFileRead -> Entering function.') } + + if (err.message === 'File does not exist.') { + positionsArray = [] + readSnapshotFiles() + return + } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readPositionsFile -> onFileRead -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readPositionsFile -> onFileRead -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readPositionsFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) + + callBackFunction(err) + return + } + + positionsArray = JSON.parse(text) + callBack() + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readPositionsFile -> onFileRead -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readPositionsFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } + + function readDailyFiles(callBack) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> Entering function.') } + + readRecordsFile() + + function readRecordsFile() { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readRecordsFile -> Entering function.') } + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) + let fileName = 'Data.json' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + SIMULATED_RECORDS_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath + filePath += '/' + fileName + + fileStorage.getTextFile(filePath, onFileRead, true) + + function onFileRead(err, text) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readRecordsFile -> onFileRead -> Entering function.') } + + if (err.message === 'File does not exist.') { + recordsArray = [] + readConditionsFile() + return + } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readRecordsFile -> onFileRead -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readRecordsFile -> onFileRead -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readRecordsFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) + + callBackFunction(err) + return + } + + recordsArray = JSON.parse(text) + readConditionsFile() + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readRecordsFile -> onFileRead -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readRecordsFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + + function readConditionsFile() { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readConditionsFile -> Entering function.') } + + fileStorage.getTextFile(filePath, onFileRead, true) + + function onFileRead(err) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readConditionsFile -> onFileRead -> Entering function.') } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readConditionsFile -> onFileRead -> fileContent = ' + fileContent) } + + if (err.message === 'File does not exist.') { + conditionsArray = [] + readStrategiesFile() + return + } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readConditionsFile -> onFileRead -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readConditionsFile -> onFileRead -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readConditionsFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) + + callBackFunction(err) + return + } + + conditionsArray = JSON.parse(text) + readStrategiesFile() + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readConditionsFile -> onFileRead -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readConditionsFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + + function readStrategiesFile() { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readStrategiesFile -> Entering function.') } + + let separator = '' + let fileRecordCounter = 0 + + let fileContent = '' + + for (let i = 0; i < strategiesArray.length; i++) { + let record = strategiesArray[i] + + /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends + at the current date. */ + + if (record.end < currentDay.valueOf()) { continue } + + fileContent = fileContent + separator + '[' + + record.begin + ',' + + record.end + ',' + + record.status + ',' + + record.number + ',' + + record.beginRate + ',' + + record.endRate + ',' + + '"' + record.situationName + '"' + ',' + + '"' + record.name + '"' + ']' + + if (separator === '') { separator = ',' } + + fileRecordCounter++ + } + + fileContent = '[' + fileContent + ']' + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) + let fileName = 'Data.json' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + STRATEGIES_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath + filePath += '/' + fileName + + fileStorage.getTextFile(filePath, fileContent + '\n', onFileRead) + + function onFileRead(err) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readStrategiesFile -> onFileRead -> Entering function.') } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readStrategiesFile -> onFileRead -> fileContent = ' + fileContent) } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readStrategiesFile -> onFileRead -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readStrategiesFile -> onFileRead -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readStrategiesFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) + + callBackFunction(err) + return + } + + readPositionsFile() + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readStrategiesFile -> onFileRead -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readStrategiesFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + + function readPositionsFile() { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readPositionsFile -> Entering function.') } + + let separator = '' + let fileRecordCounter = 0 + + let fileContent = '' + + for (let i = 0; i < positionsArray.length; i++) { + let record = positionsArray[i] + + /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends + at the current date. */ + + if (record.end < currentDay.valueOf()) { continue } + if (record.stopRate === undefined) { record.stopRate = 0 } + + fileContent = fileContent + separator + '[' + + record.begin + ',' + + record.end + ',' + + record.status + ',' + + record.ROI + ',' + + record.beginRate + ',' + + record.endRate + ',' + + record.exitType + ',' + + '"' + record.situationName + '"' + ']' + + if (separator === '') { separator = ',' } + + fileRecordCounter++ + } + + fileContent = '[' + fileContent + ']' + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) + let fileName = 'Data.json' + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + TRADES_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath + filePath += '/' + fileName + + fileStorage.getTextFile(filePath, fileContent + '\n', onFileRead) + + function onFileRead(err) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readPositionsFile -> onFileRead -> Entering function.') } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readPositionsFile -> onFileRead -> fileContent = ' + fileContent) } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readPositionsFile -> onFileRead -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readPositionsFile -> onFileRead -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readPositionsFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) + + callBackFunction(err) + return + } + + readSnapshotFiles() + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readPositionsFile -> onFileRead -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readPositionsFile -> err = ' + err.stack) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + } + + function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pPositionsArray, pSnapshotHeaders, pTriggerOnSnapshot, pTakePositionSnapshot) { tradingSystem = pTradingSystem From 10c120f33203ed5f06ecdf687d971becf1d990af Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 21 May 2020 19:14:44 +0200 Subject: [PATCH 34/44] Appending to existing files --- TradingBot.js | 128 +++++++++++++------------------------------ TradingSimulation.js | 11 ++-- 2 files changed, 44 insertions(+), 95 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index c114034d1..9e2dbc5d5 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -128,18 +128,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR let tradingSystem = {} - function runSimulation() { - tradingSimulation.runSimulation( - chart, - dataDependencies, - timeFrame, - timeFrameLabel, - currentDay, - variable, - exchangeAPI, - writeFiles, - callBackFunction) - } + readFiles() function readFiles() { @@ -297,7 +286,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR if (err.message === 'File does not exist.') { positionsArray = [] - readSnapshotFiles() + callBack() return } @@ -378,10 +367,9 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR fileStorage.getTextFile(filePath, onFileRead, true) - function onFileRead(err) { + function onFileRead(err, text) { try { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readConditionsFile -> onFileRead -> Entering function.') } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readConditionsFile -> onFileRead -> fileContent = ' + fileContent) } if (err.message === 'File does not exist.') { conditionsArray = [] @@ -415,47 +403,22 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR try { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readStrategiesFile -> Entering function.') } - let separator = '' - let fileRecordCounter = 0 - - let fileContent = '' - - for (let i = 0; i < strategiesArray.length; i++) { - let record = strategiesArray[i] - - /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends - at the current date. */ - - if (record.end < currentDay.valueOf()) { continue } - - fileContent = fileContent + separator + '[' + - record.begin + ',' + - record.end + ',' + - record.status + ',' + - record.number + ',' + - record.beginRate + ',' + - record.endRate + ',' + - '"' + record.situationName + '"' + ',' + - '"' + record.name + '"' + ']' - - if (separator === '') { separator = ',' } - - fileRecordCounter++ - } - - fileContent = '[' + fileContent + ']' - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) let fileName = 'Data.json' let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + STRATEGIES_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath filePath += '/' + fileName - fileStorage.getTextFile(filePath, fileContent + '\n', onFileRead) + fileStorage.getTextFile(filePath, onFileRead, true) - function onFileRead(err) { + function onFileRead(err, text) { try { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readStrategiesFile -> onFileRead -> Entering function.') } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readStrategiesFile -> onFileRead -> fileContent = ' + fileContent) } + + if (err.message === 'File does not exist.') { + strategiesArray = [] + readPositionsFile() + return + } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readStrategiesFile -> onFileRead -> err = ' + err.stack) @@ -466,6 +429,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR return } + strategiesArray = JSON.parse(text) readPositionsFile() } catch (err) { logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readStrategiesFile -> onFileRead -> err = ' + err.stack) @@ -482,48 +446,22 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR try { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readPositionsFile -> Entering function.') } - let separator = '' - let fileRecordCounter = 0 - - let fileContent = '' - - for (let i = 0; i < positionsArray.length; i++) { - let record = positionsArray[i] - - /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends - at the current date. */ - - if (record.end < currentDay.valueOf()) { continue } - if (record.stopRate === undefined) { record.stopRate = 0 } - - fileContent = fileContent + separator + '[' + - record.begin + ',' + - record.end + ',' + - record.status + ',' + - record.ROI + ',' + - record.beginRate + ',' + - record.endRate + ',' + - record.exitType + ',' + - '"' + record.situationName + '"' + ']' - - if (separator === '') { separator = ',' } - - fileRecordCounter++ - } - - fileContent = '[' + fileContent + ']' - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) let fileName = 'Data.json' let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + TRADES_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath filePath += '/' + fileName - fileStorage.getTextFile(filePath, fileContent + '\n', onFileRead) + fileStorage.getTextFile(filePath, onFileRead, true) - function onFileRead(err) { + function onFileRead(err, text) { try { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readPositionsFile -> onFileRead -> Entering function.') } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readPositionsFile -> onFileRead -> fileContent = ' + fileContent) } + + if (err.message === 'File does not exist.') { + positionsArray = [] + callBack() + return + } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readPositionsFile -> onFileRead -> err = ' + err.stack) @@ -534,7 +472,8 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR return } - readSnapshotFiles() + positionsArray = JSON.parse(text) + callBack() } catch (err) { logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readPositionsFile -> onFileRead -> err = ' + err.stack) callBackFunction(global.DEFAULT_FAIL_RESPONSE) @@ -547,14 +486,25 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR } } + function runSimulation() { + tradingSimulation.runSimulation( + chart, + dataDependencies, + timeFrame, + timeFrameLabel, + currentDay, + variable, + exchangeAPI, + recordsArray, + conditionsArray, + strategiesArray, + positionsArray, + writeFiles, + callBackFunction) + } - - function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pPositionsArray, pSnapshotHeaders, pTriggerOnSnapshot, pTakePositionSnapshot) { + function writeFiles(pTradingSystem, pSnapshotHeaders, pTriggerOnSnapshot, pTakePositionSnapshot) { tradingSystem = pTradingSystem - recordsArray = pRecordsArray - conditionsArray = pConditionsArray - strategiesArray = pStrategiesArray - positionsArray = pPositionsArray snapshotHeaders = pSnapshotHeaders triggerOnSnapshot = pTriggerOnSnapshot diff --git a/TradingSimulation.js b/TradingSimulation.js index 754368378..0415c8bd7 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -27,6 +27,10 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT currentDay, variable, exchangeAPI, + recordsArray, + conditionsArray, + strategiesArray, + positionsArray, callback, callBackFunction) { try { @@ -38,11 +42,6 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT processingDailyFiles = true } - let recordsArray = [] - let conditionsArray = [] - let strategiesArray = [] - let positionsArray = [] - /* Snapshots of Trigger On and Take Positions */ let snapshots = { headers: undefined, @@ -2434,7 +2433,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> callback -> recordsArray.length = ' + recordsArray.length) } - callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, positionsArray, snapshots.headers, snapshots.triggerOn, snapshots.takePosition) + callback(tradingSystem, snapshots.headers, snapshots.triggerOn, snapshots.takePosition) } function getElement(pArray, currentCandle, datasetName) { From 9a289cb7ab31e51ba26563aef4deb3a8f11dc34b Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 21 May 2020 22:35:14 +0200 Subject: [PATCH 35/44] simulation, strategies and positions write market done --- TradingBot.js | 101 +----------- TradingSimulation.js | 377 +++++++++++++++++++++++-------------------- 2 files changed, 202 insertions(+), 276 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index 9e2dbc5d5..4efdb2a0e 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -526,55 +526,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR try { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeRecordsFile -> Entering function.') } - let separator = '' - let fileRecordCounter = 0 - - let fileContent = '' - - for (let i = 0; i < recordsArray.length; i++) { - let record = recordsArray[i] - - fileContent = fileContent + separator + '[' + - record.begin + ',' + - record.end + ',' + - record.variable_current_balance_baseAsset + ',' + - record.variable_current_balance_quotedAsset + ',' + - record.variable_episode_stat_profitLoss + ',' + - record.variable_last_position_profitLoss + ',' + - record.variable_current_position_stopLoss_value + ',' + - record.variable_episode_count_positions + ',' + - record.variable_episode_count_hits + ',' + - record.variable_episode_count_fails + ',' + - record.variable_episode_stat_hitRatio + ',' + - record.variable_episode_stat_ROI + ',' + - record.variable_episode_count_periods + ',' + - record.variable_episode_stat_days + ',' + - record.variable_episode_stat_anualizedRateOfReturn + ',' + - record.variable_current_position_rate + ',' + - record.variable_last_position_ROI + ',' + - record.variable_current_position_takeProfit_value + ',' + - record.variable_current_position_stopLoss_phase + ',' + - record.variable_current_position_stopLoss_phase + ',' + - record.variable_current_position_size + ',' + - record.variable_episode_parameters_initial_balance_baseAsset + ',' + - record.variable_episode_parameters_minimum_balance_baseAsset + ',' + - record.variable_episode_parameters_maximum_balance_baseAsset + ',' + - record.variable_episode_parameters_initial_balance_quotedAsset + ',' + - record.variable_episode_parameters_minimum_balance_quotedAsset + ',' + - record.variable_episode_parameters_maximum_balance_quotedAsset + ',' + - record.variable_episode_parameters_baseAsset + ',' + - record.variable_episode_parameters_quotedAsset + ',' + - record.variable_episode_parameters_marketBaseAsset + ',' + - record.variable_episode_parameters_marketQuotedAsset + ',' + - record.variable_current_position_count_periods + ',' + - record.variable_current_position_stat_days + ']' - - if (separator === '') { separator = ',' } - - fileRecordCounter++ - } - - fileContent = '[' + fileContent + ']' + let fileContent = JSON.stringify(recordsArray) let fileName = 'Data.json' let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + SIMULATED_RECORDS_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel @@ -678,30 +630,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR try { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeStrategiesFile -> Entering function.') } - let separator = '' - let fileRecordCounter = 0 - - let fileContent = '' - - for (let i = 0; i < strategiesArray.length; i++) { - let record = strategiesArray[i] - - fileContent = fileContent + separator + '[' + - record.begin + ',' + - record.end + ',' + - record.status + ',' + - record.number + ',' + - record.beginRate + ',' + - record.endRate + ',' + - '"' + record.situationName + '"' + ',' + - '"' + record.name + '"' + ']' - - if (separator === '') { separator = ',' } - - fileRecordCounter++ - } - - fileContent = '[' + fileContent + ']' + let fileContent = JSON.stringify(strategiesArray) let fileName = 'Data.json' let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + STRATEGIES_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel @@ -739,31 +668,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR try { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writePositionsFile -> Entering function.') } - let separator = '' - let fileRecordCounter = 0 - - let fileContent = '' - - for (let i = 0; i < positionsArray.length; i++) { - let record = positionsArray[i] - if (record.stopRate === undefined) { record.stopRate = 0 } - - fileContent = fileContent + separator + '[' + - record.begin + ',' + - record.end + ',' + - record.status + ',' + - record.ROI + ',' + - record.beginRate + ',' + - record.endRate + ',' + - record.exitType + ',' + - '"' + record.situationName + '"' + ']' - - if (separator === '') { separator = ',' } - - fileRecordCounter++ - } - - fileContent = '[' + fileContent + ']' + let fileContent = JSON.stringify(positionsArray) let fileName = 'Data.json' let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + TRADES_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel diff --git a/TradingSimulation.js b/TradingSimulation.js index 0415c8bd7..e1e2f4738 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -384,16 +384,11 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT let conditions = new Map() // Here we store the conditions values that will be use in the simulator for decision making. let formulas = new Map() - let conditionsArrayRecord = [] // These are the records that will be saved in a file for the plotter to consume. let conditionsValues = [] // Here we store the conditions values that will be written on file for the plotter. let formulasErrors = [] // Here we store the errors produced by all phase formulas. let formulasValues = [] // Here we store the values produced by all phase formulas. /* We define and evaluate all conditions to be used later during the simulation loop. */ - - conditionsArrayRecord.push(candle.begin) - conditionsArrayRecord.push(candle.end) - for (let j = 0; j < tradingSystem.strategies.length; j++) { let strategy = tradingSystem.strategies[j] @@ -1828,7 +1823,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.balance.quotedAsset = variable.current.balance.quotedAsset - variable.current.position.size } - addRecord() + addRecords() if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> takePositionAtSimulation -> Exiting Loop Body after taking position at simulation.') } controlLoop() return @@ -2029,7 +2024,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.episode.stat.anualizedRateOfReturn = variable.episode.stat.ROI / variable.episode.stat.days * 365 } - addRecord() + addRecords() variable.current.position.stopLoss.value = 0 variable.current.position.takeProfit.value = 0 @@ -2071,185 +2066,211 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT /* Not a buy or sell condition */ - addRecord() + addRecords() if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Exiting Loop Body after adding a record.') } controlLoop() return - function addRecord() { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> addRecord -> Entering function.') } - let simulationRecord + function addRecords() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> addRecords -> Entering function.') } - if (variable.current.balance.baseAsset === Infinity) { - variable.current.balance.baseAsset = Number.MAX_SAFE_INTEGER - } - - if (variable.current.balance.quotedAsset === Infinity) { - variable.current.balance.quotedAsset = Number.MAX_SAFE_INTEGER - } - - simulationRecord = { - begin: candle.begin, - end: candle.end, - variable_current_balance_baseAsset: variable.current.balance.baseAsset, - variable_current_balance_quotedAsset: variable.current.balance.quotedAsset, - variable_episode_stat_profitLoss: variable.episode.stat.profitLoss, - variable_last_position_profitLoss: variable.last.position.profitLoss, - variable_current_position_stopLoss_value: variable.current.position.stopLoss.value, - variable_episode_count_positions: variable.episode.count.positions, - variable_episode_count_hits: variable.episode.count.hits, - variable_episode_count_fails: variable.episode.count.fails, - variable_episode_stat_hitRatio: variable.episode.stat.hitRatio, - variable_episode_stat_ROI: variable.episode.stat.ROI, - variable_episode_count_periods: variable.episode.count.periods, - variable_episode_stat_days: variable.episode.stat.days, - variable_episode_stat_anualizedRateOfReturn: variable.episode.stat.anualizedRateOfReturn, - variable_current_position_rate: variable.current.position.rate, - variable_last_position_ROI: variable.last.position.ROI, - variable_current_position_takeProfit_value: variable.current.position.takeProfit.value, - variable_current_position_stopLoss_phase: variable.current.position.stopLoss.phase, - variable_current_position_takeProfit_phase: variable.current.position.takeProfit.phase, - variable_current_position_size: variable.current.position.size, - variable_episode_parameters_initial_balance_baseAsset: variable.episode.parameters.initial.balance.baseAsset, - variable_episode_parameters_minimum_balance_baseAsset: variable.episode.parameters.minimum.balance.baseAsset, - variable_episode_parameters_maximum_balance_baseAsset: variable.episode.parameters.maximum.balance.baseAsset, - variable_episode_parameters_initial_balance_quotedAsset: variable.episode.parameters.initial.balance.quotedAsset, - variable_episode_parameters_minimum_balance_quotedAsset: variable.episode.parameters.minimum.balance.quotedAsset, - variable_episode_parameters_maximum_balance_quotedAsset: variable.episode.parameters.maximum.balance.quotedAsset, - variable_episode_parameters_baseAsset: '"' + variable.episode.parameters.baseAsset + '"', - variable_episode_parameters_quotedAsset: '"' + variable.episode.parameters.quotedAsset + '"', - variable_episode_parameters_marketBaseAsset: '"' + variable.episode.parameters.marketBaseAsset + '"', - variable_episode_parameters_marketQuotedAsset: '"' + variable.episode.parameters.marketQuotedAsset + '"', - variable_current_position_count_periods: variable.current.position.count.periods, - variable_current_position_stat_days: variable.current.position.stat.days - } - - recordsArray.push(simulationRecord) - - /* Prepare the information for the Conditions File */ - - conditionsArrayRecord.push(variable.current.strategy.index) - conditionsArrayRecord.push(variable.current.position.stopLoss.phase) - conditionsArrayRecord.push(variable.current.position.takeProfit.phase) - conditionsArrayRecord.push(conditionsValues) - conditionsArrayRecord.push(formulasErrors) - conditionsArrayRecord.push(formulasValues) - - conditionsArray.push(conditionsArrayRecord) - - /* - Lets see if there will be an open strategy ... - Except if we are at the head of the market (remember we skipped the last candle for not being closed.) - */ - if (variable.current.strategy.begin !== 0 && variable.current.strategy.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { - variable.current.strategy.status = 2 // This means the strategy is open, i.e. that has a begin but no end. - variable.current.strategy.end = candle.end - } - - /* Prepare the information for the Strategies File */ - if (variable.current.strategy.begin !== 0 && variable.current.strategy.end !== 0) { - let currentStrategyRecord = { - begin: variable.current.strategy.begin, - end: variable.current.strategy.end, - status: variable.current.strategy.status, - number: variable.current.strategy.number, - beginRate: variable.current.strategy.beginRate, - endRate: variable.current.strategy.endRate, - situationName: variable.current.strategy.situationName, - name: variable.current.strategy.name - } - - strategiesArray.push(currentStrategyRecord) - - inializeCurrentStrategy() - } - - /* - Lets see if there will be an open trade ... - Except if we are at the head of the market (remember we skipped the last candle for not being closed.) - */ - if (variable.current.position.begin !== 0 && variable.current.position.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { - variable.current.position.status = 2 // This means the trade is open - variable.current.position.end = candle.end - variable.current.position.endRate = candle.close - - /* Here we will calculate the ongoing ROI */ - if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { - variable.current.position.stat.ROI = (variable.current.position.rate - candle.close) / variable.current.position.rate * 100 - } else { - variable.current.position.stat.ROI = (candle.close - variable.current.position.rate) / variable.current.position.rate * 100 - } - } - - /* Snapshots Management (before we generate the trade record and delete that info) */ - if (saveAsLastTriggerOnSnapshot === true) { - snapshots.lastTriggerOn = snapshotDataRecord - saveAsLastTriggerOnSnapshot = false - } - - if (saveAsLastTakePositionSnapshot === true) { - snapshots.lastTakePosition = snapshotDataRecord - saveAsLastTakePositionSnapshot = false - } - - if (addToSnapshots === true) { - let closeValues = [ - variable.episode.count.positions, // Position Number - (new Date(candle.begin)).toISOString(), // Datetime - tradingSystem.strategies[variable.current.strategy.index].name, // Strategy Name - variable.current.strategy.situationName, // Trigger On Situation - variable.current.position.situationName, // Take Position Situation - hitOrFial(), // Result - variable.last.position.ROI, // ROI - exitType() // Exit Type - ] - - function hitOrFial() { - if (variable.last.position.ROI > 0) { return 'HIT' } else { return 'FAIL' } - } - - function exitType() { - switch (variable.current.position.exitType) { - case 1: return 'Stop' - case 2: return 'Take Profit' - } - } - - - if (positionedAtYesterday === false) { - snapshots.triggerOn.push(closeValues.concat(snapshots.lastTriggerOn)) - snapshots.takePosition.push(closeValues.concat(snapshots.lastTakePosition)) - } - snapshots.lastTriggerOn = undefined - snapshots.lastTakePosition = undefined - addToSnapshots = false - } - - let closeHeaders = ['Trade Number', 'Close Datetime', 'Strategy', 'Trigger On Situation', 'Take Position Situation', 'Result', 'ROI', 'Exit Type'] - if (snapshots.headers === undefined) { - snapshots.headers = closeHeaders.concat(JSON.parse(JSON.stringify(snapshotLoopHeaders))) - } - - /* Prepare the information for the Trades File */ - if (variable.current.position.begin !== 0 && variable.current.position.end !== 0) { - let currentPositionRecord = { - begin: variable.current.position.begin, - end: variable.current.position.end, - status: variable.current.position.status, - ROI: variable.current.position.stat.ROI, - exitType: variable.current.position.exitType, - beginRate: variable.current.position.beginRate, - endRate: variable.current.position.endRate, - situationName: variable.current.position.situationName - } - - positionsArray.push(currentPositionRecord) - - initializeCurrentPosition() - } + manageSnapshots() + addSimulationRecord() + addConditionsRecord() + addStrategyRecord() + addPositionRecord() /* After everything at the simulation level was done, we will do the annoucements that are pending. */ makeAnnoucements() + + function manageSnapshots() { + /* Snapshots Management (before we generate the trade record and delete that info) */ + if (saveAsLastTriggerOnSnapshot === true) { + snapshots.lastTriggerOn = snapshotDataRecord + saveAsLastTriggerOnSnapshot = false + } + + if (saveAsLastTakePositionSnapshot === true) { + snapshots.lastTakePosition = snapshotDataRecord + saveAsLastTakePositionSnapshot = false + } + + if (addToSnapshots === true) { + let closeValues = [ + variable.episode.count.positions, // Position Number + (new Date(candle.begin)).toISOString(), // Datetime + tradingSystem.strategies[variable.current.strategy.index].name, // Strategy Name + variable.current.strategy.situationName, // Trigger On Situation + variable.current.position.situationName, // Take Position Situation + hitOrFial(), // Result + variable.last.position.ROI, // ROI + exitType() // Exit Type + ] + + function hitOrFial() { + if (variable.last.position.ROI > 0) { return 'HIT' } else { return 'FAIL' } + } + + function exitType() { + switch (variable.current.position.exitType) { + case 1: return 'Stop' + case 2: return 'Take Profit' + } + } + + + if (positionedAtYesterday === false) { + snapshots.triggerOn.push(closeValues.concat(snapshots.lastTriggerOn)) + snapshots.takePosition.push(closeValues.concat(snapshots.lastTakePosition)) + } + snapshots.lastTriggerOn = undefined + snapshots.lastTakePosition = undefined + addToSnapshots = false + } + + let closeHeaders = ['Trade Number', 'Close Datetime', 'Strategy', 'Trigger On Situation', 'Take Position Situation', 'Result', 'ROI', 'Exit Type'] + if (snapshots.headers === undefined) { + snapshots.headers = closeHeaders.concat(JSON.parse(JSON.stringify(snapshotLoopHeaders))) + } + } + + function addSimulationRecord() { + /* Simulation Record */ + let simulationRecord + + if (variable.current.balance.baseAsset === Infinity) { + variable.current.balance.baseAsset = Number.MAX_SAFE_INTEGER + } + + if (variable.current.balance.quotedAsset === Infinity) { + variable.current.balance.quotedAsset = Number.MAX_SAFE_INTEGER + } + + simulationRecord = [ + candle.begin, + candle.end, + variable.current.balance.baseAsset, + variable.current.balance.quotedAsset, + variable.episode.stat.profitLoss, + variable.last.position.profitLoss, + variable.current.position.stopLoss.value, + variable.episode.count.positions, + variable.episode.count.hits, + variable.episode.count.fails, + variable.episode.stat.hitRatio, + variable.episode.stat.ROI, + variable.episode.count.periods, + variable.episode.stat.days, + variable.episode.stat.anualizedRateOfReturn, + variable.current.position.rate, + variable.last.position.ROI, + variable.current.position.takeProfit.value, + variable.current.position.stopLoss.phase, + variable.current.position.takeProfit.phase, + variable.current.position.size, + variable.episode.parameters.initial.balance.baseAsset, + variable.episode.parameters.minimum.balance.baseAsset, + variable.episode.parameters.maximum.balance.baseAsset, + variable.episode.parameters.initial.balance.quotedAsset, + variable.episode.parameters.minimum.balance.quotedAsset, + variable.episode.parameters.maximum.balance.quotedAsset, + '"' + variable.episode.parameters.baseAsset + '"', + '"' + variable.episode.parameters.quotedAsset + '"', + '"' + variable.episode.parameters.marketBaseAsset + '"', + '"' + variable.episode.parameters.marketQuotedAsset + '"', + variable.current.position.count.periods, + variable.current.position.stat.days + ] + + recordsArray.push(simulationRecord) + } + + function addConditionsRecord() { + /* Prepare the information for the Conditions File */ + let conditionsRecord = [ + candle.begin, + candle.end, + variable.current.strategy.index, + variable.current.position.stopLoss.phase, + variable.current.position.takeProfit.phase, + conditionsValues, + formulasErrors, + formulasValues + ] + + conditionsArray.push(conditionsRecord) + } + + function addStrategyRecord() { + /* + Lets see if there will be an open strategy ... + Except if we are at the head of the market (remember we skipped the last candle for not being closed.) + */ + if (variable.current.strategy.begin !== 0 && variable.current.strategy.end === 0 && currentCandleIndex === candles.length - 2 && lastCandle.end !== lastInstantOfTheDay) { + variable.current.strategy.status = 2 // This means the strategy is open, i.e. that has a begin but no end. + variable.current.strategy.end = candle.end + } + + /* Prepare the information for the Strategies File */ + if (variable.current.strategy.begin !== 0 && variable.current.strategy.end !== 0) { + let strategyRecord = [ + variable.current.strategy.begin, + variable.current.strategy.end, + variable.current.strategy.status, + variable.current.strategy.number, + variable.current.strategy.beginRate, + variable.current.strategy.endRate, + '"' + variable.current.strategy.situationName + '"', + '"' + variable.current.strategy.name + '"' + ] + + strategiesArray.push(strategyRecord) + + inializeCurrentStrategy() + } + } + + function addPositionRecord() { + /* + Lets see if there will be an open trade ... + Except if we are at the head of the market (remember we skipped the last candle for not being closed.) + */ + if (variable.current.position.begin !== 0 && + variable.current.position.end === 0 && + currentCandleIndex === candles.length - 2 && + lastCandle.end !== lastInstantOfTheDay) { + + /* This means the trade is open */ + variable.current.position.status = 2 + variable.current.position.end = candle.end + variable.current.position.endRate = candle.close + + /* Here we will calculate the ongoing ROI */ + if (variable.episode.parameters.baseAsset === variable.episode.parameters.marketBaseAsset) { + variable.current.position.stat.ROI = (variable.current.position.rate - candle.close) / variable.current.position.rate * 100 + } else { + variable.current.position.stat.ROI = (candle.close - variable.current.position.rate) / variable.current.position.rate * 100 + } + } + + /* Prepare the information for the Positions File */ + if (variable.current.position.begin !== 0 && variable.current.position.end !== 0) { + let positionRecord = [ + variable.current.position.begin, + variable.current.position.end, + variable.current.position.status, + variable.current.position.stat.ROI, + variable.current.position.exitType, + variable.current.position.beginRate, + variable.current.position.endRate, + '"' + variable.current.position.situationName + '"' + ] + + positionsArray.push(positionRecord) + + initializeCurrentPosition() + } + } } function checkAnnouncements(node, value) { From ec46e9696c06aefa4bb632b8a4f2fe80461ba453 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 21 May 2020 22:58:48 +0200 Subject: [PATCH 36/44] Adding Records Correctly to all --- TradingBot.js | 30 +++--------------------------- TradingSimulation.js | 2 +- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index 4efdb2a0e..051500fc0 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -216,6 +216,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR } conditionsArray = JSON.parse(text) + conditionsArray = conditionsArray[1] // conditionsArray[0] = a snapshot of the trading system. readStrategiesFile() } catch (err) { logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readConditionsFile -> onFileRead -> err = ' + err.stack) @@ -387,6 +388,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR } conditionsArray = JSON.parse(text) + conditionsArray = conditionsArray[1] // conditionsArray[0] = a snapshot of the trading system. readStrategiesFile() } catch (err) { logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readConditionsFile -> onFileRead -> err = ' + err.stack) @@ -564,34 +566,8 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR try { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeMarketFiles -> writeConditionsFile -> Entering function.') } - let separator = '' - let fileRecordCounter = 0 + let fileContent = JSON.stringify(conditionsArray) - let fileContent = '' - - for (let i = 0; i < conditionsArray.length; i++) { - let record = conditionsArray[i] - - let conditions = '' - let conditionsSeparator = '' - - for (let j = 0; j < record.length - 3; j++) { - conditions = conditions + conditionsSeparator + record[j] - if (conditionsSeparator === '') { conditionsSeparator = ',' } - } - - conditions = conditions + conditionsSeparator + '[' + record[record.length - 3] + ']' // The last item contains an Array of condition values. - conditions = conditions + conditionsSeparator + '[' + record[record.length - 2] + ']' // The last item contains an Array of formulaErrors. - conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']' // The last item contains an Array of formulaValues. - - fileContent = fileContent + separator + '[' + conditions + ']' - - if (separator === '') { separator = ',' } - - fileRecordCounter++ - } - - fileContent = '[' + fileContent + ']' fileContent = '[' + JSON.stringify(tradingSystem) + ',' + fileContent + ']' let fileName = 'Data.json' diff --git a/TradingSimulation.js b/TradingSimulation.js index e1e2f4738..bf4258aec 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -2260,9 +2260,9 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.position.end, variable.current.position.status, variable.current.position.stat.ROI, - variable.current.position.exitType, variable.current.position.beginRate, variable.current.position.endRate, + variable.current.position.exitType, '"' + variable.current.position.situationName + '"' ] From 6b3b3d4e3796361748dd2a94a909b0d589b7df09 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 21 May 2020 23:13:22 +0200 Subject: [PATCH 37/44] daily and market finished --- TradingBot.js | 151 ++------------------------------------------------ 1 file changed, 4 insertions(+), 147 deletions(-) diff --git a/TradingBot.js b/TradingBot.js index 051500fc0..e5a47c3c2 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -759,59 +759,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR try { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeRecordsFile -> Entering function.') } - let separator = '' - let fileRecordCounter = 0 - - let fileContent = '' - - for (let i = 0; i < recordsArray.length; i++) { - let record = recordsArray[i] - - /* Will only add to the file the records of the current day */ - - if (record.begin < currentDay.valueOf()) { continue } - - fileContent = fileContent + separator + '[' + - record.begin + ',' + - record.end + ',' + - record.variable_current_balance_baseAsset + ',' + - record.variable_current_balance_quotedAsset + ',' + - record.variable_episode_stat_profitLoss + ',' + - record.variable_last_position_profitLoss + ',' + - record.variable_current_position_stopLoss_value + ',' + - record.variable_episode_count_positions + ',' + - record.variable_episode_count_hits + ',' + - record.variable_episode_count_fails + ',' + - record.variable_episode_stat_hitRatio + ',' + - record.variable_episode_stat_ROI + ',' + - record.variable_episode_count_periods + ',' + - record.variable_episode_stat_days + ',' + - record.variable_episode_stat_anualizedRateOfReturn + ',' + - record.variable_current_position_rate + ',' + - record.variable_last_position_ROI + ',' + - record.variable_current_position_takeProfit_value + ',' + - record.variable_current_position_stopLoss_phase + ',' + - record.variable_current_position_stopLoss_phase + ',' + - record.variable_current_position_size + ',' + - record.variable_episode_parameters_initial_balance_baseAsset + ',' + - record.variable_episode_parameters_minimum_balance_baseAsset + ',' + - record.variable_episode_parameters_maximum_balance_baseAsset + ',' + - record.variable_episode_parameters_initial_balance_quotedAsset + ',' + - record.variable_episode_parameters_minimum_balance_quotedAsset + ',' + - record.variable_episode_parameters_maximum_balance_quotedAsset + ',' + - record.variable_episode_parameters_baseAsset + ',' + - record.variable_episode_parameters_quotedAsset + ',' + - record.variable_episode_parameters_marketBaseAsset + ',' + - record.variable_episode_parameters_marketQuotedAsset + ',' + - record.variable_current_position_count_periods + ',' + - record.variable_current_position_stat_days + ']' - - if (separator === '') { separator = ',' } - - fileRecordCounter++ - } - - fileContent = '[' + fileContent + ']' + let fileContent = JSON.stringify(recordsArray) let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) let fileName = 'Data.json' @@ -850,42 +798,8 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR try { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeConditionsFile -> Entering function.') } - let separator = '' - let fileRecordCounter = 0 + let fileContent = JSON.stringify(conditionsArray) - let fileContent = '' - - for (let i = 0; i < conditionsArray.length; i++) { - let record = conditionsArray[i] - - /* Will only add to the file the records of the current day */ - - if (record.begin < currentDay.valueOf()) { continue } - - let conditions = '' - let conditionsSeparator = '' - - /* Will only add to the file the records of the current day */ - - if (record.begin < currentDay.valueOf()) { continue } - - for (let j = 0; j < record.length - 3; j++) { - conditions = conditions + conditionsSeparator + record[j] - if (conditionsSeparator === '') { conditionsSeparator = ',' } - } - - conditions = conditions + conditionsSeparator + '[' + record[record.length - 3] + ']' // The last item contains an Array of condition values. - conditions = conditions + conditionsSeparator + '[' + record[record.length - 2] + ']' // The last item contains an Array of formulaErrors. - conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']' // The last item contains an Array of formulaValues. - - fileContent = fileContent + separator + '[' + conditions + ']' - - if (separator === '') { separator = ',' } - - fileRecordCounter++ - } - - fileContent = '[' + fileContent + ']' fileContent = '[' + JSON.stringify(tradingSystem) + ',' + fileContent + ']' let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) @@ -925,35 +839,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR try { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writeStrategiesFile -> Entering function.') } - let separator = '' - let fileRecordCounter = 0 - - let fileContent = '' - - for (let i = 0; i < strategiesArray.length; i++) { - let record = strategiesArray[i] - - /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends - at the current date. */ - - if (record.end < currentDay.valueOf()) { continue } - - fileContent = fileContent + separator + '[' + - record.begin + ',' + - record.end + ',' + - record.status + ',' + - record.number + ',' + - record.beginRate + ',' + - record.endRate + ',' + - '"' + record.situationName + '"' + ',' + - '"' + record.name + '"' + ']' - - if (separator === '') { separator = ',' } - - fileRecordCounter++ - } - - fileContent = '[' + fileContent + ']' + let fileContent = JSON.stringify(strategiesArray) let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) let fileName = 'Data.json' @@ -992,36 +878,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR try { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> writeDailyFiles -> writePositionsFile -> Entering function.') } - let separator = '' - let fileRecordCounter = 0 - - let fileContent = '' - - for (let i = 0; i < positionsArray.length; i++) { - let record = positionsArray[i] - - /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends - at the current date. */ - - if (record.end < currentDay.valueOf()) { continue } - if (record.stopRate === undefined) { record.stopRate = 0 } - - fileContent = fileContent + separator + '[' + - record.begin + ',' + - record.end + ',' + - record.status + ',' + - record.ROI + ',' + - record.beginRate + ',' + - record.endRate + ',' + - record.exitType + ',' + - '"' + record.situationName + '"' + ']' - - if (separator === '') { separator = ',' } - - fileRecordCounter++ - } - - fileContent = '[' + fileContent + ']' + let fileContent = JSON.stringify(positionsArray) let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) let fileName = 'Data.json' From bf954a5d68773d8a559447253835c7fecffa17c1 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 22 May 2020 09:59:49 +0200 Subject: [PATCH 38/44] Improved Logging while live Trading --- DebugLog.js | 24 ++++++++++++------------ TradingSimulation.js | 8 ++++++++ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/DebugLog.js b/DebugLog.js index bcaf567a3..f3372242d 100644 --- a/DebugLog.js +++ b/DebugLog.js @@ -34,7 +34,7 @@ exports.newDebugLog = function newDebugLog() { disableLogging = pdisableLogging } catch (err) { - console.log("[ERROR] Debug Log -> initialize -> err = "+ err.stack); + console.log("[ERROR] Debug Log -> initialize -> err = " + err.stack); } } @@ -53,12 +53,12 @@ exports.newDebugLog = function newDebugLog() { date = date.getUTCFullYear() + '-' + strPad(date.getUTCMonth() + 1, 2, "0") + '-' + strPad(date.getUTCDate(), 2, "0"); console.log(new Date().toISOString() + " " + strPad(thisObject.bot.exchange, 20) + " " + strPad(thisObject.bot.market.baseAsset + '/' + thisObject.bot.market.quotedAsset, 10) + " " + strPad(pBot, 30) + " " + strPad(pProcess, 30) - + " Internal Loop # " + strPad(internalLoopCounter + 1, 8) + " " + strPad(date, 30) + " " + strPad(percentage, 10)) + + " Internal Loop # " + strPad(internalLoopCounter + 1, 8) + " " + strPad(date, 30) + " " + strPad(percentage, 10)) persist(); function strPad(str, max, fill) { - if (fill === undefined) {fill = " "} + if (fill === undefined) { fill = " " } str = str.toString(); return str.length < max ? strPad(fill + str, max) : str; } @@ -69,7 +69,7 @@ exports.newDebugLog = function newDebugLog() { /* Here we actually write the content of the in-memory log to a file */ try { - if (accumulatedLog === "[") {return} // nothing to persist at the moment. + if (accumulatedLog === "[") { return } // nothing to persist at the moment. internalLoopCounter++; @@ -82,7 +82,7 @@ exports.newDebugLog = function newDebugLog() { let filePath = thisObject.bot.filePathRoot + "/Logs/" + thisObject.bot.process + "/" if (thisObject.bot.SESSION !== undefined) { - filePath = filePath + thisObject.bot.SESSION.folderName + "/" + executionDatetime; + filePath = filePath + thisObject.bot.SESSION.folderName + "/" + executionDatetime; } else { filePath = filePath + executionDatetime; } @@ -102,32 +102,32 @@ exports.newDebugLog = function newDebugLog() { writeLog(); /* This is the implementation of the mechanism to auto-mantain logs. */ - if (contentToPersist.indexOf('[ERROR]') < 0) { + if (contentToPersist.indexOf('[ERROR]') < 0 && contentToPersist.indexOf('[PERSIST]') < 0) { thisObject.bot.LOGS_TO_DELETE_QUEUE.push(filePath + '/' + fileName) } if (thisObject.bot.LOGS_TO_DELETE_QUEUE.length > thisObject.bot.DELETE_QUEUE_SIZE) { let fileToDelete = thisObject.bot.LOGS_TO_DELETE_QUEUE[0] thisObject.bot.LOGS_TO_DELETE_QUEUE.splice(0, 1) /* Will delete this file only if it does not contains ERROR inside. */ - let fileContent = fileStorage.getTextFile(fileToDelete, onGetFile, true) + let fileContent = fileStorage.getTextFile(fileToDelete, onGetFile, true) function onGetFile(err, fileContent) { if (err.result === global.DEFAULT_OK_RESPONSE.result) { if (fileContent.indexOf("ERROR") < 0) { /* Logs will only be deleted when they contain no ERROR in them. */ fileStorage.deleteTextFile(fileToDelete); - } + } } else { fileStorage.deleteTextFile(fileToDelete); } } } - + function writeLog() { fileStorage.createTextFile(filePath + '/' + fileName, contentToPersist + '\r\n' + "]", onFileCreated); function onFileCreated(err) { if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - console.log("[ERROR] DebugLog -> persist -> onInizialized -> onFileCreated -> err = "+ err.message); + console.log("[ERROR] DebugLog -> persist -> onInizialized -> onFileCreated -> err = " + err.message); setTimeout(writeLog, 10000); // Lets retry until we make it. return; } @@ -135,7 +135,7 @@ exports.newDebugLog = function newDebugLog() { } } } catch (err) { - console.log("[ERROR] DebugLog -> persist -> err = "+ err.stack); + console.log("[ERROR] DebugLog -> persist -> err = " + err.stack); console.log("[ERROR] DebugLog -> persist -> onInizialized -> contentToPersist = " + contentToPersist); } } @@ -174,7 +174,7 @@ exports.newDebugLog = function newDebugLog() { accumulatedLog = accumulatedLog + logLine; } catch (err) { - console.log("[ERROR] DebugLog -> write -> err = "+ err.stack); + console.log("[ERROR] DebugLog -> write -> err = " + err.stack); } } diff --git a/TradingSimulation.js b/TradingSimulation.js index bf4258aec..df1e148d1 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -1622,6 +1622,14 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT variable.current.position.rate = variable.current.position.rate + slippageAmount } + if (bot.startMode === 'Live') { + logger.write(MODULE_NAME, '[PERSIST] runSimulation -> loop -> takePositionNow -> Taking a Position in Live Mode.') + logger.write(MODULE_NAME, '[PERSIST] runSimulation -> loop -> takePositionNow -> strategy.positionSize = ' + strategy.positionSize) + logger.write(MODULE_NAME, '[PERSIST] runSimulation -> loop -> takePositionNow -> strategy.positionRate = ' + strategy.positionRate) + logger.write(MODULE_NAME, '[PERSIST] runSimulation -> loop -> takePositionNow -> slippageAmount = ' + slippageAmount) + logger.write(MODULE_NAME, '[PERSIST] runSimulation -> loop -> takePositionNow -> variable.current.position.rate = ' + variable.current.position.rate) + } + /* Update the trade record information. */ variable.current.position.begin = candle.begin variable.current.position.beginRate = variable.current.position.rate From 66312b82c981466ce857c935e3e17e3f7ac1e262 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 22 May 2020 13:27:49 +0200 Subject: [PATCH 39/44] Resuming implemented --- MultiPeriod.js | 181 +++++-------------------------------------- Session.js | 45 +++++------ TradingBot.js | 14 ++-- TradingSimulation.js | 46 ++++++++--- 4 files changed, 89 insertions(+), 197 deletions(-) diff --git a/MultiPeriod.js b/MultiPeriod.js index 939d30a50..984e45e26 100644 --- a/MultiPeriod.js +++ b/MultiPeriod.js @@ -57,7 +57,7 @@ multiPeriodDataFiles = undefined statusDependencies = undefined dataDependenciesModule = undefined - botInstance.finalize() + botInstance.finalize() botInstance = undefined fileStorage = undefined processConfig = undefined @@ -71,7 +71,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); } let currentTimeFrame - let currentTimeFrameLabel + let currentTimeFrameLabel let market = bot.market; let botNeverRan = true; @@ -86,7 +86,7 @@ let previousDay; // Holds the date of the previous day relative to the processing date. - let variableArray = []; + let variable = {} getContextVariables(); @@ -101,12 +101,11 @@ let statusReport; /* We are going to use the start date as beging of market date. */ - contextVariables.dateBeginOfMarket = bot.VALUES_TO_USE.timeRange.initialDatetime + contextVariables.dateBeginOfMarket = bot.VALUES_TO_USE.timeRange.initialDatetime /* Here we get the status report from the bot who knows which is the end of the market. */ - statusReport = statusDependencies.reportsByMainUtility.get("Market Ending Point") if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. @@ -138,7 +137,6 @@ contextVariables.dateEndOfMarket = new Date(thisReport.lastFile.valueOf()); /* Validation that the data is not up-to-date. */ - if (bot.multiPeriodProcessDatetime.valueOf() - ONE_DAY_IN_MILISECONDS > contextVariables.dateEndOfMarket.valueOf() && bot.SESSION.type !== "Backtesting Session") { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> " + "Head of the market is @ " + contextVariables.dateEndOfMarket); } @@ -150,7 +148,6 @@ } /* Finally we get our own Status Report. */ - statusReport = statusDependencies.reportsByMainUtility.get("Self Reference") if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. @@ -177,15 +174,16 @@ } contextVariables.lastFile = new Date(thisReport.lastFile); - variableArray = thisReport.variableArray; + variable = thisReport.variable; processSingleFiles(); return; } else { - /* - In the case when there is no status report, we assume like the last processed file is the one on the date of Begining of Market. + We are here becuse either: + 1. There is no status report + 2. There is no Last File (this happens on Market Files) */ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Starting from the begining of the market because own status report not found or lastFile was undefined."); } startFromBegining(); @@ -198,18 +196,6 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> startFromBegining -> contextVariables.lastFile = " + contextVariables.lastFile); } - /* - The first time the process is running is the right time to create the data structure that is going to be shared across different executions. - This data structure has one object per each timeFrame. - */ - - variableArray = []; - - for (let i = 0; i < global.dailyFilePeriods.length; i++) { - let emptyObject = {}; - variableArray.push(emptyObject); - } - processSingleFiles(); } @@ -237,7 +223,6 @@ function dependencyLoopBody() { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processSingleFiles -> dependencyLoopBody -> Entering function."); } let dependency = dataDependenciesModule.nodeArray[dependencyIndex]; @@ -266,7 +251,6 @@ function onFileReceived(err, text) { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processSingleFiles -> dependencyLoopBody -> getFile -> onFileReceived -> Entering function."); } if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processSingleFiles -> dependencyLoopBody -> getFile -> onFileReceived -> text = " + text); } @@ -309,22 +293,16 @@ function dependencyControlLoop() { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processSingleFiles -> dependencyControlLoop -> Entering function."); } dependencyIndex++; if (dependencyIndex < dataDependenciesModule.nodeArray.length) { - dependencyLoopBody(); - } else { - let mapKey = "Single Files" multiPeriodDataFiles.set(mapKey, dataFiles) - processMarketFiles(); - } } catch (err) { @@ -344,25 +322,17 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processMarketFiles -> Entering function."); } try { - let n; - timeFramesLoop(); function timeFramesLoop() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processMarketFiles -> timeFramesLoop -> Entering function."); } - /* We will iterate through all posible timeFrames. */ - n = 0 // loop Variable representing each possible period as defined at the timeFrames array. - timeFramesLoopBody(); - } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> processMarketFiles -> timeFramesLoop -> err = " + err.stack); @@ -371,11 +341,8 @@ } function timeFramesLoopBody() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processMarketFiles -> timeFramesLoopBody -> Entering function."); } - const timeFrame = global.marketFilesPeriods[n][0]; const timeFrameLabel = global.marketFilesPeriods[n][1]; @@ -389,9 +356,7 @@ dependencyLoopBody(); function dependencyLoopBody() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processMarketFiles -> timeFramesLoopBody -> dependencyLoopBody -> Entering function."); } let dependency = dataDependenciesModule.nodeArray[dependencyIndex]; @@ -420,9 +385,7 @@ datasetModule.getTextFile(filePath, fileName, onFileReceived); function onFileReceived(err, text) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processMarketFiles -> timeFramesLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> Entering function."); } if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processMarketFiles -> timeFramesLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> text = " + text); } @@ -433,7 +396,7 @@ } else { logger.write(MODULE_NAME, "[ERROR] start -> processMarketFiles -> timeFramesLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = " + err.message); callBackFunction(err); - } + } return; } @@ -454,7 +417,6 @@ callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> processMarketFiles -> timeFramesLoop -> dependencyLoopBody -> err = " + err.stack); @@ -463,24 +425,16 @@ } function dependencyControlLoop() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processMarketFiles -> dependencyControlLoop -> Entering function."); } dependencyIndex++; - if (dependencyIndex < dataDependenciesModule.nodeArray.length) { - dependencyLoopBody(); - } else { - let mapKey = global.marketFilesPeriods[n][1]; multiPeriodDataFiles.set(mapKey, dataFiles) - timeFramesControlLoop(); - } } catch (err) { @@ -496,21 +450,13 @@ } function timeFramesControlLoop() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processMarketFiles -> timeFramesControlLoop -> Entering function."); } - n++; - if (n < global.marketFilesPeriods.length) { - timeFramesLoopBody(); - } else { - processDailyFiles(); - } } catch (err) { @@ -518,7 +464,6 @@ callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> processMarketFiles -> err = " + err.stack); @@ -527,20 +472,14 @@ } function processDailyFiles() { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> Entering function."); } - try { - let n = 0; - if (currentTimeFrame) { callTheBot() return - } - + } bot.multiPeriodProcessDatetime = new Date(contextVariables.lastFile.valueOf() - ONE_DAY_IN_MILISECONDS); // Go back one day to start well when we advance time at the begining of the loop. - advanceTime(); function advanceTime() { @@ -551,12 +490,11 @@ bot.multiPeriodProcessDatetime = new Date(bot.multiPeriodProcessDatetime.valueOf() + ONE_DAY_IN_MILISECONDS); previousDay = new Date(bot.multiPeriodProcessDatetime.valueOf() - ONE_DAY_IN_MILISECONDS); - + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> advanceTime -> bot.multiPeriodProcessDatetime = " + bot.multiPeriodProcessDatetime); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> advanceTime -> previousDay = " + previousDay); } /* Validation that we are not going past the user defined end date. */ - if (bot.multiPeriodProcessDatetime.valueOf() >= bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf()) { const logText = "User Defined End Datetime reached @ " + previousDay.getUTCFullYear() + "/" + (previousDay.getUTCMonth() + 1) + "/" + previousDay.getUTCDate() + "."; @@ -565,11 +503,9 @@ bot.STOP_SESSION = true callBackFunction(global.DEFAULT_OK_RESPONSE); return; - } /* Validation that we are not going past the head of the market. */ - if (bot.multiPeriodProcessDatetime.valueOf() > contextVariables.dateEndOfMarket.valueOf() + ONE_DAY_IN_MILISECONDS - 1) { const logText = "Head of the market found @ " + previousDay.getUTCFullYear() + "/" + (previousDay.getUTCMonth() + 1) + "/" + previousDay.getUTCDate() + "."; @@ -577,7 +513,6 @@ callBackFunction(global.DEFAULT_OK_RESPONSE); return; - } checkStopTaskGracefully(); @@ -591,20 +526,13 @@ function checkStopTaskGracefully() { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> checkStopTaskGracefully -> Entering function."); } - /* Validation that we dont need to stop. */ - if (global.STOP_TASK_GRACEFULLY === true) { - callBackFunction(global.DEFAULT_OK_RESPONSE); return; - } - checkStopProcessing(); - } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> processDailyFiles -> checkStopTaskGracefully -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); @@ -612,18 +540,13 @@ } function checkStopProcessing() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> checkStopProcessing -> Entering function."); } /* Validation that we dont need to stop. */ - if (bot.STOP_SESSION === true) { - callBackFunction(global.DEFAULT_OK_RESPONSE); return; - } timeFramesLoop(); @@ -635,23 +558,16 @@ } function timeFramesLoop() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> timeFramesLoop -> Entering function."); } /* Telling the world we are alive and doing well */ let processingDate = bot.multiPeriodProcessDatetime.getUTCFullYear() + '-' + utilities.pad(bot.multiPeriodProcessDatetime.getUTCMonth() + 1, 2) + '-' + utilities.pad(bot.multiPeriodProcessDatetime.getUTCDate(), 2); - bot.processHeartBeat(processingDate) - + bot.processHeartBeat(processingDate) /* - We will iterate through all posible timeFrames. - */ - n = 0 // loop Variable representing each possible period as defined at the timeFrames array. - timeFramesLoopBody(); } @@ -662,9 +578,7 @@ } function timeFramesLoopBody() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> timeFramesLoopBody -> Entering function."); } const timeFrame = global.dailyFilePeriods[n][0]; @@ -693,9 +607,7 @@ dependencyLoopBody(); function dependencyLoopBody() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> timeFramesLoopBody -> dependencyLoopBody -> Entering function."); } let dependency = dataDependenciesModule.nodeArray[dependencyIndex]; @@ -735,14 +647,12 @@ } else { filePath = dependency.referenceParent.parentNode.code.codeName + '/' + dependency.referenceParent.code.codeName + "/" + dateForPath; } - let fileName = "Data.json"; + let fileName = "Data.json"; datasetModule.getTextFile(filePath, fileName, onFileReceived); function onFileReceived(err, text) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> timeFramesLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> Entering function."); } if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> timeFramesLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> text = " + text); } @@ -776,7 +686,6 @@ } previousFile = JSON.parse(text); - getCurrentFile(); } @@ -815,14 +724,12 @@ } else { filePath = dependency.referenceParent.parentNode.code.codeName + '/' + dependency.referenceParent.code.codeName + "/" + dateForPath; } - let fileName = "Data.json"; + let fileName = "Data.json"; datasetModule.getTextFile(filePath, fileName, onFileReceived); function onFileReceived(err, text) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> timeFramesLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> Entering function."); } if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> timeFramesLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> text = " + text); } @@ -841,11 +748,8 @@ } currentFile = JSON.parse(text); - let dataFile = previousFile.concat(currentFile); - dataFiles.set(dependency.id, dataFile); - dependencyControlLoop(); } @@ -868,24 +772,16 @@ } function dependencyControlLoop() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> dependencyControlLoop -> Entering function."); } - dependencyIndex++; if (dependencyIndex < dataDependenciesModule.nodeArray.length) { - dependencyLoopBody(); - } else { - let mapKey = global.dailyFilePeriods[n][1]; multiPeriodDataFiles.set(mapKey, dataFiles) - timeFramesControlLoop(); - } } catch (err) { @@ -902,25 +798,17 @@ } function timeFramesControlLoop() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> timeFramesControlLoop -> Entering function."); } - n++; - if (n < global.dailyFilePeriods.length) { - timeFramesLoopBody(); - } else { - n = 0; - if (currentTimeFrame !== undefined) { callTheBot(); } else { - logger.write(MODULE_NAME, "[ERROR] start -> processDailyFiles -> timeFramesControlLoop -> Time Frame not Recognized. Can not continue." ); + logger.write(MODULE_NAME, "[ERROR] start -> processDailyFiles -> timeFramesControlLoop -> Time Frame not Recognized. Can not continue."); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -932,25 +820,19 @@ } function callTheBot() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> callTheBot -> Entering function."); } - botInstance.start( multiPeriodDataFiles, currentTimeFrame, currentTimeFrameLabel, bot.multiPeriodProcessDatetime, - variableArray[n], + variable, onBotFinished); function onBotFinished(err) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> callTheBot -> onBotFinished -> Entering function."); } - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { callBackFunction(err); return; @@ -966,9 +848,7 @@ } function onWritten(err) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> callTheBot -> onBotFinished -> onWritten -> Entering function."); } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { @@ -978,7 +858,6 @@ } writeDailyStatusReport(bot.multiPeriodProcessDatetime, onDailyStatusReport); - } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> processDailyFiles -> callTheBot -> onBotFinished -> onWritten -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); @@ -991,7 +870,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> callTheBot -> onBotFinished -> onDailyStatusReport -> Entering function."); } /* The next run we need the process to continue at the date it finished. */ - processConfig.framework.startDate.resumeExecution = true; + processConfig.framework.startDate.resumeExecution = true; advanceTime(); } catch (err) { @@ -1005,7 +884,6 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> callTheBot -> onBotFinished -> onMarketStatusReport -> Entering function."); } /* This is where we check if we need reached the user defined end datetime. */ - const now = new Date() if (now.valueOf() >= bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf()) { @@ -1044,9 +922,7 @@ } function writeDataRanges(currentTimeFrameLabel, callBack) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRanges -> Entering function."); } let outputDatasetIndex = -1; @@ -1058,9 +934,7 @@ } function controlLoop() { - outputDatasetIndex++; - if (outputDatasetIndex < bot.processNode.referenceParent.processOutput.outputDatasets.length) { productLoopBody(); } else { @@ -1076,25 +950,20 @@ } function writeDataRange(pBegin, pEnd, productCodeName, currentTimeFrameLabel, callBack) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> Entering function."); } - let dataRange = { begin: pBegin.valueOf(), end: pEnd.valueOf() + ONE_DAY_IN_MILISECONDS }; let fileContent = JSON.stringify(dataRange); - let fileName = '/Data.Range.json'; let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + productCodeName + "/" + 'Multi-Period-Daily' + fileName; fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Entering function."); } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { @@ -1107,11 +976,11 @@ logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Content written = " + fileContent); } - let key = bot.dataMine + "-" + bot.codeName + "-" + productCodeName + "-" + bot.exchange + "-" + bot.market.baseAsset + '/' + bot.market.quotedAsset + let key = bot.dataMine + "-" + bot.codeName + "-" + productCodeName + "-" + bot.exchange + "-" + bot.market.baseAsset + '/' + bot.market.quotedAsset let event = { dateRange: dataRange } - + global.EVENT_SERVER_CLIENT.raiseEvent(key, 'Data Range Updated', event) callBack(global.DEFAULT_OK_RESPONSE); @@ -1124,22 +993,19 @@ } function writeDailyStatusReport(lastFileDate, callBack) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyStatusReport -> Entering function."); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyStatusReport -> lastFileDate = " + lastFileDate); } try { - let reportKey = bot.dataMine + "-" + bot.codeName + "-" + "Multi-Period" + "-" + "dataSet.V1"; let thisReport = statusDependencies.statusReports.get(reportKey); thisReport.file.lastExecution = bot.currentDaytime; thisReport.file.lastFile = lastFileDate; - thisReport.file.variableArray = variableArray; + thisReport.file.variable = variable; thisReport.save(callBack); bot.hasTheBotJustStarted = false; - } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> writeDailyStatusReport -> err = " + err.stack); @@ -1148,15 +1014,13 @@ } function writeMarketStatusReport(callBack) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketStatusReport -> Entering function."); } - try { - let reportKey = bot.dataMine + "-" + bot.codeName + "-" + "Multi-Period" + "-" + "dataSet.V1"; let thisReport = statusDependencies.statusReports.get(reportKey); thisReport.file.lastExecution = bot.processDatetime; + thisReport.file.variable = variable; thisReport.save(callBack); logger.newInternalLoop(bot.codeName, bot.process, bot.multiPeriodProcessDatetime); @@ -1166,15 +1030,12 @@ callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - } - catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - function pad(str, max) { str = str.toString(); return str.length < max ? pad(" " + str, max) : str; diff --git a/Session.js b/Session.js index 9ae1f99f4..8e0c985bd 100644 --- a/Session.js +++ b/Session.js @@ -5,7 +5,7 @@ const ONE_YEAR_IN_MILISECONDS = 365 * 24 * 60 * 60 * 1000 let thisObject = { - initialize: initialize + initialize: initialize } return thisObject; @@ -17,10 +17,10 @@ let telegramAPI /* Initialize this info so that everything is logged propeerly */ - + bot.SESSION = { name: bot.processNode.session.name, - id: bot.processNode.session.id + id: bot.processNode.session.id } /* Set the folderName for early logging */ @@ -29,7 +29,7 @@ } else { bot.SESSION.folderName = bot.processNode.session.code.folderName + "-" + bot.SESSION.id } - + /* Check if there is a session */ if (bot.processNode.session === undefined) { parentLogger.write(MODULE_NAME, "[ERROR] initialize -> Cannot run without a Session."); @@ -40,7 +40,7 @@ /* Listen to event to start or stop the session. */ bot.sessionKey = bot.processNode.session.name + '-' + bot.processNode.session.type + '-' + bot.processNode.session.id global.SESSION_MAP.set(bot.sessionKey, bot.sessionKey) - + global.EVENT_SERVER_CLIENT.listenToEvent(bot.sessionKey, 'Run Session', undefined, bot.sessionKey, undefined, runSession) global.EVENT_SERVER_CLIENT.listenToEvent(bot.sessionKey, 'Stop Session', undefined, bot.sessionKey, undefined, stopSession) @@ -56,6 +56,7 @@ bot.TRADING_SYSTEM = JSON.parse(message.event.tradingSystem) bot.SESSION = JSON.parse(message.event.session) bot.DEPENDENCY_FILTER = JSON.parse(message.event.dependencyFilter) + bot.RESUME = message.event.resume /* Set the folderName for logging, reports, context and data output */ let code @@ -133,7 +134,7 @@ } bot.resumeExecution = false; bot.hasTheBotJustStarted = true - bot.multiPeriodProcessDatetime = new Date(bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) + bot.multiPeriodProcessDatetime = new Date(bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) return true } @@ -148,7 +149,7 @@ bot.startMode = "Live" checkDatetimes() bot.resumeExecution = false; - bot.multiPeriodProcessDatetime = new Date(bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) + bot.multiPeriodProcessDatetime = new Date(bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) bot.hasTheBotJustStarted = true pProcessConfig.liveWaitTime = getTimeFrameFromLabel(bot.VALUES_TO_USE.timeFrame) return true @@ -165,23 +166,23 @@ bot.startMode = "Live" checkDatetimes() bot.resumeExecution = false; - bot.multiPeriodProcessDatetime = new Date(bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) + bot.multiPeriodProcessDatetime = new Date(bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) bot.hasTheBotJustStarted = true /* Reduce the balance */ let balancePercentage = 1 // This is the default value - + if (bot.SESSION.code.balancePercentage !== undefined) { balancePercentage = bot.SESSION.code.balancePercentage } bot.VALUES_TO_USE.initialBalanceA = bot.VALUES_TO_USE.initialBalanceA * balancePercentage / 100 bot.VALUES_TO_USE.initialBalanceB = bot.VALUES_TO_USE.initialBalanceB * balancePercentage / 100 - + bot.VALUES_TO_USE.minimumBalanceA = bot.VALUES_TO_USE.minimumBalanceA * balancePercentage / 100 bot.VALUES_TO_USE.minimumBalanceB = bot.VALUES_TO_USE.minimumBalanceB * balancePercentage / 100 - + bot.VALUES_TO_USE.maximumBalanceA = bot.VALUES_TO_USE.maximumBalanceA * balancePercentage / 100 bot.VALUES_TO_USE.maximumBalanceB = bot.VALUES_TO_USE.maximumBalanceB * balancePercentage / 100 @@ -192,11 +193,11 @@ function startPaperTrading(message) { bot.startMode = "Backtest" - + checkDatetimes() bot.resumeExecution = false; bot.hasTheBotJustStarted = true - bot.multiPeriodProcessDatetime = new Date(bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) + bot.multiPeriodProcessDatetime = new Date(bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) pProcessConfig.normalWaitTime = getTimeFrameFromLabel(bot.VALUES_TO_USE.timeFrame) return true } @@ -270,7 +271,7 @@ } } - let tradingSystem = bot.TRADING_SYSTEM + let tradingSystem = bot.TRADING_SYSTEM if (tradingSystem !== undefined) { @@ -429,7 +430,7 @@ let socialBot = bot.SESSION.socialBots.bots[i] if (socialBot.type === "Telegram Bot") { let code = socialBot.code - socialBot.botInstance = initializeTelegramBot(code.botToken, code.chatId) + socialBot.botInstance = initializeTelegramBot(code.botToken, code.chatId) } } } @@ -440,7 +441,7 @@ let socialBot = bot.SESSION.socialBots.bots[i] try { let code = announcement.code - + if (socialBot.type === "Telegram Bot") { if (announcement.formulaValue !== undefined) { socialBot.botInstance.telegramAPI.sendMessage(socialBot.botInstance.chatId, announcement.formulaValue).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> initializeSocialBots -> announce -> Telegram API error -> err = " + err)) @@ -448,7 +449,7 @@ socialBot.botInstance.telegramAPI.sendMessage(socialBot.botInstance.chatId, code.text).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> initializeSocialBots -> announce -> Telegram API error -> err = " + err)) } } - + } catch (err) { parentLogger.write(MODULE_NAME, "[WARN] initialize -> initializeSocialBots -> announce -> err = " + err.stack); } @@ -461,7 +462,7 @@ } function finalizeSocialBots() { - if (bot.SESSION.socialBots === undefined) {return} + if (bot.SESSION.socialBots === undefined) { return } if (bot.SESSION.socialBots.bots !== undefined) { for (let i = 0; i < bot.SESSION.socialBots.bots.length; i++) { let socialBot = bot.SESSION.socialBots.bots[i] @@ -488,8 +489,8 @@ telegramAPI = new Telegram(botToken) - const messge = bot.SESSION.type + " '" + bot.SESSION.name + "' was started with an initial balance of " + " " + bot.VALUES_TO_USE.initialBalanceA + " " + bot.VALUES_TO_USE.baseAsset + "." - telegramAPI.sendMessage(chatId, messge ).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> initializeTelegramBot -> Telegram API error -> err = " + err)) + const messge = bot.SESSION.type + " '" + bot.SESSION.name + "' was started with an initial balance of " + " " + bot.VALUES_TO_USE.initialBalanceA + " " + bot.VALUES_TO_USE.baseAsset + "." + telegramAPI.sendMessage(chatId, messge).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> initializeTelegramBot -> Telegram API error -> err = " + err)) let botInstance = { telegramBot: telegramBot, @@ -504,10 +505,10 @@ } function finalizeTelegramBot(chatId) { - const messge = bot.SESSION.type + " '" + bot.SESSION.name + "' was stopped." + const messge = bot.SESSION.type + " '" + bot.SESSION.name + "' was stopped." telegramAPI.sendMessage(chatId, messge).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> initializeTelegramBot -> Telegram API error -> err = " + err)) } - + } catch (err) { parentLogger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); diff --git a/TradingBot.js b/TradingBot.js index e5a47c3c2..699ccf512 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -117,10 +117,10 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000 - let recordsArray - let conditionsArray - let strategiesArray - let positionsArray + let recordsArray = [] + let conditionsArray = [] + let strategiesArray = [] + let positionsArray = [] let snapshotHeaders let triggerOnSnapshot @@ -128,7 +128,11 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR let tradingSystem = {} - readFiles() + if (bot.RESUME === true) { + readFiles() + } else { + runSimulation() + } function readFiles() { diff --git a/TradingSimulation.js b/TradingSimulation.js index df1e148d1..621fdf38a 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -217,18 +217,41 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT function initializeLoop() { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> initializeLoop -> Entering function.') } - /* Estimate Initial Candle */ + if (bot.RESUME === true && variable.last.candle !== undefined) { + /* Estimate the Initial Candle based on the last candle saved at variable */ + let firstBegin = candles[0].begin + let lastBegin = variable.last.candle.begin + let diff = lastBegin - firstBegin + let amount = diff / variable.episode.parameters.timeFrame - let firstEnd = candles[0].end - let targetEnd = bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf() - let diff = targetEnd - firstEnd - let amount = diff / variable.episode.parameters.timeFrame + currentCandleIndex = Math.trunc(amount) + 1 // Because we need to start from the next candle + if (currentCandleIndex < 0 || currentCandleIndex > candles.length - 1) { + logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> Cannot resume simulation.') + logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> currentCandleIndex = ' + currentCandleIndex) + logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> firstBegin = ' + firstBegin) + logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> lastBegin = ' + lastBegin) + logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> diff = ' + diff) + logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> amount = ' + amount) - currentCandleIndex = Math.trunc(amount) - if (currentCandleIndex < 0) { currentCandleIndex = 0 } - if (currentCandleIndex > candles.length - 1) { - /* This will happen when the bot.VALUES_TO_USE.timeRange.initialDatetime is beyond the last candle available, meaning that the dataSet needs to be updated with more up-to-date data. */ - currentCandleIndex = candles.length - 1 + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + return + } + } else { + /* Estimate Initial Candle based on the timeRage configured for the session. */ + let firstEnd = candles[0].end + let targetEnd = bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf() + let diff = targetEnd - firstEnd + let amount = diff / variable.episode.parameters.timeFrame + + currentCandleIndex = Math.trunc(amount) + if (currentCandleIndex < 0) { currentCandleIndex = 0 } + if (currentCandleIndex > candles.length - 1) { + /* + This will happen when the bot.VALUES_TO_USE.timeRange.initialDatetime is beyond the last candle available, + meaning that the dataSet needs to be updated with more up-to-date data. + */ + currentCandleIndex = candles.length - 1 + } } loop() @@ -2088,6 +2111,9 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT addStrategyRecord() addPositionRecord() + /* We will remmember the last candle processed, so that if it is the last one of this run we can use it to continue from there next time. */ + variable.last.candle = candle + /* After everything at the simulation level was done, we will do the annoucements that are pending. */ makeAnnoucements() From 0631cbd16d3735c7e62a19e4500bc0311bb11dbd Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 22 May 2020 14:08:31 +0200 Subject: [PATCH 40/44] Resume working --- FileStorage.js | 80 ++++++++++++++++++++++---------------------- MultiPeriod.js | 9 ++--- StatusReport.js | 28 ++++++++-------- TradingSimulation.js | 5 ++- 4 files changed, 61 insertions(+), 61 deletions(-) diff --git a/FileStorage.js b/FileStorage.js index 22966c706..bec9ef69a 100644 --- a/FileStorage.js +++ b/FileStorage.js @@ -22,11 +22,11 @@ exports.newFileStorage = function newFileStorage(logger, host, port) { deleteTextFile: deleteTextFile } - return thisObject + return thisObject function getTextFile(filePath, callBackFunction, noRetry, canUsePrevious) { - let currentRetryGetTextFile = 0 + let currentRetryGetTextFile = 0 recursiveGetTextFile(filePath, callBackFunction, noRetry, canUsePrevious) @@ -77,7 +77,7 @@ exports.newFileStorage = function newFileStorage(logger, host, port) { } callBackFunction(customResponse) return - } + } fileDoesNotExist = true logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> File does not exist. Retrying. ') @@ -106,7 +106,7 @@ exports.newFileStorage = function newFileStorage(logger, host, port) { if (mustBeJason === false) { /* In this case there is nothing else to check. */ callBackFunction(global.DEFAULT_OK_RESPONSE, text.toString()) - return + return } /* @@ -117,7 +117,7 @@ exports.newFileStorage = function newFileStorage(logger, host, port) { /* The file was correctly read and could be parsed. */ callBackFunction(global.DEFAULT_OK_RESPONSE, text.toString()) - return + return } catch (err) { @@ -140,11 +140,11 @@ exports.newFileStorage = function newFileStorage(logger, host, port) { logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> canUsePrevious -> err = ' + err.stack) callBackFunction(global.DEFAULT_FAIL_RESPONSE) return - } + } /* Returning the previous file */ callBackFunction(global.DEFAULT_OK_RESPONSE, text.toString()) - return + return } } else { logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Could read the file, but could not parse it as it is not a valid JSON.') @@ -153,12 +153,12 @@ exports.newFileStorage = function newFileStorage(logger, host, port) { setTimeout(retry, retryTimeToUse) return } - } + } } } catch (err) { - logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> Error writing file -> file = ' + fileLocation) - logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> Error writing file -> err = ' + err.stack) + logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> Error reading file -> file = ' + fileLocation) + logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> Error reading file -> err = ' + err.stack) retry() } @@ -252,7 +252,7 @@ exports.newFileStorage = function newFileStorage(logger, host, port) { logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error deleting file -> err = ' + err.stack) setTimeout(retry, retryTimeToUse) return - } + } /* Rename de Original into Previous */ fs.rename(fileLocation, fileLocation + '.Previous.json', onOriginalRenamed) @@ -266,7 +266,7 @@ exports.newFileStorage = function newFileStorage(logger, host, port) { logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onOriginalRenamed -> Error renaming original file -> file = ' + fileLocation) logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onOriginalRenamed -> Error renaming original file -> err = ' + err.stack) setTimeout(retry, retryTimeToUse) - return + return } /* Rename de Temp into Original */ @@ -282,13 +282,13 @@ exports.newFileStorage = function newFileStorage(logger, host, port) { callBackFunction(global.DEFAULT_OK_RESPONSE) } - } + } } } } else { /* In this case, there is no need to keep a copy of the file being replaced, so we just delete and that's it. */ - fs.unlink(fileLocation , onUnlinked) + fs.unlink(fileLocation, onUnlinked) function onUnlinked(err) { let code = '' @@ -296,11 +296,11 @@ exports.newFileStorage = function newFileStorage(logger, host, port) { code = err.code } if (code !== '' && code !== 'ENOENT') { - logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error deleting file -> file = ' + fileLocation ) + logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error deleting file -> file = ' + fileLocation) logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error deleting file -> err = ' + err.stack) setTimeout(retry, retryTimeToUse) return - } + } /* Rename de Temp into Original */ fs.rename(fileLocation + '.tmp', fileLocation, onTempRenamed) @@ -406,33 +406,33 @@ exports.newFileStorage = function newFileStorage(logger, host, port) { /* Function to create folders of missing folders at any path. */ function mkDirByPathSync(targetDir, { isRelativeToScript = false } = {}) { - const sep = '/'; - const initDir = path.isAbsolute(targetDir) ? sep : ''; - const baseDir = isRelativeToScript ? __dirname : '.'; + const sep = '/'; + const initDir = path.isAbsolute(targetDir) ? sep : ''; + const baseDir = isRelativeToScript ? __dirname : '.'; - return targetDir.split(sep).reduce((parentDir, childDir) => { - const curDir = path.resolve(baseDir, parentDir, childDir); - try { - const fs = require('fs') - fs.mkdirSync(curDir); - } catch (err) { - if (err.code === 'EEXIST') { // curDir already exists! - return curDir; - } + return targetDir.split(sep).reduce((parentDir, childDir) => { + const curDir = path.resolve(baseDir, parentDir, childDir); + try { + const fs = require('fs') + fs.mkdirSync(curDir); + } catch (err) { + if (err.code === 'EEXIST') { // curDir already exists! + return curDir; + } - // To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows. - if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure. - throw new Error(`EACCES: permission denied, mkdir '${parentDir}'`); - } + // To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows. + if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure. + throw new Error(`EACCES: permission denied, mkdir '${parentDir}'`); + } - const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1; - if (!caughtErr || caughtErr && curDir === path.resolve(targetDir)) { - throw err; // Throw if it's just the last created dir. - } - } + const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1; + if (!caughtErr || caughtErr && curDir === path.resolve(targetDir)) { + throw err; // Throw if it's just the last created dir. + } + } - return curDir; - }, initDir); + return curDir; + }, initDir); } function getFileViaHTTP(filePath, callback, callBackFunction) { @@ -455,7 +455,7 @@ exports.newFileStorage = function newFileStorage(logger, host, port) { logger.write(MODULE_NAME, "[ERROR] getFileViaHTTP -> onError -> err = " + err.stack); logger.write(MODULE_NAME, "[ERROR] getFileViaHTTP -> onError -> Failed to fetch file via HTTP. Will retry later. "); callBackFunction(global.DEFAULT_RETRY_RESPONSE); - }) + }) function onResponse(response) { diff --git a/MultiPeriod.js b/MultiPeriod.js index 984e45e26..219357a95 100644 --- a/MultiPeriod.js +++ b/MultiPeriod.js @@ -86,7 +86,7 @@ let previousDay; // Holds the date of the previous day relative to the processing date. - let variable = {} + let variable getContextVariables(); @@ -163,19 +163,17 @@ } thisReport = statusReport.file; + variable = thisReport.variable; + if (variable === undefined) { variable = {} } // This should happen only when there is no status report if (thisReport.lastFile !== undefined) { - if (bot.hasTheBotJustStarted === true && bot.resumeExecution === false) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Starting from the begining because bot has just started and resume execution was true."); } startFromBegining(); return; } - contextVariables.lastFile = new Date(thisReport.lastFile); - variable = thisReport.variable; - processSingleFiles(); return; @@ -195,7 +193,6 @@ contextVariables.lastFile = new Date(contextVariables.dateBeginOfMarket.getUTCFullYear() + "-" + (contextVariables.dateBeginOfMarket.getUTCMonth() + 1) + "-" + contextVariables.dateBeginOfMarket.getUTCDate() + " " + "00:00" + GMT_SECONDS); if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> startFromBegining -> contextVariables.lastFile = " + contextVariables.lastFile); } - processSingleFiles(); } diff --git a/StatusReport.js b/StatusReport.js index 0ae6bc288..65609aa40 100644 --- a/StatusReport.js +++ b/StatusReport.js @@ -23,7 +23,7 @@ status: undefined }; - let statusDependencyNode; + let statusDependencyNode; /* Utilities needed. */ @@ -32,7 +32,7 @@ /* Storage account to be used here. */ const FILE_STORAGE = require('./FileStorage.js'); - let fileStorage + let fileStorage let sessionPath = '' @@ -119,13 +119,13 @@ for (let i = 0; i < network.networkNodes.length; i++) { let networkNode = network.networkNodes[i] - + if (checkThisBranch(networkNode.dataMining) === true) { return } - if (checkThisBranch(networkNode.testingEnvironment) === true) {return} + if (checkThisBranch(networkNode.testingEnvironment) === true) { return } if (checkThisBranch(networkNode.productionEnvironment) === true) { return } function checkThisBranch(branch) { - if (branch === undefined) {return} + if (branch === undefined) { return } for (let j = 0; j < branch.exchangeTasks.length; j++) { let exchangeTasks = branch.exchangeTasks[j] for (let k = 0; k < exchangeTasks.taskManagers.length; k++) { @@ -183,7 +183,7 @@ callBackFunction(global.DEFAULT_FAIL_RESPONSE); } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -211,9 +211,9 @@ let rootPath = bot.exchange + "/" + bot.market.baseAsset + "-" + bot.market.quotedAsset + "/" + statusDependencyNode.dataMine + "/" + statusDependencyNode.bot - filePath = rootPath + "/Reports/" + sessionPath + statusDependencyNode.process ; + filePath = rootPath + "/Reports/" + sessionPath + statusDependencyNode.process; } else { - filePath = bot.filePathRoot + "/Reports/" + sessionPath + statusDependencyNode.process ; + filePath = bot.filePathRoot + "/Reports/" + sessionPath + statusDependencyNode.process; } filePath += '/' + fileName @@ -236,10 +236,10 @@ function onFileReceived(err, text) { - if ( err.result === global.CUSTOM_FAIL_RESPONSE.result && (err.message === 'Folder does not exist.' || err.message === 'File does not exist.') + if (err.result === global.CUSTOM_FAIL_RESPONSE.result && (err.message === 'Folder does not exist.' || err.message === 'File does not exist.') || err.code === "The specified key does not exist.") { - logger.write(MODULE_NAME, "[INFO] load -> onFileReceived -> err = "+ err.stack); + logger.write(MODULE_NAME, "[INFO] load -> onFileReceived -> err = " + err.message); /* In this case we can assume that this is the first execution ever of this bot.*/ @@ -255,7 +255,7 @@ } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] load -> onFileReceived -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] load -> onFileReceived -> err = " + err.message); callBackFunction(err); return; } @@ -290,7 +290,7 @@ } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] load -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] load -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -328,7 +328,7 @@ if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] save -> onFileCreated -> Entering function."); } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] save -> onFileCreated -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] save -> onFileCreated -> err = " + err.stack); callBackFunction(err); return; } @@ -348,7 +348,7 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] save -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] save -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } diff --git a/TradingSimulation.js b/TradingSimulation.js index 621fdf38a..5014e1f1a 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -2112,7 +2112,10 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT addPositionRecord() /* We will remmember the last candle processed, so that if it is the last one of this run we can use it to continue from there next time. */ - variable.last.candle = candle + variable.last.candle = { + begin: candle.begin, + end: candle.end + } /* After everything at the simulation level was done, we will do the annoucements that are pending. */ makeAnnoucements() From b9e365254611f22614f9b1ad9316b853fac5e573 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 22 May 2020 14:54:42 +0200 Subject: [PATCH 41/44] multiple loops should resume --- MultiPeriod.js | 3 ++- TradingSimulation.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/MultiPeriod.js b/MultiPeriod.js index 219357a95..f29d1c0fa 100644 --- a/MultiPeriod.js +++ b/MultiPeriod.js @@ -835,7 +835,8 @@ return; } - botNeverRan = false; + botNeverRan = false + bot.RESUME = true // From here on, all other loops executions must resume from where we left at this current run. if (currentTimeFrame > global.dailyFilePeriods[0][0]) { writeMarketStatusReport(onMarketStatusReport) diff --git a/TradingSimulation.js b/TradingSimulation.js index 5014e1f1a..d55c3db4e 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -78,7 +78,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT lastInstantOfTheDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1 } - if (variable.isInitialized !== true) { + if (variable.isInitialized !== true || bot.RESUME === false) { variable.isInitialized = true variable.episode = {} // An Episode represents each execution of the Simulation From cee52418f87cd1cde54ff872ec38eb273ec56015 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 23 May 2020 14:08:35 +0200 Subject: [PATCH 42/44] Slipt code into config --- Commons.js | 58 +++++++++---------- DataSet.js | 30 +++++----- IndicatorBot.js | 18 +++--- MultiPeriod.js | 40 ++++++------- MultiPeriodDaily.js | 76 ++++++++++++------------- MultiPeriodMarket.js | 44 +++++++-------- ProcessExecutionEvents.js | 26 ++++----- ProcessOutput.js | 24 ++++---- Root.js | 48 ++++++++-------- Session.js | 114 +++++++++++++++++++------------------- StatusReport.js | 22 ++++---- TradingSimulation.js | 22 ++++---- server.js | 30 +++++----- 13 files changed, 276 insertions(+), 276 deletions(-) diff --git a/Commons.js b/Commons.js index fcc9ded0b..bea993f51 100644 --- a/Commons.js +++ b/Commons.js @@ -12,7 +12,7 @@ validateOutputDatasets: validateOutputDatasets, inflateDatafiles: inflateDatafiles, dataBuildingProcedure: dataBuildingProcedure, - calculationsProcedure: calculationsProcedure, + calculationsProcedure: calculationsProcedure, generateFileContent: generateFileContent, writeFile: writeFile }; @@ -25,15 +25,15 @@ function validateDataDependencies(dataDependencies, callBackFunction) { for (let i = 0; i < dataDependencies.length; i++) { - let dataDependencyNode = dataDependencies[i] + let dataDependencyNode = dataDependencies[i] /* Basic validations to see if we have everything we need. */ - if (dataDependencyNode.referenceParent.parentNode.code.singularVariableName === undefined) { + if (dataDependencyNode.referenceParent.parentNode.config.singularVariableName === undefined) { logger.write(MODULE_NAME, "[ERROR] start -> Product Definition without a Single Variable Name defined. Product Definition = " + JSON.stringify(dataDependencyNode.referenceParent.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return } - if (dataDependencyNode.referenceParent.parentNode.code.pluralVariableName === undefined) { + if (dataDependencyNode.referenceParent.parentNode.config.pluralVariableName === undefined) { logger.write(MODULE_NAME, "[ERROR] start -> Product Definition without a Plural Variable Name defined. Product Definition = " + JSON.stringify(dataDependencyNode.referenceParent.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return @@ -61,12 +61,12 @@ callBackFunction(global.DEFAULT_FAIL_RESPONSE); return } - if (outputDatasetNode.referenceParent.parentNode.code.singularVariableName === undefined) { + if (outputDatasetNode.referenceParent.parentNode.config.singularVariableName === undefined) { logger.write(MODULE_NAME, "[ERROR] start -> Product Definition without a Single Variable Name defined. Product Definition = " + JSON.stringify(outputDatasetNode.referenceParent.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return } - if (outputDatasetNode.referenceParent.parentNode.code.pluralVariableName === undefined) { + if (outputDatasetNode.referenceParent.parentNode.config.pluralVariableName === undefined) { logger.write(MODULE_NAME, "[ERROR] start -> Product Definition without a Plural Variable Name defined. Product Definition = " + JSON.stringify(outputDatasetNode.referenceParent.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return @@ -79,7 +79,7 @@ if (outputDatasetNode.referenceParent.parentNode.dataBuilding === undefined) { logger.write(MODULE_NAME, "[WARN] start -> Product Definition " + outputDatasetNode.referenceParent.parentNode.name + " without a Data Building Procedure. Product Definition = " + JSON.stringify(outputDatasetNode.referenceParent.parentNode)); } - if (outputDatasetNode.referenceParent.code.codeName === undefined) { + if (outputDatasetNode.referenceParent.config.codeName === undefined) { logger.write(MODULE_NAME, "[ERROR] start -> Dataset witn no codeName defined. Product Dataset = " + JSON.stringify(outputDatasetNode.referenceParent)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return @@ -91,7 +91,7 @@ return } - if (outputDatasetNode.referenceParent.parentNode.code.codeName === undefined) { + if (outputDatasetNode.referenceParent.parentNode.config.codeName === undefined) { logger.write(MODULE_NAME, "[ERROR] start -> Product Definition witn no codeName defined. Product Definition = " + JSON.stringify(outputDatasetNode.referenceParent.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return @@ -103,7 +103,7 @@ return } - if (outputDatasetNode.referenceParent.parentNode.parentNode.code.codeName === undefined) { + if (outputDatasetNode.referenceParent.parentNode.parentNode.config.codeName === undefined) { logger.write(MODULE_NAME, "[ERROR] start -> Bot witn no codeName defined. Bot = " + JSON.stringify(outputDatasetNode.referenceParent.parentNode.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return @@ -115,7 +115,7 @@ return } - if (outputDatasetNode.referenceParent.parentNode.parentNode.parentNode.code.codeName === undefined) { + if (outputDatasetNode.referenceParent.parentNode.parentNode.parentNode.config.codeName === undefined) { logger.write(MODULE_NAME, "[ERROR] start -> Data Mine witn no codeName defined. Data Mine = " + JSON.stringify(outputDatasetNode.referenceParent.parentNode.parentNode.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return @@ -132,19 +132,19 @@ */ for (let i = 0; i < dataDependencies.length; i++) { - let dataFile + let dataFile let jsonData // Datafile converted into Json objects let inputData // Includes calculated properties let singularVariableName // name of the variable for this product let recordDefinition - let dataDependencyNode = dataDependencies[i] + let dataDependencyNode = dataDependencies[i] dataFile = dataFiles.get(dataDependencyNode.id) if (dataFile === undefined) { continue } // When a datafile is not found it might be because we are processing market or daily and at the dependency array there are both types mixed up. recordDefinition = dataDependencyNode.referenceParent.parentNode.record - singularVariableName = dataDependencyNode.referenceParent.parentNode.code.singularVariableName + singularVariableName = dataDependencyNode.referenceParent.parentNode.config.singularVariableName /* Transform the raw data into JSON objects */ jsonData = jsonifyDataFile(dataFile, recordDefinition) /* Add the calculated properties */ @@ -153,7 +153,7 @@ } else { inputData = jsonData } - products[dataDependencyNode.referenceParent.parentNode.code.pluralVariableName] = inputData + products[dataDependencyNode.referenceParent.parentNode.config.pluralVariableName] = inputData /* The main dependency is defined as the first dependency processed. */ if (mainDependency.records === undefined) { @@ -177,8 +177,8 @@ let record = {} for (let j = 0; j < recordDefinition.properties.length; j++) { let property = recordDefinition.properties[j] - if (property.code.isCalculated !== true) { - record[property.code.codeName] = dataFile[i][j] + if (property.config.isCalculated !== true) { + record[property.config.codeName] = dataFile[i][j] } } @@ -238,13 +238,13 @@ /* For each calculated property we apply its formula*/ for (let j = 0; j < recordDefinition.properties.length; j++) { let property = recordDefinition.properties[j] - if (property.code.isCalculated === true) { + if (property.config.isCalculated === true) { if (property.formula !== undefined) { if (property.formula.code !== undefined) { try { let newValue = eval(property.formula.code) let currentRecord = product[variableName] - currentRecord[property.code.codeName] = newValue + currentRecord[property.config.codeName] = newValue } catch (err) { logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> loop -> formula -> Error executing User Code. Error = " + err.stack) logger.write(MODULE_NAME, "[ERROR] calculationsProcedure -> loop -> formula -> Error executing User Code. product = " + JSON.stringify(product)) @@ -277,7 +277,7 @@ interExecutionMemory, processingDailyFiles, currentDay - ) { + ) { /* This function has as an input the products object, with all the information @@ -286,7 +286,7 @@ a new set of information. */ - let lastInstantOfTheDay + let lastInstantOfTheDay let yesterday = {} let system = { // These are the available system variables to be used in User Code and Formulas timeFrame: timeFrame, @@ -313,7 +313,7 @@ let dataDependencyMap = new Map() for (let j = 0; j < dataDependecyArray.length; j++) { let record = dataDependecyArray[j] - let key = record.begin.toString() + '-' + record.end.toString() + let key = record.begin.toString() + '-' + record.end.toString() dataDependencyMap.set(key, record) } dataDependencies[dataDependencyName] = dataDependencyMap @@ -321,7 +321,7 @@ } function getElement(dependencyName, currentRecordPrimaryDataDependency) { - let key = currentRecordPrimaryDataDependency.begin.toString() + '-' + currentRecordPrimaryDataDependency.end.toString() + let key = currentRecordPrimaryDataDependency.begin.toString() + '-' + currentRecordPrimaryDataDependency.end.toString() return dataDependencies[dependencyName].get(key) } @@ -349,7 +349,7 @@ } else { /* We override the initialization, since the valid stuff is already at the Inter Execution Memory */ - variable = JSON.parse(JSON.stringify(interExecutionMemory[productName].variable)) + variable = JSON.parse(JSON.stringify(interExecutionMemory[productName].variable)) } } @@ -387,13 +387,13 @@ /* For each non-calculated property we apply its formula*/ for (let j = 0; j < recordDefinition.properties.length; j++) { let property = recordDefinition.properties[j] - if (property.code.isCalculated !== true) { + if (property.config.isCalculated !== true) { if (property.formula !== undefined) { if (property.formula.code !== undefined) { try { let newValue = eval(property.formula.code) let currentRecord = product[variableName] - currentRecord[property.code.codeName] = newValue + currentRecord[property.config.codeName] = newValue } catch (err) { logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> loop -> formula -> Error executing User Code. Error = " + err.stack) logger.write(MODULE_NAME, "[ERROR] dataBuildingProcedure -> loop -> formula -> Error executing User Code. product = " + JSON.stringify(product)) @@ -474,13 +474,13 @@ let propertySeparator = "" for (let j = 0; j < recordDefinition.properties.length; j++) { let property = recordDefinition.properties[j] - if (property.code.isCalculated !== true) { + if (property.config.isCalculated !== true) { fileContent = fileContent + propertySeparator - if (property.code.isString === true) { + if (property.config.isString === true) { fileContent = fileContent + '"' } - fileContent = fileContent + record[property.code.codeName] - if (property.code.isString === true) { + fileContent = fileContent + record[property.config.codeName] + if (property.config.isString === true) { fileContent = fileContent + '"' } if (propertySeparator === "") { propertySeparator = ","; } diff --git a/DataSet.js b/DataSet.js index aa0c6bb1c..1a6364b7a 100644 --- a/DataSet.js +++ b/DataSet.js @@ -16,7 +16,7 @@ exports.newDataSet = function newDataSet(BOT, logger) { /* Storage account to be used here. */ const FILE_STORAGE = require('./FileStorage.js'); - let fileStorage + let fileStorage return thisObject; @@ -36,7 +36,7 @@ exports.newDataSet = function newDataSet(BOT, logger) { return } - if (thisObject.node.code.codeName === undefined) { + if (thisObject.node.config.codeName === undefined) { logger.write(MODULE_NAME, "[ERROR] initialize -> Dataset witn no codeName defined -> Product Dataset = " + JSON.stringify(thisObject.node)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return @@ -48,7 +48,7 @@ exports.newDataSet = function newDataSet(BOT, logger) { return } - if (thisObject.node.parentNode.code.codeName === undefined) { + if (thisObject.node.parentNode.config.codeName === undefined) { logger.write(MODULE_NAME, "[ERROR] initialize -> Product Definition witn no codeName defined -> Product Definition = " + JSON.stringify(thisObject.node.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return @@ -60,7 +60,7 @@ exports.newDataSet = function newDataSet(BOT, logger) { return } - if (thisObject.node.parentNode.parentNode.code.codeName === undefined) { + if (thisObject.node.parentNode.parentNode.config.codeName === undefined) { logger.write(MODULE_NAME, "[ERROR] initialize -> Bot witn no codeName defined. Bot = " + JSON.stringify(thisObject.node.parentNode.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return @@ -72,14 +72,14 @@ exports.newDataSet = function newDataSet(BOT, logger) { return } - if (thisObject.node.parentNode.parentNode.parentNode.code.codeName === undefined) { + if (thisObject.node.parentNode.parentNode.parentNode.config.codeName === undefined) { logger.write(MODULE_NAME, "[ERROR] initialize -> Data Mine witn no codeName defined. Data Mine = " + JSON.stringify(thisObject.node.parentNode.parentNode.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return } /* Now we will see where do we need to fetch this data from. */ - let network = global.TASK_NETWORK + let network = global.TASK_NETWORK let datasetProductDefinition = thisObject.node.parentNode for (let i = 0; i < network.networkNodes.length; i++) { @@ -102,9 +102,9 @@ exports.newDataSet = function newDataSet(BOT, logger) { if (datasetProductDefinition.id === productDefinition.id) { /* We found where the data is located on the network. */ - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Retrieving data from " + networkNode.name + " -> host = " + networkNode.code.host + ' -> port = ' + networkNode.code.webPort + '.'); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Retrieving data from " + networkNode.name + " -> host = " + networkNode.config.host + ' -> port = ' + networkNode.config.webPort + '.'); } - fileStorage = FILE_STORAGE.newFileStorage(logger, networkNode.code.host, networkNode.code.webPort); + fileStorage = FILE_STORAGE.newFileStorage(logger, networkNode.config.host, networkNode.config.webPort); callBackFunction(global.DEFAULT_OK_RESPONSE); return } @@ -133,9 +133,9 @@ exports.newDataSet = function newDataSet(BOT, logger) { if (datasetProductDefinition.id === productDefinition.id) { /* We found where the data is located on the network. */ - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Retrieving data from " + networkNode.name + " -> host = " + networkNode.code.host + ' -> port = ' + networkNode.code.webPort + '.'); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Retrieving data from " + networkNode.name + " -> host = " + networkNode.config.host + ' -> port = ' + networkNode.config.webPort + '.'); } - fileStorage = FILE_STORAGE.newFileStorage(logger, networkNode.code.host, networkNode.code.webPort); + fileStorage = FILE_STORAGE.newFileStorage(logger, networkNode.config.host, networkNode.config.webPort); callBackFunction(global.DEFAULT_OK_RESPONSE); return } @@ -155,7 +155,7 @@ exports.newDataSet = function newDataSet(BOT, logger) { callBackFunction(global.DEFAULT_FAIL_RESPONSE); } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -173,8 +173,8 @@ exports.newDataSet = function newDataSet(BOT, logger) { if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getTextFile -> Entering function."); } - let dataMineCodeName = thisObject.node.parentNode.parentNode.parentNode.code.codeName - let botCodeName = thisObject.node.parentNode.parentNode.code.codeName + let dataMineCodeName = thisObject.node.parentNode.parentNode.parentNode.config.codeName + let botCodeName = thisObject.node.parentNode.parentNode.config.codeName let filePathRoot = bot.exchange + "/" + bot.market.baseAsset + "-" + bot.market.quotedAsset + "/" + dataMineCodeName + "/" + botCodeName; let filePath = filePathRoot + "/Output/" + pFolderPath; @@ -191,7 +191,7 @@ exports.newDataSet = function newDataSet(BOT, logger) { } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] 'getTextFile' -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] 'getTextFile' -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -232,7 +232,7 @@ exports.newDataSet = function newDataSet(BOT, logger) { } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] 'createTextFile' -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] 'createTextFile' -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } diff --git a/IndicatorBot.js b/IndicatorBot.js index 004ed077f..fc28afeae 100644 --- a/IndicatorBot.js +++ b/IndicatorBot.js @@ -65,7 +65,7 @@ if (commons.validateDataDependencies(dataDependencies, callBackFunction) !== true) { return } let outputDatasets = bot.processNode.referenceParent.processOutput.outputDatasets - if (commons.validateOutputDatasets(outputDatasets, callBackFunction) !== true) { return } + if (commons.validateOutputDatasets(outputDatasets, callBackFunction) !== true) { return } /* The second phase is about transforming the inputs into a format that can be used to apply the user defined code. */ commons.inflateDatafiles(dataFiles, dataDependencies, products, mainDependency, timeFrame) @@ -86,7 +86,7 @@ */ recordDefinition = outputDatasetNode.referenceParent.parentNode.record - singularVariableName = outputDatasetNode.referenceParent.parentNode.code.singularVariableName + singularVariableName = outputDatasetNode.referenceParent.parentNode.config.singularVariableName /* Check Irregular Periods */ @@ -103,7 +103,7 @@ recordDefinition, outputDatasetNode.referenceParent.parentNode.dataBuilding, singularVariableName, - outputDatasetNode.referenceParent.parentNode.code.codeName, + outputDatasetNode.referenceParent.parentNode.config.codeName, timeFrame, timeFrameLabel, resultsWithIrregularPeriods, @@ -118,14 +118,14 @@ } else { outputData = jsonData } - products[outputDatasetNode.referenceParent.parentNode.code.pluralVariableName] = outputData + products[outputDatasetNode.referenceParent.parentNode.config.pluralVariableName] = outputData } /*At the fourth and last phase, we will save the new information generated into files corresponding to each output outputDatasetNode.*/ let totalFilesWritten = 0 for (let i = 0; i < outputDatasets.length; i++) { let outputDatasetNode = outputDatasets[i] - let outputData = products[outputDatasetNode.referenceParent.parentNode.code.pluralVariableName] + let outputData = products[outputDatasetNode.referenceParent.parentNode.config.pluralVariableName] let resultsWithIrregularPeriods // A product will have irregular periods when the User Code inserts new result records at will, in contrast with normal procedure where the platform insert one record per loop execution. let contextSummary = {} @@ -136,10 +136,10 @@ /* Simplifying the access to basic info */ - contextSummary.dataset = outputDatasetNode.referenceParent.code.codeName - contextSummary.product = outputDatasetNode.referenceParent.parentNode.code.codeName - contextSummary.bot = outputDatasetNode.referenceParent.parentNode.parentNode.code.codeName - contextSummary.dataMine = outputDatasetNode.referenceParent.parentNode.parentNode.parentNode.code.codeName + contextSummary.dataset = outputDatasetNode.referenceParent.config.codeName + contextSummary.product = outputDatasetNode.referenceParent.parentNode.config.codeName + contextSummary.bot = outputDatasetNode.referenceParent.parentNode.parentNode.config.codeName + contextSummary.dataMine = outputDatasetNode.referenceParent.parentNode.parentNode.parentNode.config.codeName /* This stuff is still hardcoded and unresolved. */ contextSummary.botVersion = { diff --git a/MultiPeriod.js b/MultiPeriod.js index f29d1c0fa..bf46a4b85 100644 --- a/MultiPeriod.js +++ b/MultiPeriod.js @@ -231,18 +231,18 @@ try { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processSingleFiles -> dependencyLoopBody -> getFile -> Entering function."); } - if (datasetModule.node.code.codeName !== "Single-File") { + if (datasetModule.node.config.codeName !== "Single-File") { dependencyControlLoop(); return } - if (dataDependenciesModule.isItADepenency('atAnyTimeFrame', datasetModule.node.parentNode.code.singularVariableName) !== true) { + if (dataDependenciesModule.isItADepenency('atAnyTimeFrame', datasetModule.node.parentNode.config.singularVariableName) !== true) { dependencyControlLoop(); return } let fileName = "Data.json"; - let filePath = datasetModule.node.parentNode.code.codeName + '/' + datasetModule.node.code.codeName; + let filePath = datasetModule.node.parentNode.config.codeName + '/' + datasetModule.node.config.codeName; datasetModule.getTextFile(filePath, fileName, onFileReceived); function onFileReceived(err, text) { @@ -365,20 +365,20 @@ try { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processMarketFiles -> timeFramesLoopBody -> dependencyLoopBody -> getFile -> Entering function."); } - if (dependency.referenceParent.code.codeName !== "Multi-Period-Market") { + if (dependency.referenceParent.config.codeName !== "Multi-Period-Market") { dependencyControlLoop(); return } - if (dataDependenciesModule.isItADepenency(timeFrameLabel, datasetModule.node.parentNode.code.singularVariableName) !== true) { - if (!(bot.VALUES_TO_USE.timeFrame === timeFrameLabel && datasetModule.node.parentNode.code.pluralVariableName === 'candles')) { + if (dataDependenciesModule.isItADepenency(timeFrameLabel, datasetModule.node.parentNode.config.singularVariableName) !== true) { + if (!(bot.VALUES_TO_USE.timeFrame === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) { dependencyControlLoop(); return } } let fileName = "Data.json"; - let filePath = dependency.referenceParent.parentNode.code.codeName + '/' + dependency.referenceParent.code.codeName + "/" + timeFrameLabel; + let filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel; datasetModule.getTextFile(filePath, fileName, onFileReceived); function onFileReceived(err, text) { @@ -624,13 +624,13 @@ try { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> timeFramesLoopBody -> dependencyLoopBody -> getPreviousFile -> Entering function."); } - if (dependency.referenceParent.code.codeName !== "Multi-Period-Daily") { + if (dependency.referenceParent.config.codeName !== "Multi-Period-Daily") { dependencyControlLoop(); return } - if (dataDependenciesModule.isItADepenency(timeFrameLabel, datasetModule.node.parentNode.code.singularVariableName) !== true) { - if (!(bot.VALUES_TO_USE.timeFrame === timeFrameLabel && datasetModule.node.parentNode.code.pluralVariableName === 'candles')) { + if (dataDependenciesModule.isItADepenency(timeFrameLabel, datasetModule.node.parentNode.config.singularVariableName) !== true) { + if (!(bot.VALUES_TO_USE.timeFrame === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) { dependencyControlLoop(); return } @@ -639,10 +639,10 @@ let dateForPath = previousDay.getUTCFullYear() + '/' + utilities.pad(previousDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(previousDay.getUTCDate(), 2); let filePath - if (dependency.referenceParent.code.codeName === "Multi-Period-Daily") { - filePath = dependency.referenceParent.parentNode.code.codeName + '/' + dependency.referenceParent.code.codeName + "/" + timeFrameLabel + "/" + dateForPath; + if (dependency.referenceParent.config.codeName === "Multi-Period-Daily") { + filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel + "/" + dateForPath; } else { - filePath = dependency.referenceParent.parentNode.code.codeName + '/' + dependency.referenceParent.code.codeName + "/" + dateForPath; + filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + dateForPath; } let fileName = "Data.json"; @@ -702,13 +702,13 @@ try { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processDailyFiles -> timeFramesLoopBody -> dependencyLoopBody -> getCurrentFile -> Entering function."); } - if (dependency.referenceParent.code.codeName !== "Multi-Period-Daily") { + if (dependency.referenceParent.config.codeName !== "Multi-Period-Daily") { dependencyControlLoop(); return } - if (dataDependenciesModule.isItADepenency(timeFrameLabel, datasetModule.node.parentNode.code.singularVariableName) !== true) { - if (!(bot.VALUES_TO_USE.timeFrame === timeFrameLabel && datasetModule.node.parentNode.code.pluralVariableName === 'candles')) { + if (dataDependenciesModule.isItADepenency(timeFrameLabel, datasetModule.node.parentNode.config.singularVariableName) !== true) { + if (!(bot.VALUES_TO_USE.timeFrame === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) { dependencyControlLoop(); return } @@ -716,10 +716,10 @@ let dateForPath = bot.multiPeriodProcessDatetime.getUTCFullYear() + '/' + utilities.pad(bot.multiPeriodProcessDatetime.getUTCMonth() + 1, 2) + '/' + utilities.pad(bot.multiPeriodProcessDatetime.getUTCDate(), 2); let filePath - if (dependency.referenceParent.code.codeName === "Multi-Period-Daily") { - filePath = dependency.referenceParent.parentNode.code.codeName + '/' + dependency.referenceParent.code.codeName + "/" + timeFrameLabel + "/" + dateForPath; + if (dependency.referenceParent.config.codeName === "Multi-Period-Daily") { + filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel + "/" + dateForPath; } else { - filePath = dependency.referenceParent.parentNode.code.codeName + '/' + dependency.referenceParent.code.codeName + "/" + dateForPath; + filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + dateForPath; } let fileName = "Data.json"; @@ -927,7 +927,7 @@ controlLoop(); function productLoopBody() { - let productCodeName = bot.processNode.referenceParent.processOutput.outputDatasets[outputDatasetIndex].referenceParent.parentNode.code.codeName; + let productCodeName = bot.processNode.referenceParent.processOutput.outputDatasets[outputDatasetIndex].referenceParent.parentNode.config.codeName; writeDataRange(contextVariables.dateBeginOfMarket, bot.multiPeriodProcessDatetime, productCodeName, currentTimeFrameLabel, controlLoop); } diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js index 4e384081d..096df4c62 100644 --- a/MultiPeriodDaily.js +++ b/MultiPeriodDaily.js @@ -22,7 +22,7 @@ let fileStorage = FILE_STORAGE.newFileStorage(logger); - let bootstrappingTheProcess = false + let bootstrappingTheProcess = false let processConfig; let beginingOfMarket @@ -48,7 +48,7 @@ botInstance.initialize(callBackFunction); } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -248,7 +248,7 @@ } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> err = " + err.stack); if (err.message === "Cannot read property 'file' of undefined") { logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. "); logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys)); @@ -280,7 +280,7 @@ bot.multiPeriodDailyProcessDatetime = new Date(bot.multiPeriodDailyProcessDatetime.valueOf() + ONE_DAY_IN_MILISECONDS); previousDay = new Date(bot.multiPeriodDailyProcessDatetime.valueOf() - ONE_DAY_IN_MILISECONDS); - + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimeFrames -> advanceTime -> bot.multiPeriodDailyProcessDatetime = " + bot.multiPeriodDailyProcessDatetime); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimeFrames -> advanceTime -> previousDay = " + previousDay); } @@ -300,7 +300,7 @@ let currentDateString = bot.multiPeriodDailyProcessDatetime.getUTCFullYear() + '-' + utilities.pad(bot.multiPeriodDailyProcessDatetime.getUTCMonth() + 1, 2) + '-' + utilities.pad(bot.multiPeriodDailyProcessDatetime.getUTCDate(), 2); let currentDate = new Date(bot.multiPeriodDailyProcessDatetime) let percentage = global.getPercentage(fromDate, currentDate, lastDate) - bot.processHeartBeat(currentDateString, percentage) + bot.processHeartBeat(currentDateString, percentage) if (global.areEqualDates(currentDate, new Date()) === false) { logger.newInternalLoop(bot.codeName, bot.process, currentDate, percentage); @@ -309,7 +309,7 @@ checkStopTaskGracefully(); } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> advanceTime -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> advanceTime -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -355,7 +355,7 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoop -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoop -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -395,9 +395,9 @@ let dependency = dataDependenciesModule.nodeArray[dependencyIndex]; - if (dependency === undefined ) { + if (dependency === undefined) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> You need to add at least one Data Dependency to the process Multi Period Daily. Aborting process." ); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> You need to add at least one Data Dependency to the process Multi Period Daily. Aborting process."); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return; } @@ -422,10 +422,10 @@ let dateForPath = previousDay.getUTCFullYear() + '/' + utilities.pad(previousDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(previousDay.getUTCDate(), 2); let filePath - if (dependency.referenceParent.code.codeName === "Multi-Period-Daily") { - filePath = dependency.referenceParent.parentNode.code.codeName + '/' + dependency.referenceParent.code.codeName + "/" + timeFrameLabel + "/" + dateForPath; + if (dependency.referenceParent.config.codeName === "Multi-Period-Daily") { + filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel + "/" + dateForPath; } else { - filePath = dependency.referenceParent.parentNode.code.codeName + '/' + dependency.referenceParent.code.codeName + "/" + dateForPath; + filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + dateForPath; } let fileName = "Data.json"; @@ -455,14 +455,14 @@ if ((err.result === "Fail Because" && err.message === "File does not exist.") || err.code === 'The specified key does not exist.') { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> err = " + err.stack); callBackFunction(global.DEFAULT_RETRY_RESPONSE); return; } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> err = " + err.stack); callBackFunction(err); return; } @@ -473,13 +473,13 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -492,12 +492,12 @@ let dateForPath = bot.multiPeriodDailyProcessDatetime.getUTCFullYear() + '/' + utilities.pad(bot.multiPeriodDailyProcessDatetime.getUTCMonth() + 1, 2) + '/' + utilities.pad(bot.multiPeriodDailyProcessDatetime.getUTCDate(), 2); let filePath - if (dependency.referenceParent.code.codeName === "Multi-Period-Daily") { - filePath = dependency.referenceParent.parentNode.code.codeName + '/' + dependency.referenceParent.code.codeName + "/" + timeFrameLabel + "/" + dateForPath; + if (dependency.referenceParent.config.codeName === "Multi-Period-Daily") { + filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel + "/" + dateForPath; } else { - filePath = dependency.referenceParent.parentNode.code.codeName + '/' + dependency.referenceParent.code.codeName + "/" + dateForPath; + filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + dateForPath; } - let fileName = "Data.json"; + let fileName = "Data.json"; datasetModule.getTextFile(filePath, fileName, onFileReceived); @@ -543,19 +543,19 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> Catch Error -> onFileReceived -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> Catch Error -> onFileReceived -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoop -> dependencyLoopBody -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoop -> dependencyLoopBody -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -579,7 +579,7 @@ } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> dependencyControlLoop -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> dependencyControlLoop -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -617,19 +617,19 @@ periodsControlLoop(); } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> callTheBot -> onBotFinished -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> callTheBot -> onBotFinished -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> callTheBot -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> callTheBot -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -659,7 +659,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimeFrames -> controlLoop -> onWritten -> Entering function."); } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> controlLoop -> onWritten -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> controlLoop -> onWritten -> err = " + err.stack); callBackFunction(err); return; } @@ -667,21 +667,21 @@ writeStatusReport(bot.multiPeriodDailyProcessDatetime, advanceTime); } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> controlLoop -> onWritten -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> controlLoop -> onWritten -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsControlLoop -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsControlLoop -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -696,7 +696,7 @@ controlLoop(); function productLoopBody() { - let productCodeName = bot.processNode.referenceParent.processOutput.outputDatasets[outputDatasetIndex].referenceParent.parentNode.code.codeName; + let productCodeName = bot.processNode.referenceParent.processOutput.outputDatasets[outputDatasetIndex].referenceParent.parentNode.config.codeName; writeDataRange(contextVariables.dateBeginOfMarket, bot.multiPeriodDailyProcessDatetime, productCodeName, controlLoop); } @@ -712,7 +712,7 @@ } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeDataRanges -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeDataRanges -> err = " + err.stack); callBack(global.DEFAULT_FAIL_RESPONSE); } @@ -741,7 +741,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Entering function."); } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> onFileCreated -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> onFileCreated -> err = " + err.stack); callBack(err); return; } @@ -750,7 +750,7 @@ logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Content written = " + fileContent); } - let key = bot.dataMine + "-" + bot.codeName + "-" + productCodeName + "-" + bot.exchange + "-" + bot.market.baseAsset + '/' + bot.market.quotedAsset + let key = bot.dataMine + "-" + bot.codeName + "-" + productCodeName + "-" + bot.exchange + "-" + bot.market.baseAsset + '/' + bot.market.quotedAsset let event = { dateRange: dataRange } @@ -761,7 +761,7 @@ } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> err = " + err.stack); callBack(global.DEFAULT_FAIL_RESPONSE); } } @@ -786,14 +786,14 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } diff --git a/MultiPeriodMarket.js b/MultiPeriodMarket.js index 3c8b10f07..11bc7ae40 100644 --- a/MultiPeriodMarket.js +++ b/MultiPeriodMarket.js @@ -41,7 +41,7 @@ botInstance.initialize(callBackFunction); } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -100,7 +100,7 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoop -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoop -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -137,13 +137,13 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getFile -> Entering function."); } let dateForPath = bot.processDatetime.getUTCFullYear() + '/' + utilities.pad(bot.processDatetime.getUTCMonth() + 1, 2) + '/' + utilities.pad(bot.processDatetime.getUTCDate(), 2); - let fileName = "Data.json"; + let fileName = "Data.json"; let filePath - if (dependency.referenceParent.code.codeName === "Multi-Period-Market") { - filePath = dependency.referenceParent.parentNode.code.codeName + '/' + dependency.referenceParent.code.codeName + "/" + timeFrameLabel; + if (dependency.referenceParent.config.codeName === "Multi-Period-Market") { + filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel; } else { - filePath = dependency.referenceParent.parentNode.code.codeName + '/' + dependency.referenceParent.code.codeName + "/" + dateForPath; + filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + dateForPath; } datasetModule.getTextFile(filePath, fileName, onFileReceived); @@ -156,7 +156,7 @@ if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = " + err.stack); callBackFunction(err); return; } @@ -168,20 +168,20 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getFile -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> dependencyLoopBody -> getFile -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoop -> dependencyLoopBody -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoop -> dependencyLoopBody -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -205,7 +205,7 @@ } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> dependencyControlLoop -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> dependencyControlLoop -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -242,19 +242,19 @@ periodsControlLoop(); } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> callTheBot -> onBotFinished -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> callTheBot -> onBotFinished -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } - catch(err){ - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> callTheBot -> err = "+ err.stack); + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> callTheBot -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsLoopBody -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -278,14 +278,14 @@ } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsControlLoop -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> periodsControlLoop -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFrames -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -304,23 +304,23 @@ if (global.areEqualDates(bot.processDatetime, new Date()) === false) { logger.newInternalLoop(bot.codeName, bot.process, bot.processDatetime); - } - + } + /* Telling the world we are alive and doing well */ let currentDateString = bot.processDatetime.getUTCFullYear() + '-' + utilities.pad(bot.processDatetime.getUTCMonth() + 1, 2) + '-' + utilities.pad(bot.processDatetime.getUTCDate(), 2); let currentDate = new Date(bot.processDatetime) let lastDate = new Date() - bot.processHeartBeat(currentDateString, global.getPercentage(currentDate, currentDate, lastDate)) + bot.processHeartBeat(currentDateString, global.getPercentage(currentDate, currentDate, lastDate)) } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> err = "+ err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } diff --git a/ProcessExecutionEvents.js b/ProcessExecutionEvents.js index 8731bf55a..b304be111 100644 --- a/ProcessExecutionEvents.js +++ b/ProcessExecutionEvents.js @@ -8,7 +8,7 @@ */ const MODULE_NAME = "Process Execution Events"; - logger.fileName = MODULE_NAME + logger.fileName = MODULE_NAME let bot = BOT; @@ -43,7 +43,7 @@ return } - let market = bot.market.baseAsset + '/' + bot.market.quotedAsset + let market = bot.market.baseAsset + '/' + bot.market.quotedAsset currentProcessKey = bot.processNode.referenceParent.name + "-" + bot.processNode.referenceParent.type + "-" + bot.processNode.referenceParent.id + "-" + bot.exchange + "-" + market if (bot.processNode.referenceParent.executionStartedEvent !== undefined) { @@ -52,7 +52,7 @@ processThisDependsOn = bot.processNode.referenceParent.executionStartedEvent.referenceParent.parentNode name = processThisDependsOn.name - if (processThisDependsOn.code.monthlyInstances === true) { + if (processThisDependsOn.config.monthlyInstances === true) { logger.fileName = MODULE_NAME + "." + name; } if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> " + currentProcessKey + " depends on " + name); } @@ -90,13 +90,13 @@ /* We found where the task that runs the process definition we are waiting for is located on the network. */ thisObject.networkNode = networkNode - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Connecting to Websockets Server " + networkNode.name + " -> host = " + networkNode.code.host + ' -> port = ' + networkNode.code.webSocketsPort + '.'); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Connecting to Websockets Server " + networkNode.name + " -> host = " + networkNode.config.host + ' -> port = ' + networkNode.config.webSocketsPort + '.'); } - eventServerClient = EVENT_SERVER_CLIENT.newEventsServerClient(networkNode.code.host, networkNode.code.webSocketsPort) + eventServerClient = EVENT_SERVER_CLIENT.newEventsServerClient(networkNode.config.host, networkNode.config.webSocketsPort) eventServerClient.initialize(onConnected) function onConnected() { - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Connected to Websockets Server " + networkNode.name + " -> host = " + networkNode.code.host + ' -> port = ' + networkNode.code.webSocketsPort + '.'); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Connected to Websockets Server " + networkNode.name + " -> host = " + networkNode.config.host + ' -> port = ' + networkNode.config.webSocketsPort + '.'); } callBackFunction(global.DEFAULT_OK_RESPONSE); return @@ -119,7 +119,7 @@ return } callBackFunction(global.DEFAULT_OK_RESPONSE); - + } catch (err) { logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); @@ -151,7 +151,7 @@ let extraCallerId = '-' + Math.trunc(Math.random() * 10000) + '-' - let market = bot.market.baseAsset + '/' + bot.market.quotedAsset + let market = bot.market.baseAsset + '/' + bot.market.quotedAsset let key = processThisDependsOn.name + "-" + processThisDependsOn.type + "-" + processThisDependsOn.id + "-" + bot.exchange + "-" + market let callerId = bot.dataMine + "-" + bot.codeName + "-" + bot.process + extraCallerId @@ -163,7 +163,7 @@ eventServerClient.listenToEvent(key, 'Process Execution Finished', undefined, callerId, responseCallBack, eventsCallBack) - bot.processHeartBeat(undefined, undefined, "Waiting for " + thisObject.networkNode.name + "->" + processThisDependsOn.parentNode.parentNode.name + "->" + processThisDependsOn.parentNode.code.codeName + "->" + processThisDependsOn.code.codeName) + bot.processHeartBeat(undefined, undefined, "Waiting for " + thisObject.networkNode.name + "->" + processThisDependsOn.parentNode.parentNode.name + "->" + processThisDependsOn.parentNode.config.codeName + "->" + processThisDependsOn.config.codeName) function responseCallBack(message) { if (message.result !== global.DEFAULT_OK_RESPONSE.result) { @@ -192,9 +192,9 @@ global.EVENT_SERVER_CLIENT.createEventHandler(currentProcessKey, 'Process Execution Started') global.EVENT_SERVER_CLIENT.raiseEvent(currentProcessKey, 'Process Execution Started', event) - bot.processHeartBeat(undefined, undefined,"Running...") + bot.processHeartBeat(undefined, undefined, "Running...") - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] start -> eventsCallBack -> " + currentProcessKey + " Process Execution Started because " + key + " Finished."); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] start -> eventsCallBack -> " + currentProcessKey + " Process Execution Started because " + key + " Finished."); } } callBackFunction(message.event.err); @@ -208,7 +208,7 @@ global.EVENT_SERVER_CLIENT.createEventHandler(currentProcessKey, 'Process Execution Started') global.EVENT_SERVER_CLIENT.raiseEvent(currentProcessKey, 'Process Execution Started', event) - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] start -> " + currentProcessKey + " Process Execution Started " ); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] start -> " + currentProcessKey + " Process Execution Started "); } callBackFunction(global.DEFAULT_OK_RESPONSE); } @@ -232,7 +232,7 @@ global.EVENT_SERVER_CLIENT.createEventHandler(currentProcessKey, 'Process Execution Finished') global.EVENT_SERVER_CLIENT.raiseEvent(currentProcessKey, 'Process Execution Finished', event) - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] finish -> " + currentProcessKey + " Process Execution Finished " ); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] finish -> " + currentProcessKey + " Process Execution Finished "); } callBackFunction(global.DEFAULT_OK_RESPONSE); diff --git a/ProcessOutput.js b/ProcessOutput.js index 7bbdfff10..2130a7cf6 100644 --- a/ProcessOutput.js +++ b/ProcessOutput.js @@ -30,29 +30,29 @@ /* Some validations to verify that everything is in place. */ if (outputDataset.referenceParent !== undefined) { - if (outputDataset.referenceParent.code.codeName === undefined) { + if (outputDataset.referenceParent.config.codeName === undefined) { logger.write(MODULE_NAME, "[ERROR] raiseEvents -> codeName at Dataset Definition not defined. Dataset Definition = " + JSON.stringify(outputDataset.referenceParent)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return - } + } if (outputDataset.referenceParent.parentNode !== undefined) { - if (outputDataset.referenceParent.parentNode.code.codeName === undefined) { + if (outputDataset.referenceParent.parentNode.config.codeName === undefined) { logger.write(MODULE_NAME, "[ERROR] raiseEvents -> codeName at Product not defined. Product = " + JSON.stringify(outputDataset.referenceParent.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return - } + } if (outputDataset.referenceParent.parentNode.parentNode !== undefined) { - if (outputDataset.referenceParent.parentNode.parentNode.code.codeName === undefined) { + if (outputDataset.referenceParent.parentNode.parentNode.config.codeName === undefined) { logger.write(MODULE_NAME, "[ERROR] raiseEvents -> codeName at Bot not defined. Bot = " + JSON.stringify(outputDataset.referenceParent.parentNode.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return - } + } if (outputDataset.referenceParent.parentNode.parentNode.parentNode !== undefined) { - if (outputDataset.referenceParent.parentNode.parentNode.parentNode.code.codeName === undefined) { + if (outputDataset.referenceParent.parentNode.parentNode.parentNode.config.codeName === undefined) { logger.write(MODULE_NAME, "[ERROR] raiseEvents -> codeName at Data Mine not defined. Data Mine = " + JSON.stringify(outputDataset.referenceParent.parentNode.parentNode.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return - } + } } else { logger.write(MODULE_NAME, "[ERROR] raiseEvents -> Bot not attached to a Data Mine. Bot = " + JSON.stringify(outputDataset.referenceParent.parentNode.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); @@ -76,10 +76,10 @@ /* All good, lets emit the event. */ - let dataMine = outputDataset.referenceParent.parentNode.parentNode.parentNode.code.codeName - let botName = outputDataset.referenceParent.parentNode.parentNode.code.codeName - let product = outputDataset.referenceParent.parentNode.code.codeName - let dataset = outputDataset.referenceParent.code.codeName + let dataMine = outputDataset.referenceParent.parentNode.parentNode.parentNode.config.codeName + let botName = outputDataset.referenceParent.parentNode.parentNode.config.codeName + let product = outputDataset.referenceParent.parentNode.config.codeName + let dataset = outputDataset.referenceParent.config.codeName key = dataMine + "-" + botName + "-" + product + "-" + dataset + "-" + bot.exchange + "-" + bot.market.baseAsset + '/' + bot.market.quotedAsset let event = { diff --git a/Root.js b/Root.js index 3a0dec4cd..f4f3910f3 100644 --- a/Root.js +++ b/Root.js @@ -112,7 +112,7 @@ } catch (err) { - console.log(logDisplace + "Root : [ERROR] initialize -> err = " + err.stack); + console.log(logDisplace + "Root : [ERROR] initialize -> err = " + err.stack); return; } } @@ -141,19 +141,19 @@ /* Here we will check if we need to load the configuration and code of the bot from a file or we will take that from the UI. */ if ( - processInstance.referenceParent.code.framework !== undefined && - ( processInstance.referenceParent.code.framework.name === 'Multi-Period-Market' || - processInstance.referenceParent.code.framework.name === 'Multi-Period-Daily' || - processInstance.referenceParent.code.framework.name === 'Multi-Period') - ) { - botConfig = processInstance.referenceParent.parentNode.code + processInstance.referenceParent.config.framework !== undefined && + (processInstance.referenceParent.config.framework.name === 'Multi-Period-Market' || + processInstance.referenceParent.config.framework.name === 'Multi-Period-Daily' || + processInstance.referenceParent.config.framework.name === 'Multi-Period') + ) { + botConfig = processInstance.referenceParent.parentNode.config botConfig.definedByUI = true bootingBot(processIndex) return } else { getBotConfigFromFile(); return - } + } function getBotConfigFromFile() { @@ -162,7 +162,7 @@ const FILE_STORAGE = require('./FileStorage.js'); let fileStorage = FILE_STORAGE.newFileStorage(); - let filePath = global.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.code.codeName + '/bots/' + global.TASK_NODE.bot.code.repo + '/this.bot.config.json'; + let filePath = global.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + '/bots/' + global.TASK_NODE.bot.config.repo + '/this.bot.config.json'; fileStorage.getTextFile(filePath, onFileReceived); @@ -171,13 +171,13 @@ if (err.result !== global.DEFAULT_OK_RESPONSE.result) { console.log(logDisplace + "Root : [ERROR] start -> getBotConfigFromFile -> onInizialized -> onFileReceived -> err = " + JSON.stringify(err)); console.log(logDisplace + "Root : [ERROR] start -> getBotConfigFromFile -> onInizialized -> onFileReceived -> filePath = " + filePath); - console.log(logDisplace + "Root : [ERROR] start -> getBotConfigFromFile -> onInizialized -> onFileReceived -> dataMine = " + global.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.code.codeName); + console.log(logDisplace + "Root : [ERROR] start -> getBotConfigFromFile -> onInizialized -> onFileReceived -> dataMine = " + global.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName); return; } try { botConfig = JSON.parse(text); - botConfig.repo = global.TASK_NODE.bot.code.repo; + botConfig.repo = global.TASK_NODE.bot.config.repo; bootingBot(processIndex); } catch (err) { console.log(logDisplace + "Root : [ERROR] start -> getBotConfigFromFile -> onInizialized -> onFileReceived -> err = " + JSON.stringify(err)); @@ -195,7 +195,7 @@ try { - botConfig.process = global.TASK_NODE.bot.processes[processIndex].referenceParent.code.codeName + botConfig.process = global.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName botConfig.debug = {}; botConfig.processNode = global.TASK_NODE.bot.processes[processIndex] @@ -204,15 +204,15 @@ botConfig.DELETE_QUEUE_SIZE = 10 // This number represents how many log files can be at the queue at any point in time, which means how many logs are not still deleted. /* Simplifying the access to basic info */ - botConfig.dataMine = global.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.code.codeName + botConfig.dataMine = global.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName botConfig.exchange = global.TASK_NODE.bot.processes[processIndex].marketReference.referenceParent.parentNode.parentNode.name botConfig.exchangeNode = global.TASK_NODE.bot.processes[processIndex].marketReference.referenceParent.parentNode.parentNode botConfig.market = { - baseAsset: global.TASK_NODE.bot.processes[processIndex].marketReference.referenceParent.baseAsset.referenceParent.code.codeName, - quotedAsset: global.TASK_NODE.bot.processes[processIndex].marketReference.referenceParent.quotedAsset.referenceParent.code.codeName + baseAsset: global.TASK_NODE.bot.processes[processIndex].marketReference.referenceParent.baseAsset.referenceParent.config.codeName, + quotedAsset: global.TASK_NODE.bot.processes[processIndex].marketReference.referenceParent.quotedAsset.referenceParent.config.codeName } - botConfig.uiStartDate = global.TASK_NODE.bot.code.startDate - botConfig.code = global.TASK_NODE.bot.code + botConfig.uiStartDate = global.TASK_NODE.bot.config.startDate + botConfig.config = global.TASK_NODE.bot.config /* This stuff is still hardcoded and unresolved. */ botConfig.version = { @@ -222,10 +222,10 @@ botConfig.dataSetVersion = "dataSet.V1" /* Loop Counter */ - botConfig.loopCounter = 0; + botConfig.loopCounter = 0; /* File Path Root */ - botConfig.filePathRoot = botConfig.exchange + "/" + botConfig.market.baseAsset + "-" + botConfig.market.quotedAsset + "/" + botConfig.dataMine + "/" + botConfig.codeName ; + botConfig.filePathRoot = botConfig.exchange + "/" + botConfig.market.baseAsset + "-" + botConfig.market.quotedAsset + "/" + botConfig.dataMine + "/" + botConfig.codeName; /* Process Key */ botConfig.processKey = global.TASK_NODE.bot.processes[processIndex].name + '-' + global.TASK_NODE.bot.processes[processIndex].type + '-' + global.TASK_NODE.bot.processes[processIndex].id @@ -243,14 +243,14 @@ if (botConfig.processNode.marketReference.keyInstance.referenceParent !== undefined) { let key = botConfig.processNode.marketReference.keyInstance.referenceParent - process.env.KEY = key.code.codeName - process.env.SECRET = key.code.secret + process.env.KEY = key.config.codeName + process.env.SECRET = key.config.secret } } } } - let processConfig = global.TASK_NODE.bot.processes[processIndex].referenceParent.code + let processConfig = global.TASK_NODE.bot.processes[processIndex].referenceParent.config if (processConfig.framework !== undefined) { if (processConfig.framework.name === "Multi-Period-Daily" || processConfig.framework.name === "Multi-Period-Market" || processConfig.framework.name === "Multi-Period") { @@ -283,7 +283,7 @@ if (processConfig.startMode === undefined) { // Default botConfig.hasTheBotJustStarted = true; - + switch (botConfig.type) { case 'Sensor Bot': { runSensorBot(botConfig, processConfig); @@ -475,7 +475,7 @@ pBotConfig.loopCounter = 0; let botId = pBotConfig.dataMine + "." + pBotConfig.codeName + "." + pBotConfig.process; - + if (err.result === global.DEFAULT_OK_RESPONSE.result) { logger.write(MODULE_NAME, "[INFO] start -> bootingBot -> runIndicatorBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully."); diff --git a/Session.js b/Session.js index 8e0c985bd..f8fdc0f1e 100644 --- a/Session.js +++ b/Session.js @@ -24,10 +24,10 @@ } /* Set the folderName for early logging */ - if (bot.processNode.session.code.folderName === undefined) { + if (bot.processNode.session.config.folderName === undefined) { bot.SESSION.folderName = bot.SESSION.id } else { - bot.SESSION.folderName = bot.processNode.session.code.folderName + "-" + bot.SESSION.id + bot.SESSION.folderName = bot.processNode.session.config.folderName + "-" + bot.SESSION.id } /* Check if there is a session */ @@ -59,13 +59,13 @@ bot.RESUME = message.event.resume /* Set the folderName for logging, reports, context and data output */ - let code - if (bot.SESSION.code !== undefined) { - code = bot.SESSION.code - if (code.folderName === undefined) { + let config + if (bot.SESSION.config !== undefined) { + config = bot.SESSION.config + if (config.folderName === undefined) { bot.SESSION.folderName = bot.SESSION.id } else { - bot.SESSION.folderName = code.folderName + "-" + bot.SESSION.id + bot.SESSION.folderName = config.folderName + "-" + bot.SESSION.id } } @@ -173,8 +173,8 @@ let balancePercentage = 1 // This is the default value - if (bot.SESSION.code.balancePercentage !== undefined) { - balancePercentage = bot.SESSION.code.balancePercentage + if (bot.SESSION.config.balancePercentage !== undefined) { + balancePercentage = bot.SESSION.config.balancePercentage } bot.VALUES_TO_USE.initialBalanceA = bot.VALUES_TO_USE.initialBalanceA * balancePercentage / 100 @@ -285,38 +285,38 @@ if (bot.SESSION.parameters.baseAsset.referenceParent !== undefined) { if (bot.SESSION.parameters.baseAsset.referenceParent.referenceParent !== undefined) { - let code = bot.SESSION.parameters.baseAsset.referenceParent.referenceParent.code + let config = bot.SESSION.parameters.baseAsset.referenceParent.referenceParent.config - if (code.codeName !== undefined) { - bot.VALUES_TO_USE.baseAsset = code.codeName; + if (config.codeName !== undefined) { + bot.VALUES_TO_USE.baseAsset = config.codeName; } - code = bot.SESSION.parameters.baseAsset.code + config = bot.SESSION.parameters.baseAsset.config if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { - if (code.initialBalance !== undefined) { - bot.VALUES_TO_USE.initialBalanceA = code.initialBalance; + if (config.initialBalance !== undefined) { + bot.VALUES_TO_USE.initialBalanceA = config.initialBalance; bot.VALUES_TO_USE.initialBalanceB = 0 } - if (code.minimumBalance !== undefined) { - bot.VALUES_TO_USE.minimumBalanceA = code.minimumBalance; + if (config.minimumBalance !== undefined) { + bot.VALUES_TO_USE.minimumBalanceA = config.minimumBalance; bot.VALUES_TO_USE.minimumBalanceB = 0 } - if (code.maximumBalance !== undefined) { - bot.VALUES_TO_USE.maximumBalanceA = code.maximumBalance; + if (config.maximumBalance !== undefined) { + bot.VALUES_TO_USE.maximumBalanceA = config.maximumBalance; bot.VALUES_TO_USE.maximumBalanceB = 0 } } else { - if (code.initialBalance !== undefined) { - bot.VALUES_TO_USE.initialBalanceB = code.initialBalance; + if (config.initialBalance !== undefined) { + bot.VALUES_TO_USE.initialBalanceB = config.initialBalance; bot.VALUES_TO_USE.initialBalanceA = 0 } - if (code.minimumBalance !== undefined) { - bot.VALUES_TO_USE.minimumBalanceB = code.minimumBalance; + if (config.minimumBalance !== undefined) { + bot.VALUES_TO_USE.minimumBalanceB = config.minimumBalance; bot.VALUES_TO_USE.minimumBalanceA = 0 } - if (code.maximumBalance !== undefined) { - bot.VALUES_TO_USE.maximumBalanceB = code.maximumBalance; + if (config.maximumBalance !== undefined) { + bot.VALUES_TO_USE.maximumBalanceB = config.maximumBalance; bot.VALUES_TO_USE.maximumBalanceA = 0 } } @@ -348,10 +348,10 @@ if (bot.SESSION.parameters.quotedAsset.referenceParent !== undefined) { if (bot.SESSION.parameters.quotedAsset.referenceParent.referenceParent !== undefined) { - let code = bot.SESSION.parameters.quotedAsset.referenceParent.referenceParent.code + let config = bot.SESSION.parameters.quotedAsset.referenceParent.referenceParent.config - if (code.codeName !== undefined) { - bot.VALUES_TO_USE.quotedAsset = code.codeName; + if (config.codeName !== undefined) { + bot.VALUES_TO_USE.quotedAsset = config.codeName; } } } @@ -360,59 +360,59 @@ /* Time Frame */ if (bot.SESSION.parameters.timeFrame !== undefined) { - bot.VALUES_TO_USE.timeFrame = bot.SESSION.parameters.timeFrame.code.value + bot.VALUES_TO_USE.timeFrame = bot.SESSION.parameters.timeFrame.config.value } /* Slippage */ if (bot.SESSION.parameters.slippage !== undefined) { - if (bot.SESSION.parameters.slippage.code !== undefined) { + if (bot.SESSION.parameters.slippage.config !== undefined) { - let code = bot.SESSION.parameters.slippage.code + let config = bot.SESSION.parameters.slippage.config - if (code.positionRate !== undefined) { - bot.VALUES_TO_USE.slippage.positionRate = code.positionRate + if (config.positionRate !== undefined) { + bot.VALUES_TO_USE.slippage.positionRate = config.positionRate } - if (code.stopLoss !== undefined) { - bot.VALUES_TO_USE.slippage.stopLoss = code.stopLoss + if (config.stopLoss !== undefined) { + bot.VALUES_TO_USE.slippage.stopLoss = config.stopLoss } - if (code.takeProfit !== undefined) { - bot.VALUES_TO_USE.slippage.takeProfit = code.takeProfit + if (config.takeProfit !== undefined) { + bot.VALUES_TO_USE.slippage.takeProfit = config.takeProfit } } } /* Fee Structure */ if (bot.SESSION.parameters.feeStructure !== undefined) { - if (bot.SESSION.parameters.feeStructure.code !== undefined) { + if (bot.SESSION.parameters.feeStructure.config !== undefined) { - let code = bot.SESSION.parameters.feeStructure.code + let config = bot.SESSION.parameters.feeStructure.config - if (code.maker !== undefined) { - bot.VALUES_TO_USE.feeStructure.maker = code.maker + if (config.maker !== undefined) { + bot.VALUES_TO_USE.feeStructure.maker = config.maker } - if (code.taker !== undefined) { - bot.VALUES_TO_USE.feeStructure.taker = code.taker + if (config.taker !== undefined) { + bot.VALUES_TO_USE.feeStructure.taker = config.taker } } } /* Time Range */ if (bot.SESSION.parameters.timeRange !== undefined) { - if (bot.SESSION.parameters.timeRange.code !== undefined) { + if (bot.SESSION.parameters.timeRange.config !== undefined) { - let code = bot.SESSION.parameters.timeRange.code - if (code.initialDatetime !== undefined) { - if (isNaN(Date.parse(code.initialDatetime)) === true) { + let config = bot.SESSION.parameters.timeRange.config + if (config.initialDatetime !== undefined) { + if (isNaN(Date.parse(config.initialDatetime)) === true) { parentLogger.write(MODULE_NAME, "[WARN] initialize -> runSession -> setValuesToUse -> Cannot use initialDatatime provided at Session Parameters because it is not a valid Date."); } else { - bot.VALUES_TO_USE.timeRange.initialDatetime = new Date(code.initialDatetime) + bot.VALUES_TO_USE.timeRange.initialDatetime = new Date(config.initialDatetime) } } - if (code.finalDatetime !== undefined) { - if (isNaN(Date.parse(code.finalDatetime)) === true) { + if (config.finalDatetime !== undefined) { + if (isNaN(Date.parse(config.finalDatetime)) === true) { parentLogger.write(MODULE_NAME, "[WARN] initialize -> runSession -> setValuesToUse -> Cannot use finalDatetime provided at Session Parameters because it is not a valid Date."); } else { - bot.VALUES_TO_USE.timeRange.finalDatetime = new Date(code.finalDatetime) + bot.VALUES_TO_USE.timeRange.finalDatetime = new Date(config.finalDatetime) } } } @@ -429,8 +429,8 @@ for (let i = 0; i < bot.SESSION.socialBots.bots.length; i++) { let socialBot = bot.SESSION.socialBots.bots[i] if (socialBot.type === "Telegram Bot") { - let code = socialBot.code - socialBot.botInstance = initializeTelegramBot(code.botToken, code.chatId) + let config = socialBot.config + socialBot.botInstance = initializeTelegramBot(config.botToken, config.chatId) } } } @@ -440,13 +440,13 @@ for (let i = 0; i < bot.SESSION.socialBots.bots.length; i++) { let socialBot = bot.SESSION.socialBots.bots[i] try { - let code = announcement.code + let config = announcement.config if (socialBot.type === "Telegram Bot") { if (announcement.formulaValue !== undefined) { socialBot.botInstance.telegramAPI.sendMessage(socialBot.botInstance.chatId, announcement.formulaValue).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> initializeSocialBots -> announce -> Telegram API error -> err = " + err)) } else { - socialBot.botInstance.telegramAPI.sendMessage(socialBot.botInstance.chatId, code.text).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> initializeSocialBots -> announce -> Telegram API error -> err = " + err)) + socialBot.botInstance.telegramAPI.sendMessage(socialBot.botInstance.chatId, config.text).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> initializeSocialBots -> announce -> Telegram API error -> err = " + err)) } } @@ -467,8 +467,8 @@ for (let i = 0; i < bot.SESSION.socialBots.bots.length; i++) { let socialBot = bot.SESSION.socialBots.bots[i] if (socialBot.type === "Telegram Bot") { - let code = socialBot.code - socialBot.botInstance = finalizeTelegramBot(code.chatId) + let config = socialBot.config + socialBot.botInstance = finalizeTelegramBot(config.chatId) } } } diff --git a/StatusReport.js b/StatusReport.js index 65609aa40..b9865452e 100644 --- a/StatusReport.js +++ b/StatusReport.js @@ -59,7 +59,7 @@ return } - if (statusDependencyNode.referenceParent.parentNode.code.codeName === undefined) { + if (statusDependencyNode.referenceParent.parentNode.config.codeName === undefined) { logger.write(MODULE_NAME, "[ERROR] initialize -> Process Definition witn no codeName defined. Process Definition = " + JSON.stringify(statusDependencyNode.referenceParent.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return @@ -71,7 +71,7 @@ return } - if (statusDependencyNode.referenceParent.parentNode.parentNode.code.codeName === undefined) { + if (statusDependencyNode.referenceParent.parentNode.parentNode.config.codeName === undefined) { logger.write(MODULE_NAME, "[ERROR] initialize -> Bot witn no codeName defined. Bot = " + JSON.stringify(statusDependencyNode.referenceParent.parentNode.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return @@ -83,22 +83,22 @@ return } - if (statusDependencyNode.referenceParent.parentNode.parentNode.parentNode.code.codeName === undefined) { + if (statusDependencyNode.referenceParent.parentNode.parentNode.parentNode.config.codeName === undefined) { logger.write(MODULE_NAME, "[ERROR] initialize -> Data Mine witn no codeName defined. Data Mine = " + JSON.stringify(statusDependencyNode.referenceParent.parentNode.parentNode.parentNode)); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return } /* Simplifying the access to basic info */ - statusDependencyNode.bot = statusDependencyNode.referenceParent.parentNode.parentNode.code.codeName - statusDependencyNode.process = statusDependencyNode.referenceParent.parentNode.code.codeName + statusDependencyNode.bot = statusDependencyNode.referenceParent.parentNode.parentNode.config.codeName + statusDependencyNode.process = statusDependencyNode.referenceParent.parentNode.config.codeName statusDependencyNode.bottype = statusDependencyNode.referenceParent.parentNode.parentNode.type - statusDependencyNode.dataMine = statusDependencyNode.referenceParent.parentNode.parentNode.parentNode.code.codeName + statusDependencyNode.dataMine = statusDependencyNode.referenceParent.parentNode.parentNode.parentNode.config.codeName /* We retrieve the report main utility */ - if (statusDependencyNode.code !== undefined) { - if (statusDependencyNode.code.mainUtility !== undefined) { - thisObject.mainUtility = statusDependencyNode.code.mainUtility + if (statusDependencyNode.config !== undefined) { + if (statusDependencyNode.config.mainUtility !== undefined) { + thisObject.mainUtility = statusDependencyNode.config.mainUtility } } @@ -156,9 +156,9 @@ /* We found where the task that runs the process definition this status report depends on and where it is located on the network. */ thisObject.networkNode = networkNode - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Retrieving status report from " + networkNode.name + " -> host = " + networkNode.code.host + ' -> port = ' + networkNode.code.webPort + '.'); } + if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Retrieving status report from " + networkNode.name + " -> host = " + networkNode.config.host + ' -> port = ' + networkNode.config.webPort + '.'); } - fileStorage = FILE_STORAGE.newFileStorage(logger, networkNode.code.host, networkNode.code.webPort); + fileStorage = FILE_STORAGE.newFileStorage(logger, networkNode.config.host, networkNode.config.webPort); callBackFunction(global.DEFAULT_OK_RESPONSE); return true } diff --git a/TradingSimulation.js b/TradingSimulation.js index d55c3db4e..313b2e1e7 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -294,9 +294,9 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT for (let k = 0; k < dataDependencies.length; k++) { let dataDependencyNode = dataDependencies[k] - if (dataDependencyNode.referenceParent.code.codeName !== 'Multi-Period-Daily') { continue } - let singularVariableName = dataDependencyNode.referenceParent.parentNode.code.singularVariableName - let pluralVariableName = dataDependencyNode.referenceParent.parentNode.code.pluralVariableName + if (dataDependencyNode.referenceParent.config.codeName !== 'Multi-Period-Daily') { continue } + let singularVariableName = dataDependencyNode.referenceParent.parentNode.config.singularVariableName + let pluralVariableName = dataDependencyNode.referenceParent.parentNode.config.pluralVariableName let currentElement = getElement(thisChart[pluralVariableName], candle, 'Daily' + '-' + mapKey + '-' + pluralVariableName) thisChart[singularVariableName] = currentElement } @@ -311,9 +311,9 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT for (let k = 0; k < dataDependencies.length; k++) { let dataDependencyNode = dataDependencies[k] - if (dataDependencyNode.referenceParent.code.codeName !== 'Multi-Period-Market') { continue } - let singularVariableName = dataDependencyNode.referenceParent.parentNode.code.singularVariableName - let pluralVariableName = dataDependencyNode.referenceParent.parentNode.code.pluralVariableName + if (dataDependencyNode.referenceParent.config.codeName !== 'Multi-Period-Market') { continue } + let singularVariableName = dataDependencyNode.referenceParent.parentNode.config.singularVariableName + let pluralVariableName = dataDependencyNode.referenceParent.parentNode.config.pluralVariableName let currentElement = getElement(thisChart[pluralVariableName], candle, 'Market' + '-' + mapKey + '-' + pluralVariableName) thisChart[singularVariableName] = currentElement } @@ -333,9 +333,9 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT for (let k = 0; k < dataDependencies.length; k++) { let dataDependencyNode = dataDependencies[k] - if (dataDependencyNode.referenceParent.code.codeName !== 'Single-File') { continue } - let singularVariableName = dataDependencyNode.referenceParent.parentNode.code.singularVariableName - let pluralVariableName = dataDependencyNode.referenceParent.parentNode.code.pluralVariableName + if (dataDependencyNode.referenceParent.config.codeName !== 'Single-File') { continue } + let singularVariableName = dataDependencyNode.referenceParent.parentNode.config.singularVariableName + let pluralVariableName = dataDependencyNode.referenceParent.parentNode.config.pluralVariableName let elementArray = thisChart[pluralVariableName] let currentElement if (elementArray !== undefined) { @@ -2339,8 +2339,8 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT /* The Value Variation is what tells us how much the value already announced must change in order to annouce it again. */ let valueVariation - let code = announcement.code - valueVariation = code.valueVariation + let config = announcement.config + valueVariation = config.valueVariation if (newAnnouncementRecord.value !== undefined && valueVariation !== undefined) { let upperLimit = newAnnouncementRecord.value + newAnnouncementRecord.value * valueVariation / 100 diff --git a/server.js b/server.js index 80ac46a62..e2840cc6d 100644 --- a/server.js +++ b/server.js @@ -57,7 +57,7 @@ function finalizeSessions() { } } -process.on('exit', function (code) { +process.on('exit', function (config) { if (global.TASK_NODE !== undefined) { /* We send an event signaling that the Task is being terminated. */ @@ -68,7 +68,7 @@ process.on('exit', function (code) { global.EVENT_SERVER_CLIENT = undefined } - //console.log('[INFO] Task Server -> server -> process.on.exit -> About to exit -> code = ' + code) + //console.log('[INFO] Task Server -> server -> process.on.exit -> About to exit -> config = ' + config) }) /* Here we listen for the message to stop this Task / Process comming from the Task Manager, which is the paret of this node js process. */ @@ -84,7 +84,7 @@ process.on('message', message => { let key = global.TASK_NODE.name + '-' + global.TASK_NODE.type + '-' + global.TASK_NODE.id console.log('[INFO] Task Server -> server -> process.on -> Stopping Task ' + key + '. Nodejs process will be exited in less than 1 minute.') setTimeout(global.EXIT_NODE_PROCESS, 60000); - } + } }); @@ -101,7 +101,7 @@ global.EXIT_NODE_PROCESS = function exitProcess() { clearInterval(global.HEARTBEAT_INTERVAL_HANDLER) for (let i = 0; i < global.TASK_NODE.bot.processes.length; i++) { - let code = global.TASK_NODE.bot.processes[i].code + let config = global.TASK_NODE.bot.processes[i].config let process = global.TASK_NODE.bot.processes[i] key = process.name + '-' + process.type + '-' + process.id @@ -138,7 +138,7 @@ let taskId = process.argv[2] // reading what comes as an argument of the nodejs /* Setting up the global Event Handler */ let EVENT_SERVER_CLIENT = require('./EventServerClient.js'); - + global.EVENT_SERVER_CLIENT = EVENT_SERVER_CLIENT.newEventsServerClient() global.EVENT_SERVER_CLIENT.initialize(preLoader) global.STOP_TASK_GRACEFULLY = false; @@ -162,7 +162,7 @@ function preLoader() { } } else { /* This process was started not by the Task Manager, but independently (most likely for debugging purposes). In this case we listen to an event with the Task Info that should be emitted at the UI */ - try { + try { //console.log('[INFO] Task Server -> server -> preLoader -> Waiting for event to start debugging...') global.EVENT_SERVER_CLIENT.listenToEvent('Task Server', 'Debug Task Started', undefined, 'Task Server', undefined, startDebugging) function startDebugging(message) { @@ -190,15 +190,15 @@ function bootLoader() { function taskHearBeat() { - /* The heartbeat event is raised at the event handler of the instance of this task, created at the UI. */ + /* The heartbeat event is raised at the event handler of the instance of this task, created at the UI. */ let event = { seconds: (new Date()).getSeconds() } - global.EVENT_SERVER_CLIENT.raiseEvent(key, 'Heartbeat', event) + global.EVENT_SERVER_CLIENT.raiseEvent(key, 'Heartbeat', event) } for (let processIndex = 0; processIndex < global.TASK_NODE.bot.processes.length; processIndex++) { - let code = global.TASK_NODE.bot.processes[processIndex].code + let config = global.TASK_NODE.bot.processes[processIndex].config /* Validate that the minimun amount of input required are defined. */ @@ -257,17 +257,17 @@ function bootLoader() { continue } - if (global.TASK_NODE.bot.processes[processIndex].referenceParent.code.codeName === undefined) { + if (global.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName === undefined) { console.log("[WARN] Task Server -> server -> bootLoader -> Process Definition without a codeName defined. -> Process Definition = " + JSON.stringify(global.TASK_NODE.bot.processes[processIndex].referenceParent)); continue } - if (global.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.code.codeName === undefined) { + if (global.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName === undefined) { console.log("[WARN] Task Server -> server -> bootLoader -> Bot Definition without a codeName defined. -> Bot Definition = " + JSON.stringify(global.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode)); continue } - if (global.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.code.codeName === undefined) { + if (global.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName === undefined) { console.log("[WARN] Task Server -> server -> bootLoader -> Data Mine without a codeName defined. -> Data Mine Definition = " + JSON.stringify(global.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode)); continue } @@ -278,7 +278,7 @@ function bootLoader() { function startRoot(processIndex) { - // console.log('[INFO] Task Server -> server -> startRoot -> Entering function. ') + // console.log('[INFO] Task Server -> server -> startRoot -> Entering function. ') const ROOT_MODULE = require('./Root') let root = ROOT_MODULE.newRoot() @@ -299,13 +299,13 @@ global.getPercentage = function (fromDate, currentDate, lastDate) { if ((lastDays - fromDays) === 0) { percentage = 100 } - return percentage + return percentage } global.areEqualDates = function (date1, date2) { let day1Days = Math.trunc(date1.valueOf() / ONE_DAY_IN_MILISECONDS) let day2Days = Math.trunc(date2.valueOf() / ONE_DAY_IN_MILISECONDS) - + if (day1Days === day2Days) { return true } else { From d8821e138c14d2df508b80a6b5fdce8fbff9aad7 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 1 Jun 2020 10:32:45 +0200 Subject: [PATCH 43/44] Update Session.js --- Session.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Session.js b/Session.js index f8fdc0f1e..feb0e7421 100644 --- a/Session.js +++ b/Session.js @@ -54,6 +54,7 @@ /* We are going to run the Definition comming at the event. */ bot.TRADING_SYSTEM = JSON.parse(message.event.tradingSystem) + bot.TRADING_ENGINE = JSON.parse(message.event.tradingEngine) bot.SESSION = JSON.parse(message.event.session) bot.DEPENDENCY_FILTER = JSON.parse(message.event.dependencyFilter) bot.RESUME = message.event.resume From c878c267d3993700029011a0dcad271bbdab5cb9 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 1 Jun 2020 12:29:09 +0200 Subject: [PATCH 44/44] Recursive Initialization Ready --- Assistant.js | 1127 ----------------- Context.js | 551 -------- MultiPeriod.js | 2 +- Session.js | 9 + TradingBot.js => Trading/TradingBot.js | 2 +- Trading/TradingEngine.js | 69 + .../TradingSimulation.js | 40 +- 7 files changed, 103 insertions(+), 1697 deletions(-) delete mode 100644 Assistant.js delete mode 100644 Context.js rename TradingBot.js => Trading/TradingBot.js (99%) create mode 100644 Trading/TradingEngine.js rename TradingSimulation.js => Trading/TradingSimulation.js (98%) diff --git a/Assistant.js b/Assistant.js deleted file mode 100644 index 9a98b1cbd..000000000 --- a/Assistant.js +++ /dev/null @@ -1,1127 +0,0 @@ -exports.newAssistant = function newAssistant(BOT, logger, UTILITIES) { - - /* - This module allows trading bots to execute actions on the exchange. - */ - - const MODULE_NAME = "Assistant"; - - let bot = BOT; - - let thisObject = { - dataDependencies: undefined, - initialize: initialize, - createOrder: createOrder, - getPositions: getPositions, - getBalance: getBalance, - getAvailableBalance: getAvailableBalance, - getInitialBalance: getInitialBalance, - getProfits: getProfits, - getCombinedProfits: getCombinedProfits, - getROI: getROI, - getMarketRate: getMarketRate, - getTicker: getTicker, - sendMessage: sendMessage, - rememberThis: rememberThis, - remindMeOf: remindMeOf, - truncDecimals: truncDecimals, - sendEmail: sendEmail, - addExtraData: addExtraData - }; - - let utilities = UTILITIES.newCloudUtilities(logger); - - let openOrders = []; // These are the open positions at the exchange at the account the bot is authorized to use. - let openPositions = []; // These are the open positions the bot knows it made by itself. - - let context; - let exchangeAPI; - - let marketRate; - let ticker; - - return thisObject; - - function initialize(pContext, pExchangeAPI, pDataDependencies, callBackFunction) { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } - - /* Save local values. */ - - context = pContext; - exchangeAPI = pExchangeAPI; - thisObject.dataDependencies = pDataDependencies; - - switch (bot.startMode) { - - case 'Live': { - getMarketRateFromExchange(); - break; - } - - case 'Backtest': { - validateExchangeSyncronicity(); - break; - } - - default: { - logger.write(MODULE_NAME, "[ERROR] initialize -> Unexpected bot.startMode."); - logger.write(MODULE_NAME, "[ERROR] initialize -> bot.startMode = " + bot.startMode); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - return; - } - } - - function getMarketRateFromExchange() { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> getMarketRateFromExchange -> Entering function."); } - - exchangeAPI.getTicker(bot.market, onTicker); - - return; - - function onTicker(err, pTicker) { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> getMarketRateFromExchange -> onTicker -> Entering function."); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> getMarketRateFromExchange -> onTicker -> We could not get the Market Price now."); } - - callBackFunction(global.DEFAULT_RETRY_RESPONSE); - return; - } - - ticker = pTicker; - marketRate = pTicker.last; - - context.newHistoryRecord.marketRate = marketRate; - - validateExchangeSyncronicity(); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> getMarketRateFromExchange -> onTicker -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> getMarketRateFromExchange -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function validateExchangeSyncronicity() { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> validateExchangeSyncronicity -> Entering function."); } - - /* Procedure to validate we are in sync with the exchange. */ - - getPositionsAtExchange(onDone); - - function onDone(err) { - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> validateExchangeSyncronicity -> onDone -> Entering function."); } - - switch (err.result) { - case global.DEFAULT_OK_RESPONSE.result: { - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> validateExchangeSyncronicity -> onDone -> Execution finished well."); } - calculateProfits(); - return; - } - break; - case global.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, "[ERROR] initialize -> validateExchangeSyncronicity -> onDone -> Retry Later. Requesting Execution Retry."); - callBackFunction(err); - return; - } - break; - case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. - logger.write(MODULE_NAME, "[ERROR] initialize -> validateExchangeSyncronicity -> onDone -> Operation Failed. Aborting the process."); - callBackFunction(err); - return; - } - break; - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> validateExchangeSyncronicity -> onDone -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> onDone -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function calculateProfits() { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> calculateProfits -> Entering function."); } - - /* Calculate Profits */ - - if (context.executionContext.initialBalance.baseAsset > 0) { - - context.executionContext.profits.baseAsset = (thisObject.truncDecimals(context.executionContext.balance.baseAsset) - thisObject.truncDecimals(context.executionContext.initialBalance.baseAsset)) / thisObject.truncDecimals(context.executionContext.initialBalance.baseAsset); - context.executionContext.profits.baseAsset = thisObject.truncDecimals(context.executionContext.profits.baseAsset); - } - - if (context.executionContext.initialBalance.quotedAsset > 0) { - - context.executionContext.profits.quotedAsset = (thisObject.truncDecimals(context.executionContext.balance.quotedAsset) - thisObject.truncDecimals(context.executionContext.initialBalance.quotedAsset)) / thisObject.truncDecimals(context.executionContext.initialBalance.quotedAsset); - context.executionContext.profits.quotedAsset = thisObject.truncDecimals(context.executionContext.profits.quotedAsset); - } - - context.newHistoryRecord.profitsBaseAsset = context.executionContext.profits.baseAsset; - context.newHistoryRecord.profitsQuotedAsset = context.executionContext.profits.quotedAsset; - - /* Calculate Combined Profits */ - - if (context.executionContext.initialBalance.baseAsset > 0) { - - let convertedAssetsB = (thisObject.truncDecimals(context.executionContext.balance.quotedAsset) - thisObject.truncDecimals(context.executionContext.initialBalance.quotedAsset)) * marketRate; - convertedAssetsB = thisObject.truncDecimals(convertedAssetsB); - - context.executionContext.combinedProfits.baseAsset = (thisObject.truncDecimals(context.executionContext.balance.baseAsset) + convertedAssetsB - thisObject.truncDecimals(context.executionContext.initialBalance.baseAsset)) / thisObject.truncDecimals(context.executionContext.initialBalance.baseAsset) * 100; - context.executionContext.combinedProfits.baseAsset = thisObject.truncDecimals(context.executionContext.combinedProfits.baseAsset); - } - - if (context.executionContext.initialBalance.quotedAsset > 0) { - - let convertedAssetsA = (thisObject.truncDecimals(context.executionContext.balance.baseAsset) - thisObject.truncDecimals(context.executionContext.initialBalance.baseAsset)) / marketRate; - convertedAssetsA = thisObject.truncDecimals(convertedAssetsA); - - context.executionContext.combinedProfits.quotedAsset = (thisObject.truncDecimals(context.executionContext.balance.quotedAsset) + convertedAssetsA - thisObject.truncDecimals(context.executionContext.initialBalance.quotedAsset)) / thisObject.truncDecimals(context.executionContext.initialBalance.quotedAsset) * 100; - context.executionContext.combinedProfits.quotedAsset = thisObject.truncDecimals(context.executionContext.combinedProfits.quotedAsset); - } - - context.newHistoryRecord.combinedProfitsA = context.executionContext.combinedProfits.baseAsset; - context.newHistoryRecord.combinedProfitsB = context.executionContext.combinedProfits.quotedAsset; - - callBackFunction(global.DEFAULT_OK_RESPONSE); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> calculateProfits -> err = " + err.stack); - callBack(global.DEFAULT_FAIL_RESPONSE); - return; - } - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function getPositionsAtExchange(callBack) { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getPositionsAtExchange -> Entering function."); } - - /* - - Here we grab all the positions at the exchange for the account we are using for trading. We will not asume all the positions - were made by this bot, but we need them all to later check if all the ones made by the bot are still there, were executed or - manually cancelled by the exchange account owner. - - */ - - switch (bot.startMode) { - - case "Live": { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getPositionsAtExchange -> Live Mode Detected."); } - exchangeAPI.getOpenOrders(bot.market, onResponse); - break; - } - - case "Backtest": { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getPositionsAtExchange -> Backtest Mode Detected."); } - let openOrders = []; // We simulate all positions were executed. - onResponse(global.DEFAULT_OK_RESPONSE, openOrders); - break; - } - - default: { - logger.write(MODULE_NAME, "[ERROR] getPositionsAtExchange -> Unexpected bot.startMode."); - logger.write(MODULE_NAME, "[ERROR] getPositionsAtExchange -> bot.startMode = " + bot.startMode); - callBack(global.DEFAULT_FAIL_RESPONSE); - return; - } - } - - function onResponse(err, pOpenOrders) { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getPositionsAtExchange -> onResponse -> Entering function."); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getPositionsAtExchange -> onResponse -> pOpenOrders = " + JSON.stringify(pOpenOrders)); } - - switch (err.result) { - case global.DEFAULT_OK_RESPONSE.result: { // Everything went well, we have the information requested. - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getPositionsAtExchange -> onResponse -> Execution finished well."); } - openOrders = pOpenOrders; - ordersExecutionCheck(callBack); - return; - } - break; - case global.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, "[ERROR] getPositionsAtExchange -> onResponse -> Retry Later. Requesting Execution Retry."); - callBack(err); - return; - } - break; - case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. - logger.write(MODULE_NAME, "[ERROR] getPositionsAtExchange -> onResponse -> Operation Failed. Aborting the process."); - callBack(err); - return; - } - break; - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] getPositionsAtExchange -> err = " + err.stack); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - - function ordersExecutionCheck(callBack) { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> Entering function."); } - - /* - - Here we check that all the positions we know are still valid at the exchange. If they are not, we will try to take appropiate - actions. Reasons why the positions might not be there are: - - 1. The user / account owner closed the positions manually. - 2. The exchange for some reason closed the positions. In some exchanges positions have an expiration time. - 3. The orders were executed. - - Situations 1 and 2 are similar unexpected and we will stop the bot execution when we detect them. Number 3 is an - expected behaviour and we will take appropiate action. - - Also, the position might still be there but it might have been partially executed. To detect that we need to compare the - position amounts we have on file to the one we are receiving from the exchange. - - Before we begin, we have to remove all the orders that have been already closed at the last execution of the bot. - - */ - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> JSON.stringify(context.executionContext.positions) = " + JSON.stringify(context.executionContext.positions)); } - - let openPositions = []; - - for (let a = 0; a < context.executionContext.positions.length; a++) { - - if (context.executionContext.positions[a].status === "open") { - - openPositions.push(context.executionContext.positions[a]); - - } - } - - /* - - This removes all orders leaving only the not executed position. Consider that we do want executed positions to be recored on the file so as to - have a record of their execution. But at next execution these records must be deleted before the new Execution Context file is created and - this is what we do here. - - */ - - context.executionContext.positions = openPositions; - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> Removing executed positions."); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> JSON.stringify(context.executionContext.positions) = " + JSON.stringify(context.executionContext.positions)); } - - /* Now we can start checking what happened at the exchange. */ - - let i = 0; - - controlLoop(); - - function loopBody() { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> Entering function."); } - - let position = context.executionContext.positions[i]; - let exchangePosition; - - for (let j = 0; j < openOrders.length; j++) { - - if (position.id === openOrders[j].id) { - - exchangePosition = openOrders[j]; - positionFound(); - return; - } - } - - positionNotFound(); - return; - - function positionFound() { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> positionFound -> Entering function."); } - - /* - We update the final amountA based on what we got from the exchange. - This is needed since the values could be different from what we calculate. - */ - position.amountA = exchangePosition.amountA; - - /* - We need to know if the order was partially executed. To know that, we compare the amounts on file with the ones - received from the exchange. If they are the same, then the order is intact. Otherwise, to confirm a partial execution, - we will request the associated trades from the exchange. - */ - - if (position.amountB === exchangePosition.amountB) { - - /* Position is still there, untouched. Nothing to do here. */ - - next(); - return; - - } else { - - getPositionTradesAtExchange(position.id, confirmOrderWasPartiallyExecuted); - return; - - } - } - - function positionNotFound() { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> positionNotFound -> Entering function."); } - - /* Position not found: we need to know if the order was executed. */ - - getPositionTradesAtExchange(position.id, confirmOrderWasExecuted); - - } - - function getPositionTradesAtExchange(pOrderId, innerCallBack) { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> Entering function."); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> pOrderId = " + pOrderId); } - - /* - - Given one position, we request all the associated trades to it. - - */ - - switch (bot.startMode) { - - case "Live": { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> Live Mode Detected."); } - exchangeAPI.getOrder(pOrderId, bot.market, onResponse); - return; - - } - - case "Backtest": { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> Backtest Mode Detected."); } - - let trades = []; - - /* We look for the position at the executionContext */ - - for (let i = 0; i < context.executionContext.positions.length; i++) { - - let thisOrder = context.executionContext.positions[i]; - - if (thisOrder.id === pOrderId) { - - let feeRate = 0.002; // Default backtesting fee simulation - - let trade = { - id: Math.trunc(Math.random(1) * 1000000), - type: thisOrder.type, - rate: thisOrder.rate.toString(), - amountA: thisObject.truncDecimals(thisOrder.amountA).toString(), - amountB: thisObject.truncDecimals(thisOrder.amountB).toString(), - fee: thisObject.truncDecimals(feeRate).toString(), - date: (new Date()).valueOf() - } - - trades.push(trade); - - let order = { - trades: trades - } - onResponse(global.DEFAULT_OK_RESPONSE, order); - - return; - } - } - - logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> Position not found at Executioin Context."); - callBack(global.DEFAULT_FAIL_RESPONSE); - return; - } - - default: { - logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> Unexpected bot.startMode."); - logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> bot.startMode = " + bot.startMode); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - return; - } - } - - function onResponse(err, order) { - - try { - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> onResponse -> Entering function."); } - - switch (err.result) { - case global.DEFAULT_OK_RESPONSE.result: { // Everything went well, we have the information requested. - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> onResponse -> Execution finished well."); } - innerCallBack(order); - } - break; - case global.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, "[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> onResponse -> Retry Later. Requesting Execution Retry."); - callBack(global.DEFAULT_RETRY_RESPONSE); - return; - } - break; - case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. - logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> onResponse -> Operation Failed. Aborting the process."); - callBack(global.DEFAULT_FAIL_RESPONSE); - return; - } - break; - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> onResponse -> err = " + err.stack); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> err = " + err.stack); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - - function confirmOrderWasExecuted(order) { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> Entering function."); } - if (global.LOG_CONTROL[MODULE_NAME].logContent === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> trades = " + JSON.stringify(trades)); } - - let trades = order.trades - /* - - To confirm everything is ok, we will add all the amounts on trades asociated to the order and - they must be equal to the one on file. Otherwise something very strange could have happened, - in which case we will halt the bot execution. - - */ - - let sumBaseAsset = 0; - let sumQuotedAsset = 0; - let sumRate = 0; - - for (let k = 0; k < trades.length; k++) { - let trade = trades[k]; - sumBaseAsset = sumBaseAsset + thisObject.truncDecimals(trade.amountA); - sumQuotedAsset = sumQuotedAsset + thisObject.truncDecimals(trade.amountB); - sumRate = sumRate + thisObject.truncDecimals(trade.rate); - } - - sumBaseAsset = thisObject.truncDecimals(sumBaseAsset); - sumQuotedAsset = thisObject.truncDecimals(sumQuotedAsset); - - if (position.amountB !== sumQuotedAsset) { - logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> position.amountB = " + position.amountB); - logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> sumQuotedAsset = " + sumQuotedAsset); - - logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> Cannot be confirmed that the order was executed. It must be manually cancelled by the user or cancelled by the exchange itself."); - logger.write(MODULE_NAME, "[HINT] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> If the process was abruptally cancelled and then restarted, it is possible that now is not sincronized with the exchange."); - logger.write(MODULE_NAME, "[HINT] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> In any case, to continue, you must manually delete the orders at the exchange."); - callBack(global.DEFAULT_FAIL_RESPONSE); - return; - } - - /* - - Confirmed that order was executed. Next thing to do is to remember the trades and change its status. - - */ - - position.status = "executed"; - - if (position.type === "sell") { - context.newHistoryRecord.sellExecRate = sumRate / trades.length; - } else { - context.newHistoryRecord.buyExecRate = sumRate / trades.length; - } - - applyTradesToContext(trades); - - let newTransaction = { - type: position.type + " executed", - position: position - }; - - context.executionContext.transactions.push(newTransaction); - - /* All done. */ - - next(); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> err = " + err.stack); - callBack(global.DEFAULT_FAIL_RESPONSE); - return; - } - } - - function confirmOrderWasPartiallyExecuted(trades) { - - try { - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> Entering function."); } - - let trades = order.trades - - /* - - To confirm everything is ok, we will add all the amounts on trades plus the remaining amounts - at the order at the exchange and they must be equal to the one on file. Otherwise an inconsistent - state has been detected, in which case we will halt the bot execution. - - */ - - let sumBaseAsset = 0; - let sumQuotedAsset = 0; - - for (let k = 0; k < trades.length; k++) { - let trade = trades[k]; - sumBaseAsset = sumBaseAsset + thisObject.truncDecimals(trade.amountA); - sumQuotedAsset = sumQuotedAsset + thisObject.truncDecimals(trade.amountB); - } - - /* To this we add the current position amounts. */ - - sumBaseAsset = sumBaseAsset + thisObject.truncDecimals(exchangePosition.amountA); - sumQuotedAsset = sumQuotedAsset + thisObject.truncDecimals(exchangePosition.amountB); - - sumBaseAsset = thisObject.truncDecimals(sumBaseAsset); - sumQuotedAsset = thisObject.truncDecimals(sumQuotedAsset); - - /* - * Next let's get the max decimal positions for the pair being trade returned by the exchange and validate that at least - * one decimal position less than the max matches. The reason for this is because there could be some - * rounding on the exchange when there are partial executed orders that will interfiere with the exact validation. - * - * IE: For Poloniex USDT/BTC the max returned decimal positions is 8, it means we will validate that the diference is less than 0.0000001 - */ - - let exchangeParam = exchangeAPI.getMaxDecimalPositions(); - let minValue = '0.' + (1).toPrecision(exchangeParam - 1).split('.').reverse().join(''); - let exchangePrecision = parseFloat(parseFloat(minValue).toFixed(exchangeParam)); - - if (Math.abs(position.amountA - sumBaseAsset) > exchangePrecision || Math.abs(position.amountB - sumQuotedAsset) > exchangePrecision) { - - logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> position.amountA = " + position.amountA); - logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> sumBaseAsset = " + sumBaseAsset); - logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> position.amountB = " + position.amountB); - logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> sumQuotedAsset = " + sumQuotedAsset); - - logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> Cannot confirm that a partial execution was done well."); - - /* There are diferences on the responses between the getPosition and getTrades that causes some issues, let's retry. */ - callBack(global.DEFAULT_RETRY_RESPONSE); - return; - } - - /* - - Confirmed that order was partially executed. Next thing to do is to remember the trades and the new position. - - */ - - position.amountA = exchangePosition.amountA; - position.amountB = exchangePosition.amountB; - position.date = (new Date(exchangePosition.date)).valueOf(); - - applyTradesToContext(trades); - - let newTransaction = { - type: position.type + " partially executed", - position: position - }; - - context.executionContext.transactions.push(newTransaction); - - /* All done. */ - - next(); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> err = " + err.stack); - callBack(global.DEFAULT_FAIL_RESPONSE); - return; - } - } - - function applyTradesToContext(trades) { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> loopBody -> applyTradesToContext -> Entering function."); } - - /* Here we apply the trades that already happened at the exchange to the balance and available balance of the bot. We also calculate its profits. */ - - for (k = 0; k < trades.length; k++) { - - let trade = trades[k]; - - position.trades.push(trade); - - context.newHistoryRecord.newTrades++; - - /* Calculate Balances */ - - let baseAsset = 0; - let quotedAsset = 0; - - if (trade.type === 'buy') { - - /* - - The fee received at each trade is the factor by which if we multiply asset B, we get the amount of Asset B extracted as fees by the exchange. - This happens with each individual trade. Remeber that one order can potentially be executed with 1 to many trades. - - */ - - let feeAmount = thisObject.truncDecimals(Number(trade.fee) * Number(trade.amountB)); - - baseAsset = Number(trade.amountA); - quotedAsset = Number(trade.amountB) - feeAmount; - - context.executionContext.balance.baseAsset = thisObject.truncDecimals(context.executionContext.balance.baseAsset - baseAsset); - context.executionContext.balance.quotedAsset = thisObject.truncDecimals(context.executionContext.balance.quotedAsset + quotedAsset); - - context.executionContext.availableBalance.quotedAsset = thisObject.truncDecimals(context.executionContext.availableBalance.quotedAsset + quotedAsset); - - /* Not the available balance for asset A is not affected since it was already reduced when the order was placed. */ - - } - - if (trade.type === 'sell') { - - /* - - The fee received at each trade is the factor by which if we multiply asset A, we get the amount of Asset A extracted as fees by the exchange. - This happens with each individual trade. Remeber that one order can potentially be executed with 1 to many trades. - - */ - - let feeAmount = thisObject.truncDecimals(Number(trade.fee) * Number(trade.amountA)); - - baseAsset = Number(trade.amountA) - feeAmount; - quotedAsset = Number(trade.amountB); - - context.executionContext.balance.baseAsset = thisObject.truncDecimals(context.executionContext.balance.baseAsset + baseAsset); - context.executionContext.balance.quotedAsset = thisObject.truncDecimals(context.executionContext.balance.quotedAsset - quotedAsset); - - context.executionContext.availableBalance.baseAsset = thisObject.truncDecimals(context.executionContext.availableBalance.baseAsset + baseAsset); - - /* Not the available balance for asset B is not affected since it was already reduced when the order was placed. */ - - } - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> applyTradesToContext -> err = " + err.stack); - callBack(global.DEFAULT_FAIL_RESPONSE); - return; - } - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> err = " + err.stack); - callBack(global.DEFAULT_FAIL_RESPONSE); - return; - } - } - - function next() { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> next -> Entering function."); } - - i++; - controlLoop(); - - } - - function controlLoop() { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> controlLoop -> Entering function."); } - - if (i < context.executionContext.positions.length) { - - loopBody(); - - } else { - - final(); - - } - } - - function final() { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] ordersExecutionCheck -> final -> Entering function."); } - - callBack(global.DEFAULT_OK_RESPONSE); - - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> err = " + err.stack); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - - function createOrder(pType, pRate, pAmountA, pAmountB, callBackFunction) { - - try { - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createOrder -> Entering function."); } - - /* Removing extra decimals. */ - - pRate = thisObject.truncDecimals(pRate); - pAmountA = thisObject.truncDecimals(pAmountA); - pAmountB = thisObject.truncDecimals(pAmountB); - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createOrder -> pType = " + pType); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createOrder -> pRate = " + pRate); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createOrder -> pAmountA = " + pAmountA); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createOrder -> pAmountB = " + pAmountB); } - - /* Validations that the limits are not surpassed. */ - - if (pType === 'buy') { - - if (pAmountA > thisObject.truncDecimals(context.executionContext.availableBalance.baseAsset)) { - - logger.write(MODULE_NAME, "[ERROR] createOrder -> Input Validations -> pAmountA is grater than the Available Balance."); - logger.write(MODULE_NAME, "[ERROR] createOrder -> Input Validations -> pAmountA = " + pAmountA); - logger.write(MODULE_NAME, "[ERROR] createOrder -> Input Validations -> Available Balance = " + thisObject.truncDecimals(context.executionContext.availableBalance.baseAsset)); - - let err = { - result: global.DEFAULT_FAIL_RESPONSE.result, - message: 'Not Enough Available Balance to Buy.' - }; - - callBackFunction(err); - return; - } - } - - if (pType === 'sell') { - - if (pAmountB > thisObject.truncDecimals(context.executionContext.availableBalance.quotedAsset)) { - - logger.write(MODULE_NAME, "[ERROR] createOrder -> Input Validations -> pAmountB is grater than the Available Balance."); - logger.write(MODULE_NAME, "[ERROR] createOrder -> Input Validations -> pAmountB = " + pAmountB); - logger.write(MODULE_NAME, "[ERROR] createOrder -> Input Validations -> Available Balance = " + thisObject.truncDecimals(context.executionContext.availableBalance.quotedAsset)); - - let err = { - result: global.DEFAULT_FAIL_RESPONSE.result, - message: 'Not Enough Available Balance to Sell.' - }; - - callBackFunction(err); - return; - } - } - - /* All validations passed, we proceed. */ - - switch (bot.startMode) { - - case "Live": { - - exchangeAPI.createOrder(bot.market, pType, pRate, pAmountA, pAmountB, onResponse); - return; - } - - case "Backtest": { - - if (pRate !== marketRate) { - - logger.write(MODULE_NAME, "[WARNING] createOrder -> Input Validations -> createOrder Rate can is different to marketRate while in Backtesting Mode. "); - //onResponse(global.DEFAULT_FAIL_RESPONSE, positionId); - } - - let positionId = Math.trunc(Math.random(1) * 1000000); - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createOrder -> Simulating Exchange Response -> orderId = " + positionId); } - onResponse(global.DEFAULT_OK_RESPONSE, positionId); - return; - } - - default: { - logger.write(MODULE_NAME, "[ERROR] createOrder -> Unexpected bot.startMode."); - logger.write(MODULE_NAME, "[ERROR] createOrder -> bot.startMode = " + bot.startMode); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - return; - } - } - - function onResponse(err, order) { - - try { - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createOrder -> onResponse -> Entering function."); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createOrder -> onResponse -> order.id = " + order.id); } - - switch (err.result) { - case global.DEFAULT_OK_RESPONSE.result: { // Everything went well, we have the information requested. - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createOrder -> onResponse -> Execution finished well."); } - - let position = { - id: order.id, - type: pType, - rate: pRate, - amountA: pAmountA, - amountB: pAmountB, - date: (bot.processDatetime.valueOf()), - status: "open", - trades: [] - }; - - context.executionContext.positions.push(position); - - let newTransaction = { - type: "newPosition", - position: position - }; - - context.executionContext.transactions.push(newTransaction); - - context.newHistoryRecord.newPositions++; - - recalculateRateAverages(); - - /* Recalculate Available Balances */ - - if (position.type === 'buy') { - - context.executionContext.availableBalance.baseAsset = thisObject.truncDecimals(context.executionContext.availableBalance.baseAsset - pAmountA); - context.newHistoryRecord.lastBuyRate = pRate; - } - - if (position.type === 'sell') { - - context.executionContext.availableBalance.quotedAsset = thisObject.truncDecimals(context.executionContext.availableBalance.quotedAsset - pAmountB); - context.newHistoryRecord.lastSellRate = pRate; - } - - callBackFunction(global.DEFAULT_OK_RESPONSE, position); - return; - } - break; - case global.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, "[ERROR] createOrder -> onResponse -> Retry Later. Requesting Execution Retry."); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); - return; - } - break; - case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. - logger.write(MODULE_NAME, "[ERROR] createOrder -> onResponse -> Operation Failed. Aborting the process."); - callBackFunction(err); - return; - } - break; - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] createOrder -> onResponse -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] createOrder -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function getPublicTradeHistory(baseAsset, quotedAsset, startTime, endTime, callback) { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getTradeHistory -> Entering function."); } - - exchangeAPI.getPublicTradeHistory(baseAsset, quotedAsset, startTime, endTime, callback); - } - - function recalculateRateAverages() { - - /* This function calculates the weighted rates of buy and sell positions. This is a way to summarize with only one rate, where the positions are. */ - - let sumBuyWeightedRates = 0; - let sumSellWeightedRates = 0; - - let sumBuyWeights = 0; - let sumSellWeights = 0; - - for (let i = 0; i < context.executionContext.positions.length; i++) { - - let position = context.executionContext.positions[i]; - - if (position.type === 'buy') { - - sumBuyWeightedRates = sumBuyWeightedRates + position.rate * position.amountB - sumBuyWeights = sumBuyWeights + position.amountB; - - } - - if (position.type === 'sell') { - - sumSellWeightedRates = sumSellWeightedRates + position.rate * position.amountB - sumSellWeights = sumSellWeights + position.amountB; - - } - - } - - context.newHistoryRecord.buyAvgRate = (sumBuyWeightedRates / sumBuyWeights || 0); - context.newHistoryRecord.sellAvgRate = (sumSellWeightedRates / sumSellWeights || 0); - } - - function getPositions() { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getPositions -> Entering function."); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getPositions -> JSON.stringify(context.executionContext.positions) = " + JSON.stringify(context.executionContext.positions)); } - - return JSON.parse(JSON.stringify(context.executionContext.positions)); - } - - function getBalance() { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getBalance -> Entering function."); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getBalance -> JSON.stringify(context.executionContext.balance) = " + JSON.stringify(context.executionContext.balance)); } - - return JSON.parse(JSON.stringify(context.executionContext.balance)); - } - - function getAvailableBalance() { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getAvailableBalance -> Entering function."); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getAvailableBalance -> JSON.stringify(context.executionContext.availableBalance) = " + JSON.stringify(context.executionContext.availableBalance)); } - - return JSON.parse(JSON.stringify(context.executionContext.availableBalance)); - } - - function getInitialBalance() { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getInitialBalance -> Entering function."); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getInitialBalance -> JSON.stringify(context.executionContext.initialBalance) = " + JSON.stringify(context.executionContext.initialBalance)); } - - return JSON.parse(JSON.stringify(context.executionContext.initialBalance)); - } - - function getProfits() { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getProfits -> Entering function."); } - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getProfits -> JSON.stringify(context.executionContext.profits) = " + JSON.stringify(context.executionContext.profits)); } - - return JSON.parse(JSON.stringify(context.executionContext.profits)); - } - - function getCombinedProfits() { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getCombinedProfits -> Entering function."); } - - let combinedProfits = { - baseAsset: context.newHistoryRecord.combinedProfitsA, - quotedAsset: context.newHistoryRecord.combinedProfitsB - } - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getCombinedProfits -> JSON.stringify(combinedProfits) = " + JSON.stringify(combinedProfits)); } - - return JSON.parse(JSON.stringify(combinedProfits)); - } - - function getROI() { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getROI -> Entering function."); } - - let ROI = { - baseAsset: (context.executionContext.balance.baseAsset - context.executionContext.initialBalance.baseAsset) / context.executionContext.initialBalance.baseAsset * 100, - quotedAsset: (context.executionContext.balance.quotedAsset - context.executionContext.initialBalance.quotedAsset) / context.executionContext.initialBalance.quotedAsset * 100 - } - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getROI -> JSON.stringify(ROI) = " + JSON.stringify(ROI)); } - - return JSON.parse(JSON.stringify(ROI)); - } - - function getMarketRate() { - return marketRate; - } - - function getTicker() { - return ticker; - } - - function sendMessage(pRelevance, pTitle, pBody) { - let runIndex = context.statusReport.runs.length - 1; - - context.newHistoryRecord.messageRelevance = pRelevance; - context.newHistoryRecord.messageTitle = bot.startMode + "." + runIndex + ": " + pTitle; - context.newHistoryRecord.messageBody = pBody; - } - - function rememberThis(pKey, pValue) { - if (context.executionContext.remember === undefined) { - context.executionContext.remember = {}; - } - context.executionContext.remember[pKey] = pValue; - } - - function remindMeOf(pKey) { - if (context.executionContext.remember === undefined) { - context.executionContext.remember = {}; - } - return context.executionContext.remember[pKey]; - } - - function sendEmail(pTitle, pBody, pTo) { - logger.write(MODULE_NAME, "[WARN] sendEmail -> Send emails is currently disabled."); - return; - } - - function addExtraData(pExtraDataArray) { - context.extraData.push(pExtraDataArray); - } - - function truncDecimals(pFloatValue, pDecimals) { - if (!pDecimals) pDecimals = 8; // Default value - return parseFloat(parseFloat(pFloatValue).toFixed(pDecimals)); - } -}; diff --git a/Context.js b/Context.js deleted file mode 100644 index bc347977b..000000000 --- a/Context.js +++ /dev/null @@ -1,551 +0,0 @@ -exports.newContext = function newContext(BOT, logger, UTILITIES) { - - let bot = BOT; - - const MODULE_NAME = "Context"; - - /* - - This module deals with keeping the context between different executions of the bot. Conceptually this context is divided in 3 main parts: - - I. The non-business information which helps the mechanisms of giving continuety to the bots execution over time. This information goes in a file - called the Status Report, and there is a module, child of this one called Status Report that deals with loading and saving the contents of that file. - - II. The business information around the bot execution, including its balance, positions at exchanges, trades executed and many other things. These - are platform data mantained on behalf of the executing bot. All these is kept in one file per execution called the Execution Context. The collection - of all these files can later reconstruct the vital business information the bot had at each moment in time. - - II. Execution of any bot cannot be guaranteed that will be on fixed interval of times. We need an index of all executions that points to the detailed files - with all the business informatino the bot had each time it executed. We call this index the Execution History and there is one file to store it. - - */ - - let thisObject = { - statusReport: undefined, // Here is the information that defines which was the last sucessfull execution and some other details. - executionHistory: [], // This is the record of bot execution. - executionContext: undefined, // Here is the business information of the last execution of this bot process. - newHistoryRecord : { - date: undefined, - buyAvgRate: 0, - sellAvgRate: 0, - lastSellRate: 0, - sellExecRate: 0, - lastBuyRate: 0, - buyExecRate: 0, - marketRate: 0, - newPositions: 0, - newTrades: 0, - movedPositions: 0, - profitsBaseAsset: 0, - profitsQuotedAsset: 0, - combinedProfitsA: 0, - combinedProfitsB: 0, - messageRelevance: 0, - messageTitle: "", - messageBody: "" - }, - initialize: initialize, - saveThemAll: saveThemAll, - extraData: [] - }; - - /* - - During the process we will create a new History Record. This will go to the Context History file which essentially mantains an - index of all the bots executions. This file will later be plotted by the bot s plotter on the timeline, allowing end users to - know where there is information related to the actions taken by the bot. - - */ - - let statusReportModule; - - /* Utilities needed. */ - - let utilities = UTILITIES.newCloudUtilities(logger); - - /* Storage account to be used here. */ - - const FILE_STORAGE = require('./FileStorage.js'); - let fileStorage = FILE_STORAGE.newFileStorage(logger); - - let statusDependencies; - - let runIndex; // This is the index for this run and depends on the startMode. - let sessionPath = '' - - return thisObject; - - function initialize(pStatusDependencies, callBackFunction) { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } - - statusDependencies = pStatusDependencies; - - if (bot.SESSION !== undefined) { - sessionPath = bot.SESSION.folderName + "/" - } - - /* - Here we get the positions the bot did and that are recorded at the bot storage account. We will use them through out the rest - of the process. - */ - thisObject.newHistoryRecord.date = bot.processDatetime; - - getStatusReport(onDone); - - function onDone(err) { - try { - - switch (err.result) { - case global.DEFAULT_OK_RESPONSE.result: { - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> onDone -> Execution finished well."); } - - callBackFunction(global.DEFAULT_OK_RESPONSE); - return; - } - case global.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, "[ERROR] initialize -> onDone -> Retry Later. Requesting Execution Retry."); - callBackFunction(err); - return; - } - case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. - logger.write(MODULE_NAME, "[ERROR] initialize -> onDone -> Operation Failed. Aborting the process."); - callBackFunction(err); - return; - } - default: { - logger.write(MODULE_NAME, "[ERROR] initialize -> onDone -> Operation Failed with custom response."); - logger.write(MODULE_NAME, "[ERROR] initialize -> onDone -> err = " + JSON.stringify(err)); - callBackFunction(err); - } - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> onDone -> err = "+ err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function getStatusReport(callBack) { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> getStatusReport -> Entering function."); } - - let key = bot.dataMine + "-" + bot.codeName + "-" + "Context" + "-" + bot.dataSetVersion; - - statusReportModule = statusDependencies.statusReports.get(key); - thisObject.statusReport = statusReportModule.file; - - /* The context is created in 2 situations: 1) when at the bot config is set not to continue using the same context after a new execution. 2) when the status report does not exist. */ - - if (bot.hasTheBotJustStarted === true || thisObject.statusReport.runs === undefined) { - - createConext(callBack); - - } else { - - runIndex = thisObject.statusReport.runs.length - 1; - - getExecutionHistory(callBack); - - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> getStatusReport -> err = "+ err.stack); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - - function getExecutionHistory(callBack) { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> getExecutionHistory -> Entering function."); } - - let fileName = "Execution.History." + bot.startMode + "." + runIndex + ".json"; - let filePath = bot.filePathRoot + "/Output/" + sessionPath + "Trading-Process/" + fileName; - - fileStorage.getTextFile(filePath, onFileReceived); - - function onFileReceived(err, text) { - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] initialize -> getExecutionHistory -> onFileReceived -> err = "+ JSON.stringify(err)); - callBack(err); - return; - } - - if (global.LOG_CONTROL[MODULE_NAME].logContent === true) { - logger.write(MODULE_NAME, "[INFO] initialize -> getExecutionHistory -> onFileReceived -> Content received = " + text); - } - - try { - - thisObject.executionHistory = JSON.parse(text); - - /* Move some values to the new record, in case there are no transactions that re-calculate them. */ - - thisObject.newHistoryRecord.buyAvgRate = thisObject.executionHistory[thisObject.executionHistory.length-1][1]; - thisObject.newHistoryRecord.sellAvgRate = thisObject.executionHistory[thisObject.executionHistory.length - 1][2]; - - getExecutionContext(callBack); - - } catch (err) { - - /* - - It might happen that the file content is corrupt or it does not exist. The bot can not run without an Execution Hitory, - since it is risky to ignore its own history unless it is its first execution in this mode ever. - - */ - - logger.write(MODULE_NAME, "[ERROR] initialize -> getExecutionHistory -> onFileReceived -> Bot cannot execute without the Execution History. -> Err = " + err.message); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> getExecutionHistory -> err = "+ err.stack); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - - function getExecutionContext(callBack) { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> getExecutionContext -> Entering function."); } - - let date; - - date = new Date(thisObject.statusReport.runs[runIndex].lastExecution); - thisObject.statusReport.runs[runIndex].lastExecution = bot.processDatetime; - thisObject.statusReport.runs[runIndex].endDatetime = bot.processDatetime; - - let fileName = "/Execution.Context." + bot.startMode + "." + runIndex + ".json"; - let dateForPath = date.getUTCFullYear() + '/' + utilities.pad(date.getUTCMonth() + 1, 2) + '/' + utilities.pad(date.getUTCDate(), 2) + '/' + utilities.pad(date.getUTCHours(), 2) + '/' + utilities.pad(date.getUTCMinutes(), 2); - let filePath = bot.filePathRoot + "/Output/" + sessionPath + "Trading-Process/" + dateForPath + fileName; - - fileStorage.getTextFile(filePath, onFileReceived); - - function onFileReceived(err, text) { - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] initialize -> getExecutionContext -> onFileReceived -> err = "+ err.stack); - callBack(err); - return; - } - - if (global.LOG_CONTROL[MODULE_NAME].logContent === true) { - logger.write(MODULE_NAME, "[INFO] initialize -> getExecutionContext -> onFileReceived -> Content received = " + text); - } - - try { - - thisObject.executionContext = JSON.parse(text); - thisObject.executionContext.transactions = []; // We record here the transactions that happened duting this execution. - - /* Update the new History Record, in case there are no trades during this execution that updates it. */ - - thisObject.newHistoryRecord.profitsBaseAsset = thisObject.executionContext.profits.baseAsset; - thisObject.newHistoryRecord.profitsQuotedAsset = thisObject.executionContext.profits.quotedAsset; - - thisObject.newHistoryRecord.combinedProfitsA = thisObject.executionContext.combinedProfits.baseAsset; - thisObject.newHistoryRecord.combinedProfitsB = thisObject.executionContext.combinedProfits.quotedAsset; - - callBack(global.DEFAULT_OK_RESPONSE); - - } catch (err) { - - /* - - It might happen that the file content is corrupt or it does not exist. The bot can not run without a Status Report, - since it is risky to ignore its own execution history. Except when the bot is running for the fist time in this mode, - an execution context file with the right format is needed. - - */ - - logger.write(MODULE_NAME, "[ERROR] initialize -> getExecutionContext -> onFileReceived -> Response from storage. -> Text = " + text); - logger.write(MODULE_NAME, "[ERROR] initialize -> getExecutionContext -> onFileReceived -> Bot cannot execute without the Execution Context. -> Err = " + err.message); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> getExecutionContext -> err = "+ err.stack); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - - function createConext(callBack) { - - try { - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> createConext -> Entering function."); } - /* - - When the bot is executed for the very first time, there are a few files that do not exist and need to be created, and that - content is what we are going to set up now. - - */ - - if (thisObject.statusReport.runs === undefined) { // This means that the Status Report does not exist. - - thisObject.statusReport.runs = []; - } - - let runContent = { - beginDatetime: bot.processDatetime, - endDatetime: bot.processDatetime, - lastExecution: bot.processDatetime - }; - - thisObject.statusReport.runs.push(runContent); - runIndex = thisObject.statusReport.runs.length - 1; - - thisObject.executionHistory = []; - - if (bot.VALUES_TO_USE.initialBalanceA === undefined || bot.VALUES_TO_USE.initialBalanceB === undefined) { throw new Error("Global Variables INITIAL_BALANCE_A and INITIAL_BALANCE_B cannot be undefined.") } - - const INITIAL_BALANCE_A = Number(bot.VALUES_TO_USE.initialBalanceB); // NOTE THAT THIS IS INVERTED BECAUSE OF POLONIEX THAT IS THE ONLY EXCHANGE SUPPORTED RIGHT NOW - const INITIAL_BALANCE_B = Number(bot.VALUES_TO_USE.initialBalanceA); - - - thisObject.executionContext = { - initialBalance: { // This is used to calculate profits. - baseAsset: INITIAL_BALANCE_A, - quotedAsset: INITIAL_BALANCE_B - }, - balance: { // This is the total balance that includes positions at the order book + funds available to be traded. - baseAsset: INITIAL_BALANCE_A, - quotedAsset: INITIAL_BALANCE_B // It starts with the initial initialBalance. - }, - availableBalance: { // This is the balance the bot has at any moment in time available to be traded (not in positions at the order book). - baseAsset: INITIAL_BALANCE_A, - quotedAsset: INITIAL_BALANCE_B // It starts with the initial initialBalance. - }, - profits: { - baseAsset: 0, - quotedAsset: 0 - }, - combinedProfits: { - baseAsset: 0, - quotedAsset: 0 - }, - positions: [], - transactions: [] - }; - - callBack(global.DEFAULT_OK_RESPONSE); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> createConext -> err = "+ err.stack); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> err = "+ err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function saveThemAll(callBackFunction) { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> Entering function."); } - - writeExecutionContext(onDone); - - function onDone(err) { - try { - - switch (err.result) { - case global.DEFAULT_OK_RESPONSE.result: { - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> onDone -> Execution finished well."); } - - bot.hasTheBotJustStarted = false; - - callBackFunction(global.DEFAULT_OK_RESPONSE); - return; - } - break; - case global.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, "[ERROR] saveThemAll -> onDone -> Retry Later. Requesting Execution Retry."); - callBackFunction(err); - return; - } - break; - case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. - logger.write(MODULE_NAME, "[ERROR] saveThemAll -> onDone -> Operation Failed. Aborting the process."); - callBackFunction(err); - return; - } - break; - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] saveThemAll -> onDone -> err = "+ err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeExecutionContext(callBack) { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> writeExecutionContext -> Entering function."); } - - let fileName = "/Execution.Context." + bot.startMode + "." + runIndex +".json"; - let dateForPath = bot.processDatetime.getUTCFullYear() + '/' + utilities.pad(bot.processDatetime.getUTCMonth() + 1, 2) + '/' + utilities.pad(bot.processDatetime.getUTCDate(), 2) + '/' + utilities.pad(bot.processDatetime.getUTCHours(), 2) + '/' + utilities.pad(bot.processDatetime.getUTCMinutes(), 2); - let filePath = bot.filePathRoot + "/Output/" + sessionPath + "Trading-Process/" + dateForPath + fileName; - let fileContent = JSON.stringify(thisObject.executionContext); - - if(fileContent === undefined){ - logger.write(MODULE_NAME, "[ERROR] saveThemAll -> writeExecutionContext -> executionContext is undefined."); - callBackFunction(global.DEFAULT_ERROR_RESPONSE); - } - - if (global.LOG_CONTROL[MODULE_NAME].logContent === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> writeExecutionContext -> fileContent = " + fileContent); } - - fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> writeExecutionContext -> onFileCreated -> Entering function."); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] saveThemAll -> writeExecutionContext -> onFileCreated -> err = "+ err.stack); - callBack(err); - return; - } - - writeExucutionHistory(callBack); - return; - } - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] saveThemAll -> writeExecutionContext -> err = "+ err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeExucutionHistory(callBack) { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> writeExucutionHistory -> Entering function."); } - - let fileName = "Execution.History." + bot.startMode + "." + runIndex + ".json"; - let filePath = bot.filePathRoot + "/Output/" + sessionPath + "Trading-Process/" + fileName; - - let newRecord = [ - thisObject.newHistoryRecord.date.valueOf(), - thisObject.newHistoryRecord.buyAvgRate, - thisObject.newHistoryRecord.sellAvgRate, - - thisObject.newHistoryRecord.lastSellRate, - thisObject.newHistoryRecord.sellExecRate, - thisObject.newHistoryRecord.lastBuyRate, - thisObject.newHistoryRecord.buyExecRate, - - thisObject.newHistoryRecord.marketRate, - thisObject.newHistoryRecord.newPositions, - thisObject.newHistoryRecord.newTrades, - thisObject.newHistoryRecord.movedPositions, - thisObject.newHistoryRecord.profitsBaseAsset, - thisObject.newHistoryRecord.profitsQuotedAsset, - thisObject.newHistoryRecord.combinedProfitsA, - thisObject.newHistoryRecord.combinedProfitsB, - - thisObject.newHistoryRecord.messageRelevance, - thisObject.newHistoryRecord.messageTitle, - thisObject.newHistoryRecord.messageBody, - thisObject.extraData - ]; - - thisObject.executionHistory.push(newRecord); - - let fileContent = JSON.stringify(thisObject.executionHistory); - - fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> writeExucutionHistory -> onFileCreated -> Entering function."); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] saveThemAll -> writeExucutionHistory -> onFileCreated -> err = "+ err.stack); - callBack(err); - return; - } - - if (global.LOG_CONTROL[MODULE_NAME].logContent === true) { - logger.write(MODULE_NAME, "[INFO] saveThemAll -> writeExucutionHistory -> onFileCreated -> Content written = " + fileContent); - } - - /* Here we will write the file containing the max sequence number. */ - - fileContent = runIndex; - fileName = "Execution.History." + bot.startMode + "." + "Sequence" + ".json"; - filePath = bot.filePathRoot + "/Output/" + sessionPath + "Trading-Process/" + fileName; - - fileStorage.createTextFile(filePath, fileContent + '\n', onSequenceFileCreated); - - function onSequenceFileCreated(err) { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> writeExucutionHistory -> onFileCreated -> onSequenceFileCreated -> Entering function."); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] saveThemAll -> writeExucutionHistory -> onFileCreated -> onSequenceFileCreated -> err = "+ err.stack); - callBack(err); - return; - } - - writeStatusReport(callBack); - return; - } - } - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] saveThemAll -> writeExucutionHistory -> err = "+ err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeStatusReport(callBack) { - - try { - - if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] saveThemAll -> writeStatusReport -> Entering function."); } - - statusReportModule.file = thisObject.statusReport; - statusReportModule.save(callBack); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] saveThemAll -> writeStatusReport -> err = "+ err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] saveThemAll -> Error = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function truncDecimals(pFloatValue, pDecimals) { - - if (!pDecimals) pDecimals = 8; // Default value - - return parseFloat(parseFloat(pFloatValue).toFixed(pDecimals)); - - } - -}; diff --git a/MultiPeriod.js b/MultiPeriod.js index bf46a4b85..c414630a3 100644 --- a/MultiPeriod.js +++ b/MultiPeriod.js @@ -41,7 +41,7 @@ dataDependenciesModule = pDataDependencies; processConfig = pProcessConfig; - let USER_BOT_MODULE = require("./TradingBot") + let USER_BOT_MODULE = require("./Trading/TradingBot") botInstance = USER_BOT_MODULE.newTradingBot(bot, logger, UTILITIES, FILE_STORAGE); botInstance.initialize(exchangeAPI, callBackFunction); diff --git a/Session.js b/Session.js index feb0e7421..3e84808ed 100644 --- a/Session.js +++ b/Session.js @@ -53,12 +53,21 @@ if (bot.SESSION_STATUS === 'Idle' || bot.SESSION_STATUS === 'Running') { return } // This happens when the UI is reloaded, the session was running and tries to run it again. /* We are going to run the Definition comming at the event. */ + bot.APP_SCHEMA_ARRAY = JSON.parse(message.event.appSchema) bot.TRADING_SYSTEM = JSON.parse(message.event.tradingSystem) bot.TRADING_ENGINE = JSON.parse(message.event.tradingEngine) bot.SESSION = JSON.parse(message.event.session) bot.DEPENDENCY_FILTER = JSON.parse(message.event.dependencyFilter) bot.RESUME = message.event.resume + /* Setup the APP_SCHEMA_MAP based on the APP_SCHEMA_ARRAY */ + bot.APP_SCHEMA_MAP = new Map() + for (let i = 0; i < bot.APP_SCHEMA_ARRAY.length; i++) { + let nodeDefinition = bot.APP_SCHEMA_ARRAY[i] + let key = nodeDefinition.type + bot.APP_SCHEMA_MAP.set(key, nodeDefinition) + } + /* Set the folderName for logging, reports, context and data output */ let config if (bot.SESSION.config !== undefined) { diff --git a/TradingBot.js b/Trading/TradingBot.js similarity index 99% rename from TradingBot.js rename to Trading/TradingBot.js index 699ccf512..37c791fc4 100644 --- a/TradingBot.js +++ b/Trading/TradingBot.js @@ -14,7 +14,7 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR let utilities = UTILITIES.newCloudUtilities(logger) let fileStorage = FILE_STORAGE.newFileStorage(logger) - const COMMONS = require('./Commons.js') + const COMMONS = require('../Commons.js') let commons = COMMONS.newCommons(bot, logger, UTILITIES, FILE_STORAGE) let exchangeAPI diff --git a/Trading/TradingEngine.js b/Trading/TradingEngine.js new file mode 100644 index 000000000..30207da99 --- /dev/null +++ b/Trading/TradingEngine.js @@ -0,0 +1,69 @@ +exports.newTradingEngine = function newTradingEngine(bot, logger) { + + const MODULE_NAME = 'Trading Engine' + + let thisObject = { + initialize: initialize, + finalize: finalize + } + + return thisObject + + function initialize() { + /* Here we will go through all the nodes in the Trading Engine hiriarchy and apply the initial value to the value property when needed */ + + if (bot.TRADING_ENGINE.isInitialized !== true || bot.RESUME === false) { + bot.TRADING_ENGINE.isInitialized = true + initializeNode(bot.TRADING_ENGINE) + } + } + + function finalize() { + + } + + 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 = bot.APP_SCHEMA_MAP.get(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] + object[property.name] = [] + for (let m = 0; m < nodePropertyArray.length; m++) { + initializeNode(nodePropertyArray[m]) + } + } + break + } + } + } + } + } +} + diff --git a/TradingSimulation.js b/Trading/TradingSimulation.js similarity index 98% rename from TradingSimulation.js rename to Trading/TradingSimulation.js index 313b2e1e7..0f78d4c25 100644 --- a/TradingSimulation.js +++ b/Trading/TradingSimulation.js @@ -52,9 +52,11 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } let tradingSystem = bot.TRADING_SYSTEM + let tradingEngine = bot.TRADING_ENGINE + let sessionParameters = bot.SESSION.parameters - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> bot.VALUES_TO_USE.timeRange.initialDatetime = ' + bot.VALUES_TO_USE.timeRange.initialDatetime) } - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> bot.VALUES_TO_USE.timeRange.finalDatetime = ' + bot.VALUES_TO_USE.timeRange.finalDatetime) } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> sessionParameters.timeRange.config.initialDatetime = ' + sessionParameters.timeRange.config.initialDatetime) } + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> sessionParameters.timeRange.config.finalDatetime = ' + sessionParameters.timeRange.config.finalDatetime) } let timerToCloseStage = 0 @@ -78,6 +80,10 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT lastInstantOfTheDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1 } + const TRADING_ENGINE_MODULE = require('./TradingEngine.js') + let tradingEngineModule = TRADING_ENGINE_MODULE.newTradingEngine(bot, logger) + tradingEngineModule.initialize() + if (variable.isInitialized !== true || bot.RESUME === false) { variable.isInitialized = true @@ -239,7 +245,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } else { /* Estimate Initial Candle based on the timeRage configured for the session. */ let firstEnd = candles[0].end - let targetEnd = bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf() + let targetEnd = sessionParameters.timeRange.config.initialDatetime.valueOf() let diff = targetEnd - firstEnd let amount = diff / variable.episode.parameters.timeFrame @@ -247,7 +253,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (currentCandleIndex < 0) { currentCandleIndex = 0 } if (currentCandleIndex > candles.length - 1) { /* - This will happen when the bot.VALUES_TO_USE.timeRange.initialDatetime is beyond the last candle available, + This will happen when the sessionParameters.timeRange.config.initialDatetime is beyond the last candle available, meaning that the dataSet needs to be updated with more up-to-date data. */ currentCandleIndex = candles.length - 1 @@ -274,13 +280,13 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT let candle = candles[currentCandleIndex] /* Not processing while out of user-defined time range */ - if (candle.end < bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Skipping Candle before the bot.VALUES_TO_USE.timeRange.initialDatetime.') } + if (candle.end < sessionParameters.timeRange.config.initialDatetime.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Skipping Candle before the sessionParameters.timeRange.config.initialDatetime.') } controlLoop() return } - if (candle.begin > bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Skipping Candle after the bot.VALUES_TO_USE.timeRange.finalDatetime.') } + if (candle.begin > sessionParameters.timeRange.config.finalDatetime.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Skipping Candle after the sessionParameters.timeRange.config.finalDatetime.') } afterLoop() return } @@ -367,8 +373,8 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Simulation ' + bot.sessionKey + ' Loop # ' + currentCandleIndex + ' @ ' + processingDate) } /* Telling the world we are alive and doing well */ - let fromDate = new Date(bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) - let lastDate = new Date(bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf()) + let fromDate = new Date(sessionParameters.timeRange.config.initialDatetime.valueOf()) + let lastDate = new Date(sessionParameters.timeRange.config.finalDatetime.valueOf()) let currentDateString = loopingDay.getUTCFullYear() + '-' + utilities.pad(loopingDay.getUTCMonth() + 1, 2) + '-' + utilities.pad(loopingDay.getUTCDate(), 2) let currentDate = new Date(loopingDay) @@ -1713,19 +1719,19 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT function putOpeningOrder() { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Entering function.') } - /* We wont take a position unless we are withing the bot.VALUES_TO_USE.timeRange.initialDatetime and the bot.VALUES_TO_USE.timeRange.finalDatetime range */ - if (bot.VALUES_TO_USE.timeRange.initialDatetime !== undefined) { - if (candle.end < bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because current candle ends before the start date. -> bot.VALUES_TO_USE.timeRange.initialDatetime = ' + bot.VALUES_TO_USE.timeRange.initialDatetime) } + /* We wont take a position unless we are withing the sessionParameters.timeRange.config.initialDatetime and the sessionParameters.timeRange.config.finalDatetime range */ + if (sessionParameters.timeRange.config.initialDatetime !== undefined) { + if (candle.end < sessionParameters.timeRange.config.initialDatetime.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because current candle ends before the start date. -> sessionParameters.timeRange.config.initialDatetime = ' + sessionParameters.timeRange.config.initialDatetime) } takePositionAtSimulation() return } } /* We wont take a position if we are past the final datetime */ - if (bot.VALUES_TO_USE.timeRange.finalDatetime !== undefined) { - if (candle.begin > bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because current candle begins after the end date. -> bot.VALUES_TO_USE.timeRange.finalDatetime = ' + bot.VALUES_TO_USE.timeRange.finalDatetime) } + if (sessionParameters.timeRange.config.finalDatetime !== undefined) { + if (candle.begin > sessionParameters.timeRange.config.finalDatetime.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because current candle begins after the end date. -> sessionParameters.timeRange.config.finalDatetime = ' + sessionParameters.timeRange.config.finalDatetime) } takePositionAtSimulation() return }