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/11] 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/11] 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/11] 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/11] 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/11] 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/11] 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/11] 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/11] 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/11] 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/11] 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/11] 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 = {