From 0fcd25e21412957a9ea743331d82bf9761e84720 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 25 Mar 2020 19:59:25 +0100 Subject: [PATCH 01/13] Bug fix --- FileStorage.js | 385 +++++++++++++++++++++++-------------------- TradingBot.js | 12 +- TradingSimulation.js | 51 ++++-- 3 files changed, 246 insertions(+), 202 deletions(-) diff --git a/FileStorage.js b/FileStorage.js index 2ec8a47ec..be6f08ccd 100644 --- a/FileStorage.js +++ b/FileStorage.js @@ -6,10 +6,7 @@ exports.newFileStorage = function newFileStorage(logger) { const MODULE_NAME = 'FileStorage' const MAX_RETRY = 30 const FAST_RETRY_TIME_IN_MILISECONDS = 500 - const SLOW_RETRY_TIME_IN_MILISECONDS = 5000 - let currentRetryGetTextFile = 0 - let currentRetryWriteTextFile = 0 - let currentRetryDeleteTextFile = 0 + const SLOW_RETRY_TIME_IN_MILISECONDS = 2000 if (logger === undefined) { // Dummy logger logger = {} @@ -29,94 +26,101 @@ exports.newFileStorage = function newFileStorage(logger) { function getTextFile(filePath, callBackFunction, noRetry) { - logger.write(MODULE_NAME, '[INFO] FileStorage -> getTextFile -> Entering Function.') + let currentRetryGetTextFile = 0 - let fileDoesNotExist = false + recursiveGetTextFile(filePath, callBackFunction, noRetry) - /* Choose path for either bots or data */ - let fileLocation - if (filePath.indexOf("/bots/") > 0) { - fileLocation = process.env.BOTS_PATH + '/' + filePath - } else { - fileLocation = process.env.STORAGE_PATH + '/' + filePath - } + function recursiveGetTextFile(filePath, callBackFunction, noRetry) { - try { + logger.write(MODULE_NAME, '[INFO] FileStorage -> getTextFile -> Entering Function.') - logger.write(MODULE_NAME, '[INFO] FileStorage -> getTextFile -> fileLocation: ' + fileLocation) + let fileDoesNotExist = false - /* Here we actually write the file. */ - const fs = require('fs') - fs.readFile(fileLocation, onFileRead) - - function onFileRead(err, text) { - let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS - if (currentRetryGetTextFile > MAX_RETRY - 2) { - retryTimeToUse = SLOW_RETRY_TIME_IN_MILISECONDS - } - if (err) { - - if (err.code === 'ENOENT') { // since files are deleted before being replaced, it can happen that it does not exist and after a retry it does. - if (noRetry === true) { - logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> File does not exist. Not Retrying. ') - let customResponse = { - result: global.CUSTOM_FAIL_RESPONSE.result, - message: 'File does not exist.' - } - callBackFunction(customResponse) - return - } else { - fileDoesNotExist = true - logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> File does not exist. Retrying. ') - setTimeout(retry, retryTimeToUse) - return - } - } - - logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> err = ' + err.stack) - logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> err = ' + err.stack) - setTimeout(retry, retryTimeToUse) - return - } - - if (text.toString() === "") { - logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Read and Empty File -> filePath = ' + filePath) - setTimeout(retry, retryTimeToUse) - return - } - - callBackFunction(global.DEFAULT_OK_RESPONSE, text.toString()) + /* Choose path for either bots or data */ + let fileLocation + if (filePath.indexOf("/bots/") > 0) { + fileLocation = process.env.BOTS_PATH + '/' + filePath + } else { + fileLocation = process.env.STORAGE_PATH + '/' + filePath } - } 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) - retry() - } + try { - function retry() { - //console.log(new Date(), ' Retry #: ' + currentRetryGetTextFile, fileLocation ) - if (currentRetryGetTextFile < MAX_RETRY) { - currentRetryGetTextFile++ - logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> retry -> Will try to read the file again -> Retry #: ' + currentRetryGetTextFile) - getTextFile(filePath, callBackFunction) - } else { - currentRetryGetTextFile = 0 + logger.write(MODULE_NAME, '[INFO] FileStorage -> getTextFile -> fileLocation: ' + fileLocation) - if (fileDoesNotExist === true) { - logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> retry -> Max retries reached reading a file. File Not Found.') - let customResponse = { - result: global.CUSTOM_FAIL_RESPONSE.result, - message: 'File does not exist.' + /* Here we actually write the file. */ + const fs = require('fs') + fs.readFile(fileLocation, onFileRead) + + function onFileRead(err, text) { + let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS + if (currentRetryGetTextFile > MAX_RETRY - 2) { + retryTimeToUse = SLOW_RETRY_TIME_IN_MILISECONDS } - callBackFunction(customResponse) - return + if (err) { + + if (err.code === 'ENOENT') { // since files are deleted before being replaced, it can happen that it does not exist and after a retry it does. + if (noRetry === true) { + logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> File does not exist. Not Retrying. ') + let customResponse = { + result: global.CUSTOM_FAIL_RESPONSE.result, + message: 'File does not exist.' + } + callBackFunction(customResponse) + return + } else { + fileDoesNotExist = true + logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> File does not exist. Retrying. ') + setTimeout(retry, retryTimeToUse) + return + } + } + + logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> err = ' + err.stack) + logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> err = ' + err.stack) + setTimeout(retry, retryTimeToUse) + return + } + + if (text.toString() === "") { + logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Read and Empty File -> filePath = ' + filePath) + setTimeout(retry, retryTimeToUse) + return + } + + callBackFunction(global.DEFAULT_OK_RESPONSE, text.toString()) + } + + } 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) + retry() + } + + function retry() { + //console.log(new Date(), ' Retry #: ' + currentRetryGetTextFile, fileLocation ) + if (currentRetryGetTextFile < MAX_RETRY) { + currentRetryGetTextFile++ + logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> retry -> Will try to read the file again -> Retry #: ' + currentRetryGetTextFile) + recursiveGetTextFile(filePath, callBackFunction) } else { - logger.write(MODULE_NAME, '[ERROR] FileStorage -> getTextFile -> retry -> Max retries reached reading a file. Giving up.') - logger.write(MODULE_NAME, '[ERROR] FileStorage -> getTextFile -> retry -> file = ' + fileLocation) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - return + currentRetryGetTextFile = 0 + + if (fileDoesNotExist === true) { + logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> retry -> Max retries reached reading a file. File Not Found.') + let customResponse = { + result: global.CUSTOM_FAIL_RESPONSE.result, + message: 'File does not exist.' + } + callBackFunction(customResponse) + return + } else { + logger.write(MODULE_NAME, '[ERROR] FileStorage -> getTextFile -> retry -> Max retries reached reading a file. Giving up.') + logger.write(MODULE_NAME, '[ERROR] FileStorage -> getTextFile -> retry -> file = ' + fileLocation) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + return + } } } } @@ -124,144 +128,161 @@ exports.newFileStorage = function newFileStorage(logger) { function createTextFile(filePath, fileContent, callBackFunction) { - logger.write(MODULE_NAME, '[INFO] FileStorage -> createTextFile -> Entering Function.') + let currentRetryWriteTextFile = 0 - /* Choose path for either logs or data */ - let fileLocation - if (filePath.indexOf("/Logs/") > 0) { - fileLocation = process.env.LOG_PATH + '/' + filePath - } else { - fileLocation = process.env.STORAGE_PATH + '/' + filePath - } + recursiveCreateTextFile(filePath, fileContent, callBackFunction) - try { + function recursiveCreateTextFile(filePath, fileContent, callBackFunction) { - logger.write(MODULE_NAME, '[INFO] FileStorage -> createTextFile -> fileLocation: ' + fileLocation) + logger.write(MODULE_NAME, '[INFO] FileStorage -> createTextFile -> Entering Function.') - /* If necesary a folder or folders are created before writing the file to disk. */ - let directoryPath = fileLocation.substring(0, fileLocation.lastIndexOf('/') + 1); - mkDirByPathSync(directoryPath) + /* Choose path for either logs or data */ + let fileLocation + if (filePath.indexOf("/Logs/") > 0) { + fileLocation = process.env.LOG_PATH + '/' + filePath + } else { + fileLocation = process.env.STORAGE_PATH + '/' + filePath + } - /* - Here we write the file with a temporary name so as to avoid dirty read from other processes. - Then we delete the original file, if exists, and finally we rename the temporary into the original name. - */ - const fs = require('fs') - fs.writeFile(fileLocation + '.tmp', fileContent, onFileWritenn) + try { - function onFileWritenn(err) { - let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS - if (currentRetryWriteTextFile > MAX_RETRY - 2) { - retryTimeToUse = SLOW_RETRY_TIME_IN_MILISECONDS - } - if (err) { - logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> Error writing file -> file = ' + fileLocation) - logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> Error writing file -> err = ' + err.stack) - setTimeout(retry, retryTimeToUse) - } else { + logger.write(MODULE_NAME, '[INFO] FileStorage -> createTextFile -> fileLocation: ' + fileLocation) - const fs = require('fs') - fs.unlink(fileLocation, onUnlinked) + /* If necesary a folder or folders are created before writing the file to disk. */ + let directoryPath = fileLocation.substring(0, fileLocation.lastIndexOf('/') + 1); + mkDirByPathSync(directoryPath) - function onUnlinked(err) { - let code = '' - if (err) { - code = err.code - } - if (code !== '' && code !== 'ENOENT') { - logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error renaming file -> file = ' + fileLocation) - logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error renaming file -> err = ' + err.stack) - setTimeout(retry, retryTimeToUse) - } else { + /* + Here we write the file with a temporary name so as to avoid dirty read from other processes. + Then we delete the original file, if exists, and finally we rename the temporary into the original name. + */ + const fs = require('fs') + fs.writeFile(fileLocation + '.tmp', fileContent, onFileWritenn) - const fs = require('fs') - fs.rename(fileLocation + '.tmp', fileLocation, onRenamed) + function onFileWritenn(err) { + let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS + if (currentRetryWriteTextFile > MAX_RETRY - 2) { + retryTimeToUse = SLOW_RETRY_TIME_IN_MILISECONDS + } + if (err) { + logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> Error writing file -> file = ' + fileLocation) + logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> Error writing file -> err = ' + err.stack) + setTimeout(retry, retryTimeToUse) + } else { - function onRenamed(err) { - if (err) { - logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onRenamed -> Error renaming file -> file = ' + fileLocation + '.tmp') - logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onRenamed -> Error renaming file -> err = ' + err.stack) - setTimeout(retry, retryTimeToUse) - } else { + const fs = require('fs') + fs.unlink(fileLocation, onUnlinked) - callBackFunction(global.DEFAULT_OK_RESPONSE) + function onUnlinked(err) { + let code = '' + if (err) { + code = err.code + } + if (code !== '' && code !== 'ENOENT') { + logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error renaming file -> file = ' + fileLocation) + logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error renaming file -> err = ' + err.stack) + setTimeout(retry, retryTimeToUse) + } else { + const fs = require('fs') + fs.rename(fileLocation + '.tmp', fileLocation, onRenamed) + + function onRenamed(err) { + if (err) { + logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onRenamed -> Error renaming file -> file = ' + fileLocation + '.tmp') + logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onRenamed -> Error renaming file -> err = ' + err.stack) + setTimeout(retry, retryTimeToUse) + } else { + + callBackFunction(global.DEFAULT_OK_RESPONSE) + + } } } } } } + + } catch (err) { + logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> Error writing file -> file = ' + fileLocation) + logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> Error writing file -> err = ' + err.stack) + retry() } - } catch (err) { - logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> Error writing file -> file = ' + fileLocation) - logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> Error writing file -> err = ' + err.stack) - retry() - } - - function retry() { - if (currentRetryWriteTextFile < MAX_RETRY) { - currentRetryWriteTextFile++ - logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> retry -> Will try to write the file again -> Retry #: ' + currentRetryWriteTextFile) - createTextFile(filePath, fileContent, callBackFunction) - } else { - currentRetryWriteTextFile = 0 - logger.write(MODULE_NAME, '[ERROR] FileStorage -> createTextFile -> retry -> Max retries reached writting a file. Giving up.') - logger.write(MODULE_NAME, '[ERROR] FileStorage -> createTextFile -> retry -> file = ' + fileLocation) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) + function retry() { + if (currentRetryWriteTextFile < MAX_RETRY) { + currentRetryWriteTextFile++ + logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> retry -> Will try to write the file again -> Retry #: ' + currentRetryWriteTextFile) + recursiveCreateTextFile(filePath, fileContent, callBackFunction) + } else { + currentRetryWriteTextFile = 0 + logger.write(MODULE_NAME, '[ERROR] FileStorage -> createTextFile -> retry -> Max retries reached writting a file. Giving up.') + logger.write(MODULE_NAME, '[ERROR] FileStorage -> createTextFile -> retry -> file = ' + fileLocation) + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } } } } function deleteTextFile(filePath, callBackFunction) { - logger.write(MODULE_NAME, '[INFO] FileStorage -> deleteTextFile -> Entering Function.') + let currentRetryDeleteTextFile = 0 - /* Choose path for either logs or data */ - let fileLocation - if (filePath.indexOf("/Logs/") > 0) { - fileLocation = process.env.LOG_PATH + '/' + filePath - } else { - fileLocation = process.env.STORAGE_PATH + '/' + filePath - } + recursiveDeleteTextFile(filePath, callBackFunction) - try { + function recursiveDeleteTextFile(filePath, callBackFunction) { + logger.write(MODULE_NAME, '[INFO] FileStorage -> deleteTextFile -> Entering Function.') - logger.write(MODULE_NAME, '[INFO] FileStorage -> deleteTextFile -> fileLocation: ' + fileLocation) + /* Choose path for either logs or data */ + let fileLocation + if (filePath.indexOf("/Logs/") > 0) { + fileLocation = process.env.LOG_PATH + '/' + filePath + } else { + fileLocation = process.env.STORAGE_PATH + '/' + filePath + } - const fs = require('fs') - fs.unlink(fileLocation, onUnlinked) + try { - function onUnlinked(err) { - if (err) { - if (callBackFunction !== undefined) { - callBackFunction(global.DEFAULT_FAIL_RESPONSE) + logger.write(MODULE_NAME, '[INFO] FileStorage -> deleteTextFile -> fileLocation: ' + fileLocation) + + const fs = require('fs') + fs.unlink(fileLocation, onUnlinked) + + function onUnlinked(err) { + let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS + if (currentRetryDeleteTextFile > MAX_RETRY - 2) { + retryTimeToUse = SLOW_RETRY_TIME_IN_MILISECONDS } + if (err) { + if (callBackFunction !== undefined) { + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } else { + setTimeout(retry, retryTimeToUse) + } + } + } catch (err) { + logger.write(MODULE_NAME, '[WARN] FileStorage -> deleteTextFile -> Error writing file -> file = ' + fileLocation) + logger.write(MODULE_NAME, '[WARN] FileStorage -> deleteTextFile -> Error writing file -> err = ' + err.stack) + if (callBackFunction !== undefined) { + callBackFunction(global.DEFAULT_FAIL_RESPONSE) + } + } + + function retry() { + if (currentRetryDeleteTextFile < MAX_RETRY) { + currentRetryDeleteTextFile++ + logger.write(MODULE_NAME, '[WARN] FileStorage -> deleteTextFile -> retry -> Will try to delete the file again -> Retry #: ' + currentRetryDeleteTextFile) + recursiveDeleteTextFile(filePath, callBackFunction) } else { + currentRetryDeleteTextFile = 0 + logger.write(MODULE_NAME, '[ERROR] FileStorage -> deleteTextFile -> retry -> Max retries reached deleting a file. Giving up.') + logger.write(MODULE_NAME, '[ERROR] FileStorage -> deleteTextFile -> retry -> file = ' + fileLocation) if (callBackFunction !== undefined) { callBackFunction(global.DEFAULT_OK_RESPONSE) } } } - } catch (err) { - logger.write(MODULE_NAME, '[WARN] FileStorage -> deleteTextFile -> Error writing file -> file = ' + fileLocation) - logger.write(MODULE_NAME, '[WARN] FileStorage -> deleteTextFile -> Error writing file -> err = ' + err.stack) - if (callBackFunction !== undefined) { - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - - function retry() { - if (currentRetryDeleteTextFile < MAX_RETRY) { - currentRetryDeleteTextFile++ - logger.write(MODULE_NAME, '[WARN] FileStorage -> deleteTextFile -> retry -> Will try to delete the file again -> Retry #: ' + currentRetryDeleteTextFile) - createTextFile(filePath, fileContent, callBackFunction) - } else { - currentRetryDeleteTextFile = 0 - logger.write(MODULE_NAME, '[ERROR] FileStorage -> deleteTextFile -> retry -> Max retries reached deleting a file. Giving up.') - logger.write(MODULE_NAME, '[ERROR] FileStorage -> deleteTextFile -> retry -> file = ' + fileLocation) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } } } diff --git a/TradingBot.js b/TradingBot.js index 7dacf7836..833b16693 100644 --- a/TradingBot.js +++ b/TradingBot.js @@ -356,7 +356,8 @@ record.status + "," + record.number + "," + record.beginRate + "," + - record.endRate + "]"; + record.endRate + "," + + '"' + record.triggerOnSituation + '"' + "]"; if (separator === "") { separator = ","; } @@ -428,7 +429,8 @@ record.lastTradeROI + "," + record.beginRate + "," + record.endRate + "," + - record.exitType + "]"; + record.exitType + "," + + '"' + record.takePositionSituation + '"' + "]"; if (separator === "") { separator = ","; } @@ -816,7 +818,8 @@ record.status + "," + record.number + "," + record.beginRate + "," + - record.endRate + "]"; + record.endRate + "," + + '"' + record.triggerOnSituation + '"' + "]"; if (separator === "") { separator = ","; } @@ -894,7 +897,8 @@ record.lastTradeROI + "," + record.beginRate + "," + record.endRate + "," + - record.exitType + "]"; + record.exitType + "," + + '"' + record.takePositionSituation + '"' + "]"; if (separator === "") { separator = ","; } diff --git a/TradingSimulation.js b/TradingSimulation.js index 59413023f..9340b2126 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -141,7 +141,8 @@ status: 0, number: 0, beginRate: 0, - endRate: 0 + endRate: 0, + triggerOnSituation: '' } let currentTrade = { @@ -151,7 +152,8 @@ profit: 0, exitType: 0, beginRate: 0, - endRate: 0 + endRate: 0, + takePositionSituation: '' } let balanceBaseAsset = bot.VALUES_TO_USE.initialBalanceA; @@ -211,7 +213,8 @@ status: 0, number: 0, beginRate: 0, - endRate: 0 + endRate: 0, + triggerOnSituation: '' } yesterday.currentTrade = { @@ -221,7 +224,8 @@ profit: 0, exitType: 0, beginRate: 0, - endRate: 0 + endRate: 0, + takePositionSituation: '' } yesterday.balanceBaseAsset = balanceBaseAsset; @@ -279,7 +283,8 @@ status: 0, number: 0, beginRate: 0, - endRate: 0 + endRate: 0, + triggerOnSituation: '' } interExecutionMemory.currentTrade = { @@ -289,7 +294,8 @@ profit: 0, exitType: 0, beginRate: 0, - endRate: 0 + endRate: 0, + takePositionSituation: '' } interExecutionMemory.balanceBaseAsset = balanceBaseAsset; @@ -349,7 +355,8 @@ status: interExecutionMemory.currentStrategy.status, number: interExecutionMemory.currentStrategy.number, beginRate: interExecutionMemory.currentStrategy.beginRate, - endRate: interExecutionMemory.currentStrategy.endRate + endRate: interExecutionMemory.currentStrategy.endRate, + triggerOnSituation: interExecutionMemory.currentStrategy.triggerOnSituation } currentTrade = { @@ -359,7 +366,8 @@ profit: interExecutionMemory.currentTrade.profit, exitType: interExecutionMemory.currentTrade.exitType, beginRate: interExecutionMemory.currentTrade.beginRate, - endRate: interExecutionMemory.currentTrade.endRate + endRate: interExecutionMemory.currentTrade.endRate, + takePositionSituation: interExecutionMemory.currentTrade.takePositionSituation } if (currentDay) { @@ -422,7 +430,8 @@ status: currentStrategy.status, number: currentStrategy.number, beginRate: currentStrategy.beginRate, - endRate: currentStrategy.endRate + endRate: currentStrategy.endRate, + triggerOnSituation: currentStrategy.triggerOnSituation } yesterday.currentTrade = { @@ -432,7 +441,8 @@ profit: currentTrade.profit, exitType: currentTrade.exitType, beginRate: currentTrade.beginRate, - endRate: currentTrade.endRate + endRate: currentTrade.endRate, + takePositionSituation: currentTrade.takePositionSituation } yesterday.lastTradeProfitLoss = lastTradeProfitLoss; @@ -1159,6 +1169,7 @@ currentStrategy.begin = candle.begin; currentStrategy.beginRate = candle.min; currentStrategy.endRate = candle.min; // In case the strategy does not get exited + currentStrategy.triggerOnSituation = situation.name if (processingDailyFiles) { if (positionedAtYesterday) { @@ -1167,6 +1178,7 @@ yesterday.currentStrategy.begin = currentStrategy.begin; yesterday.currentStrategy.beginRate = currentStrategy.beginRate; yesterday.currentStrategy.endRate = currentStrategy.endRate; + yesterday.currentStrategy.triggerOnSituation = currentStrategy.triggerOnSituation; } } @@ -1315,6 +1327,7 @@ } takePositionNow = true + currentTrade.takePositionSituation = situation.name checkAnnouncements(triggerStage.takePosition) @@ -2578,7 +2591,8 @@ status: 0, number: 0, beginRate: 0, - endRate: 0 + endRate: 0, + triggerOnSituation: '' } if (processingDailyFiles) { @@ -2589,7 +2603,8 @@ status: 0, number: 0, beginRate: 0, - endRate: 0 + endRate: 0, + triggerOnSituation: '' } } } @@ -2626,7 +2641,8 @@ lastTradeROI: 0, exitType: 0, beginRate: 0, - endRate: 0 + endRate: 0, + takePositionSituation: '' } if (processingDailyFiles) { @@ -2638,7 +2654,8 @@ lastTradeROI: 0, exitType: 0, beginRate: 0, - endRate: 0 + endRate: 0, + takePositionSituation: '' } } } @@ -2791,7 +2808,8 @@ status: yesterday.currentStrategy.status, number: yesterday.currentStrategy.number, beginRate: yesterday.currentStrategy.beginRate, - endRate: yesterday.currentStrategy.endRate + endRate: yesterday.currentStrategy.endRate, + triggerOnSituation: yesterday.curre.triggerOnSituation } interExecutionMemory.currentTrade = { @@ -2801,7 +2819,8 @@ profit: yesterday.currentTrade.profit, exitType: yesterday.currentTrade.exitType, beginRate: yesterday.currentTrade.beginRate, - endRate: yesterday.currentTrade.endRate + endRate: yesterday.currentTrade.endRate, + takePositionSituation: yesterday.currentTrade.takePositionSituation } interExecutionMemory.balanceBaseAsset = yesterday.balanceBaseAsset; From 74b07e0191ab41c807cf20f6853d076e8584ef72 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 26 Mar 2020 15:07:42 +0100 Subject: [PATCH 02/13] Telegram fixed --- Session.js | 2 +- TradingSimulation.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Session.js b/Session.js index 872258aad..87756700e 100644 --- a/Session.js +++ b/Session.js @@ -512,7 +512,7 @@ for (let i = 0; i < bot.SESSION.socialBots.bots.length; i++) { let socialBot = bot.SESSION.socialBots.bots[i] try { - let code = JSON.parse(announcement.code) + let code = announcement.code if (socialBot.id === announcement.referenceParent.id) { if (socialBot.type === "Telegram Bot") { if (announcement.formulaValue !== undefined) { diff --git a/TradingSimulation.js b/TradingSimulation.js index 9340b2126..f1c60b942 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -2746,7 +2746,9 @@ } announcement.formulaValue = formulaValue - bot.SESSION.socialBots.announce(announcement) + if (bot.SESSION.socialBots !== undefined) { + bot.SESSION.socialBots.announce(announcement) + } } } } From cde6382c8b1c064c0e430e247e1187967b3b29f9 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 28 Mar 2020 12:47:19 +0100 Subject: [PATCH 03/13] cleaning --- TradingSimulation.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index f1c60b942..3bea5733c 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -14,21 +14,9 @@ let utilities = UTILITIES.newCloudUtilities(bot, logger); - let percentageBandwidthAt = {} - let bollingerBandsAt = {} - let bollingerChannelsAt = {} - let bollingerSubChannelsAt = {} - let candlesAt = {} - - return thisObject; function finalize() { - percentageBandwidthAt = undefined - bollingerBandsAt = undefined - bollingerChannelsAt = undefined - bollingerSubChannelsAt = undefined - candlesAt = undefined thisObject = undefined } From 8ccf62c4dcf68ccd13ac17de6a2bc9571f5dd3d5 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 30 Mar 2020 10:05:29 +0200 Subject: [PATCH 04/13] More resilience when a file does not exist --- MultiPeriod.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/MultiPeriod.js b/MultiPeriod.js index d9047fb3f..c71bf9c00 100644 --- a/MultiPeriod.js +++ b/MultiPeriod.js @@ -332,9 +332,13 @@ if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimeFramesMarketFiles -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> text = " + text); } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFramesMarketFiles -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = " + err.message); - callBackFunction(err); + if (err.message === 'File does not exist.') { + logger.write(MODULE_NAME, "[ERROR] The file " + filePath + '/' + fileName + ' does not exist and it is required to continue. This process will retry to read it in a while. In the meantime make yourself sure that the process that generates it has ran properly.'); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + } else { + logger.write(MODULE_NAME, "[ERROR] start -> processTimeFramesMarketFiles -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = " + err.message); + callBackFunction(err); + } return; } @@ -660,7 +664,7 @@ 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 -> processTimeFramesDailyFiles -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] The file " + filePath + '/' + fileName + ' does not exist and it is required to continue. This process will retry to read it in a while. In the meantime make yourself sure that the process that generates it has ran properly.'); callBackFunction(global.DEFAULT_RETRY_RESPONSE); return; } From aee37b4ea298a738e125f95146b2ccb35f6b3152 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 30 Mar 2020 20:04:33 +0200 Subject: [PATCH 05/13] Update TradingSimulation.js --- TradingSimulation.js | 1 + 1 file changed, 1 insertion(+) diff --git a/TradingSimulation.js b/TradingSimulation.js index 3bea5733c..4182e20f5 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -1502,6 +1502,7 @@ if (parentNode !== undefined) { let phase = parentNode.takeProfit.phases[p]; + if (phase === undefined) {return} // trying to jump to a phase that does not exists. let nextPhaseEvent = phase.nextPhaseEvent; if (nextPhaseEvent !== undefined) { From e704c578d4a4fc705b59c64920a3a8fbf8b4fa4e Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 30 Mar 2020 20:48:27 +0200 Subject: [PATCH 06/13] better logging --- MultiPeriod.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/MultiPeriod.js b/MultiPeriod.js index c71bf9c00..09d54057a 100644 --- a/MultiPeriod.js +++ b/MultiPeriod.js @@ -725,12 +725,7 @@ 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 -> processTimeFramesDailyFiles -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> Fail Because -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFramesDailyFiles -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFramesDailyFiles -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> fileName = " + fileName); - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFramesDailyFiles -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> You are trying to use data that does not exist. "); - logger.write(MODULE_NAME, "[ERROR] start -> processTimeFramesDailyFiles -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> Check that your Datasets building processes are running well. "); - + logger.write(MODULE_NAME, "[ERROR] The file " + filePath + '/' + fileName + ' does not exist and it is required to continue. This process will retry to read it in a while. In the meantime make yourself sure that the process that generates it has ran properly.'); callBackFunction(global.DEFAULT_RETRY_RESPONSE); return; } From ef31e8c741b82087d78dbaa45331c07448ff67b8 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 31 Mar 2020 08:18:34 +0200 Subject: [PATCH 07/13] Update TradingSimulation.js --- TradingSimulation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index 4182e20f5..55757f41f 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -2800,7 +2800,7 @@ number: yesterday.currentStrategy.number, beginRate: yesterday.currentStrategy.beginRate, endRate: yesterday.currentStrategy.endRate, - triggerOnSituation: yesterday.curre.triggerOnSituation + triggerOnSituation: yesterday.currentStrategy.triggerOnSituation } interExecutionMemory.currentTrade = { From 29aed1fcd3bcbae432f0decea9d752e7fb3fb49b Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 31 Mar 2020 10:19:19 +0200 Subject: [PATCH 08/13] Update TradingSimulation.js --- TradingSimulation.js | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index 55757f41f..9e92d6502 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -568,9 +568,19 @@ 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) } - console.log("Trading-Engine -> " + MODULE_NAME + " -> runSimulation -> loop -> Simulation " + bot.sessionKey + " Loop # " + currentCandleIndex + " @ " + processingDate) - bot.sessionHeartBeat(processingDate) // tell the world we are alive and doing well + /* 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 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() @@ -2749,8 +2759,15 @@ /* 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."); } - console.log("[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing.") + 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 } From e3624984bac07d8da4abd4e0cfa41464c96f4aae Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 1 Apr 2020 13:59:51 +0200 Subject: [PATCH 09/13] base asset available --- Session.js | 14 ++++++++------ TradingSimulation.js | 46 ++++++++++++++++++++++++-------------------- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/Session.js b/Session.js index 87756700e..f671d62aa 100644 --- a/Session.js +++ b/Session.js @@ -513,12 +513,14 @@ let socialBot = bot.SESSION.socialBots.bots[i] try { let code = announcement.code - if (socialBot.id === announcement.referenceParent.id) { - 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 -> setUpSocialBots -> announce -> Telegram API error -> err = " + err)) - } else { - socialBot.botInstance.telegramAPI.sendMessage(socialBot.botInstance.chatId, code.text).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> setUpSocialBots -> announce -> Telegram API error -> err = " + err)) + if (announcement.referenceParent !== undefined) { + if (socialBot.id === announcement.referenceParent.id) { + 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 -> setUpSocialBots -> announce -> Telegram API error -> err = " + err)) + } else { + socialBot.botInstance.telegramAPI.sendMessage(socialBot.botInstance.chatId, code.text).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> setUpSocialBots -> announce -> Telegram API error -> err = " + err)) + } } } } diff --git a/TradingSimulation.js b/TradingSimulation.js index 9e92d6502..9de9a0e51 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -173,6 +173,10 @@ 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 + let yesterday = {}; /* Initialization */ @@ -714,7 +718,7 @@ if (openStage !== undefined) { /* Default Values*/ - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + if (baseAsset === bot.market.baseAsset) { positionSize = balanceBaseAsset; positionRate = candle.close; } else { @@ -737,13 +741,13 @@ initialDefinition.positionSize.formula.error = err.message } if (isNaN(positionSize)) { - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + if (baseAsset === bot.market.baseAsset) { positionSize = balanceBaseAsset; } else { positionSize = balanceQuotedAsset; } } else { - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + if (baseAsset === bot.market.baseAsset) { if (positionSize > balanceBaseAsset) { positionSize = balanceBaseAsset } } else { if (positionSize > balanceQuotedAsset) { positionSize = balanceQuotedAsset } @@ -764,7 +768,7 @@ initialDefinition.positionRate.formula.error = err.message } if (isNaN(positionRate)) { - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + if (baseAsset === bot.market.baseAsset) { positionRate = candle.close; } else { positionRate = candle.close; @@ -1101,7 +1105,7 @@ let maximumBalance let balance - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + if (baseAsset === bot.market.baseAsset) { balance = balanceBaseAsset minimumBalance = bot.VALUES_TO_USE.minimumBalanceA maximumBalance = bot.VALUES_TO_USE.maximumBalanceA @@ -1695,7 +1699,7 @@ /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - if ((bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset && candle.max >= stopLoss) || (bot.VALUES_TO_USE.baseAsset !== bot.market.baseAsset && candle.min <= stopLoss)) { + if ((baseAsset === bot.market.baseAsset && candle.max >= stopLoss) || (baseAsset !== bot.market.baseAsset && candle.min <= stopLoss)) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Stop Loss was hit."); } /* @@ -1705,7 +1709,7 @@ If we take the stop loss value at those situation would be a huge distortion of facts. */ - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + if (baseAsset === bot.market.baseAsset) { if (stopLoss < candle.min) { stopLoss = candle.min if (processingDailyFiles) { @@ -1730,7 +1734,7 @@ /* Apply the Slippage */ let slippageAmount = slippedStopLoss * bot.VALUES_TO_USE.slippage.stopLoss / 100 - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + if (baseAsset === bot.market.baseAsset) { slippedStopLoss = slippedStopLoss + slippageAmount } else { slippedStopLoss = slippedStopLoss - slippageAmount @@ -1765,7 +1769,7 @@ /* Take Profit condition: Here we verify if the Take Profit was hit or not. */ - if ((bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset && candle.min <= takeProfit) || (bot.VALUES_TO_USE.baseAsset !== bot.market.baseAsset && candle.max >= takeProfit)) { + if ((baseAsset === bot.market.baseAsset && candle.min <= takeProfit) || (baseAsset !== bot.market.baseAsset && candle.max >= takeProfit)) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Take Profit was hit."); } /* @@ -1775,7 +1779,7 @@ If we take the stop loss value at those situation would be a huge distortion of facts. */ - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + if (baseAsset === bot.market.baseAsset) { if (takeProfit > candle.max) { takeProfit = candle.max if (processingDailyFiles) { @@ -1799,7 +1803,7 @@ /* Apply the Slippage */ let slippageAmount = slippedTakeProfit * bot.VALUES_TO_USE.slippage.takeProfit / 100 - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + if (baseAsset === bot.market.baseAsset) { slippedTakeProfit = slippedTakeProfit + slippageAmount } else { slippedTakeProfit = slippedTakeProfit - slippageAmount @@ -1860,7 +1864,7 @@ /* We take what was calculated at the formula and apply the slippage. */ let slippageAmount = tradePositionRate * bot.VALUES_TO_USE.slippage.positionRate / 100 - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + if (baseAsset === bot.market.baseAsset) { tradePositionRate = tradePositionRate - slippageAmount } else { tradePositionRate = tradePositionRate + slippageAmount @@ -1988,7 +1992,7 @@ let orderSide - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + 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. @@ -2082,7 +2086,7 @@ let feePaid = 0 - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + if (baseAsset === bot.market.baseAsset) { feePaid = tradePositionSize * tradePositionRate * bot.VALUES_TO_USE.feeStructure.taker / 100 @@ -2194,7 +2198,7 @@ let amountB let orderSide - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + if (baseAsset === bot.market.baseAsset) { orderSide = "buy" orderPrice = ticker.last + 100; // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. @@ -2276,7 +2280,7 @@ let feePaid = 0 - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + if (baseAsset === bot.market.baseAsset) { strategy.positionSize = balanceQuotedAsset / closeRate; strategy.positionRate = closeRate; @@ -2302,7 +2306,7 @@ } } - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + if (baseAsset === bot.market.baseAsset) { lastTradeProfitLoss = balanceBaseAsset - previousBalanceBaseAsset; lastTradeROI = lastTradeProfitLoss * 100 / tradePositionSize; if (isNaN(lastTradeROI)) { lastTradeROI = 0; } @@ -2349,7 +2353,7 @@ } } - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + if (baseAsset === bot.market.baseAsset) { ROI = (bot.VALUES_TO_USE.initialBalanceA + profit) / bot.VALUES_TO_USE.initialBalanceA - 1; hitRatio = hits / roundtrips; anualizedRateOfReturn = ROI / days * 365; @@ -2507,8 +2511,8 @@ balanceQuotedAsset = Number.MAX_SAFE_INTEGER } - let quotedBaseAsset = '"' + bot.VALUES_TO_USE.baseAsset + '"' - let quotedQuotedAsset = '"' + bot.VALUES_TO_USE.quotedAsset + '"' + let quotedBaseAsset = '"' + baseAsset + '"' + let quotedQuotedAsset = '"' + quotedAsset + '"' simulationRecord = { begin: candle.begin, @@ -2619,7 +2623,7 @@ currentTrade.endRate = candle.close /* Here we will calculate the ongoing ROI */ - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { + if (baseAsset === bot.market.baseAsset) { currentTrade.lastTradeROI = (tradePositionRate - candle.close) / tradePositionRate * 100 } else { currentTrade.lastTradeROI = (candle.close - tradePositionRate) / tradePositionRate * 100 From f7f47ffac9f5404bec7127ed330dd6d30177541c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 1 Apr 2020 14:25:07 +0200 Subject: [PATCH 10/13] Update TradingSimulation.js --- TradingSimulation.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/TradingSimulation.js b/TradingSimulation.js index 9de9a0e51..6ec01a595 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -2695,13 +2695,10 @@ /* The Value Variation is what tells us how much the value already announced must change in order to annouce it again. */ let valueVariation - try { - let code = JSON.parse(announcement.code) - valueVariation = code.valueVariation - } catch (err) { - announcement.error = err.message - } - + + 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 From b2a365944684a6908b2a74ac476563d86d2ba942 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 1 Apr 2020 17:17:03 +0200 Subject: [PATCH 11/13] Announcements Improved --- Session.js | 16 +++++++------- TradingSimulation.js | 50 ++++++++++++++++++++++++++++++-------------- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/Session.js b/Session.js index f671d62aa..7d0035356 100644 --- a/Session.js +++ b/Session.js @@ -513,17 +513,15 @@ let socialBot = bot.SESSION.socialBots.bots[i] try { let code = announcement.code - if (announcement.referenceParent !== undefined) { - if (socialBot.id === announcement.referenceParent.id) { - 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 -> setUpSocialBots -> announce -> Telegram API error -> err = " + err)) - } else { - socialBot.botInstance.telegramAPI.sendMessage(socialBot.botInstance.chatId, code.text).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> setUpSocialBots -> announce -> Telegram API error -> err = " + err)) - } - } + + 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 -> setUpSocialBots -> announce -> Telegram API error -> err = " + err)) + } else { + socialBot.botInstance.telegramAPI.sendMessage(socialBot.botInstance.chatId, code.text).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> setUpSocialBots -> announce -> Telegram API error -> err = " + err)) } } + } catch (err) { parentLogger.write(MODULE_NAME, "[WARN] initialize -> setUpSocialBots -> announce -> err = " + err.stack); } diff --git a/TradingSimulation.js b/TradingSimulation.js index 6ec01a595..2356e2d0b 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -1167,6 +1167,8 @@ if (passed) { strategyStage = 'Trigger Stage'; + checkAnnouncements(triggerStage) + currentStrategyIndex = j; currentStrategy.begin = candle.begin; currentStrategy.beginRate = candle.min; @@ -1313,6 +1315,8 @@ type = '"Take Position"'; strategyStage = 'Open Stage'; + checkAnnouncements(strategy.openStage) + stopLossStage = 'Open Stage'; takeProfitStage = 'Open Stage'; stopLossPhase = 0; @@ -1330,7 +1334,7 @@ takePositionNow = true currentTrade.takePositionSituation = situation.name - + checkAnnouncements(triggerStage.takePosition) if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Conditions at the Take Position Event were met."); } @@ -1411,7 +1415,10 @@ stopLossPhase++; stopLossStage = 'Manage Stage' - if (takeProfitPhase > 0) { strategyStage = 'Manage Stage' } + if (takeProfitPhase > 0) { + strategyStage = 'Manage Stage' + checkAnnouncements(manageStage, 'Take Profit') + } if (processingDailyFiles) { if (positionedAtYesterday) { @@ -1543,7 +1550,10 @@ takeProfitPhase++; takeProfitStage = 'Manage Stage' - if (stopLossPhase > 0) { strategyStage = 'Manage Stage' } + if (stopLossPhase > 0) { + strategyStage = 'Manage Stage' + checkAnnouncements(manageStage, 'Stop') + } if (processingDailyFiles) { if (positionedAtYesterday) { @@ -1745,6 +1755,8 @@ marketRate = closeRate; type = '"Close@StopLoss"'; strategyStage = 'Close Stage'; + checkAnnouncements(strategy.closeStage, 'Stop') + stopLossStage = 'No Stage'; takeProfitStage = 'No Stage'; currentTrade.end = candle.end; @@ -1814,6 +1826,8 @@ marketRate = closeRate; type = '"Close@TakeProfit"'; strategyStage = 'Close Stage'; + checkAnnouncements(strategy.closeStage, 'Take Profit') + stopLossStage = 'No Stage'; takeProfitStage = 'No Stage'; @@ -2669,7 +2683,7 @@ function checkAnnouncements(node, value) { /* - Value is an optional parameter that represents the value that the announcement is monitoring for change. + 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. */ @@ -2693,18 +2707,20 @@ if (periods > lastPeriodAnnounced) { - /* 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 - - 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 + 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 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) { + /* There is not enough variation to announce this again. */ + return + } } } @@ -2712,6 +2728,7 @@ 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) /* Next, we will remmeber this announcement was already done, so that it is not announced again in further processing of the same day. */ @@ -2739,6 +2756,7 @@ let formulaValue if (announcement.formula !== undefined) { try { + let value = announcement.value formulaValue = eval(announcement.formula.code); } catch (err) { announcement.formula.error = err.message From 42bb8281f179f1121ba61bb4385fff2efc612a34 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 2 Apr 2020 11:53:19 +0200 Subject: [PATCH 12/13] no more parameters in trading system --- Session.js | 126 ----------------------------------------------------- 1 file changed, 126 deletions(-) diff --git a/Session.js b/Session.js index 7d0035356..8f341ca3c 100644 --- a/Session.js +++ b/Session.js @@ -238,132 +238,6 @@ if (tradingSystem !== undefined) { - /* Applying Trading System Level Parameters */ - if (tradingSystem.parameters !== undefined) { - - /* Base Asset and Initial Balances. */ - { - if (tradingSystem.parameters.baseAsset !== undefined) { - if (tradingSystem.parameters.baseAsset.referenceParent !== undefined) { - if (tradingSystem.parameters.baseAsset.referenceParent.referenceParent !== undefined) { - - let code = tradingSystem.parameters.baseAsset.referenceParent.referenceParent.code - - if (code.codeName !== undefined) { - bot.VALUES_TO_USE.baseAsset = code.codeName; - } - - code = tradingSystem.parameters.baseAsset.code - - if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) { - if (code.initialBalance !== undefined) { - bot.VALUES_TO_USE.initialBalanceA = code.initialBalance; - bot.VALUES_TO_USE.initialBalanceB = 0 - } - if (code.minimumBalance !== undefined) { - bot.VALUES_TO_USE.minimumBalanceA = code.minimumBalance; - bot.VALUES_TO_USE.minimumBalanceB = 0 - } - if (code.maximumBalance !== undefined) { - bot.VALUES_TO_USE.maximumBalanceA = code.maximumBalance; - bot.VALUES_TO_USE.maximumBalanceB = 0 - } - } else { - if (code.initialBalance !== undefined) { - bot.VALUES_TO_USE.initialBalanceB = code.initialBalance; - bot.VALUES_TO_USE.initialBalanceA = 0 - } - if (code.minimumBalance !== undefined) { - bot.VALUES_TO_USE.minimumBalanceB = code.minimumBalance; - bot.VALUES_TO_USE.minimumBalanceA = 0 - } - if (code.maximumBalance !== undefined) { - bot.VALUES_TO_USE.maximumBalanceB = code.maximumBalance; - bot.VALUES_TO_USE.maximumBalanceA = 0 - } - } - } - } - } - } - - /* Quoted Asset */ - { - if (tradingSystem.parameters.quotedAsset !== undefined) { - if (tradingSystem.parameters.quotedAsset.referenceParent !== undefined) { - if (tradingSystem.parameters.quotedAsset.referenceParent.referenceParent !== undefined) { - - let code = tradingSystem.parameters.quotedAsset.referenceParent.referenceParent.code - - if (code.codeName !== undefined) { - bot.VALUES_TO_USE.quotedAsset = code.codeName; - } - } - } - } - } - - /* Time Frame */ - if (tradingSystem.parameters.timeFrame !== undefined) { - bot.VALUES_TO_USE.timeFrame = tradingSystem.parameters.timeFrame.code.value - } - - /* Slippage */ - if (tradingSystem.parameters.slippage !== undefined) { - if (tradingSystem.parameters.slippage.code !== undefined) { - - let code = tradingSystem.parameters.slippage.code - - if (code.positionRate !== undefined) { - bot.VALUES_TO_USE.slippage.positionRate = code.positionRate - } - if (code.stopLoss !== undefined) { - bot.VALUES_TO_USE.slippage.stopLoss = code.stopLoss - } - if (code.takeProfit !== undefined) { - bot.VALUES_TO_USE.slippage.takeProfit = code.takeProfit - } - } - } - - /* Fee Structure */ - if (tradingSystem.parameters.feeStructure !== undefined) { - if (tradingSystem.parameters.feeStructure.code !== undefined) { - - let code = tradingSystem.parameters.feeStructure.code - - if (code.maker !== undefined) { - bot.VALUES_TO_USE.feeStructure.maker = code.maker - } - if (code.taker !== undefined) { - bot.VALUES_TO_USE.feeStructure.taker = code.taker - } - } - } - - /* Time Range */ - if (tradingSystem.parameters.timeRange !== undefined) { - if (tradingSystem.parameters.timeRange.code !== undefined) { - - let code = tradingSystem.parameters.timeRange.code - if (code.initialDatetime !== undefined) { - if (isNaN(Date.parse(code.initialDatetime)) === true) { - parentLogger.write(MODULE_NAME, "[WARN] initialize -> runSession -> setValuesToUse -> Cannot use initialDatatime provided at Trading System Parameters because it is not a valid Date."); - } else { - bot.VALUES_TO_USE.timeRange.initialDatetime = new Date(code.initialDatetime) - } - } - if (code.finalDatetime !== undefined) { - if (isNaN(Date.parse(code.finalDatetime)) === true) { - parentLogger.write(MODULE_NAME, "[WARN] initialize -> runSession -> setValuesToUse -> Cannot use finalDatetime provided at Trading System Parameters because it is not a valid Date."); - } else { - bot.VALUES_TO_USE.timeRange.finalDatetime = new Date(code.finalDatetime) - } - } - } - } - } - /* Applying Session Level Parameters */ if (bot.SESSION !== undefined) { if (bot.SESSION.parameters !== undefined) { From 860bcfc39eee81f69ce4cbcc2536c9ec2b38eba4 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 3 Apr 2020 11:10:33 +0200 Subject: [PATCH 13/13] Bug Fixed with max balance --- Session.js | 24 +++++--- TradingSimulation.js | 137 +++++++++++++++++++++---------------------- 2 files changed, 84 insertions(+), 77 deletions(-) diff --git a/Session.js b/Session.js index 8f341ca3c..0d6685f89 100644 --- a/Session.js +++ b/Session.js @@ -187,13 +187,6 @@ /* Set all default values */ bot.VALUES_TO_USE = { - baseAsset: "BTC", - initialBalanceA: 0.001, - initialBalanceB: 0, - minimumBalanceA: 0.0005, - minimumBalanceB: 0, - maximumBalanceA: 0.002, - maximumBalanceB: 0, slippage: { positionRate: 0, stopLoss: 0, @@ -283,6 +276,23 @@ bot.VALUES_TO_USE.maximumBalanceA = 0 } } + + /* Solve when values are missing. */ + if (bot.VALUES_TO_USE.minimumBalanceA === undefined) { + bot.VALUES_TO_USE.minimumBalanceA = 0 + } + + if (bot.VALUES_TO_USE.minimumBalanceB === undefined) { + bot.VALUES_TO_USE.minimumBalanceB = 0 + } + + if (bot.VALUES_TO_USE.maximumBalanceA === undefined) { + bot.VALUES_TO_USE.maximumBalanceA = 10000000000000000 + } + + if (bot.VALUES_TO_USE.maximumBalanceB === undefined) { + bot.VALUES_TO_USE.maximumBalanceB = 10000000000000000 + } } } } diff --git a/TradingSimulation.js b/TradingSimulation.js index 2356e2d0b..471ae162d 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -1114,104 +1114,101 @@ minimumBalance = bot.VALUES_TO_USE.minimumBalanceB maximumBalance = bot.VALUES_TO_USE.maximumBalanceB } - - if (minimumBalance === undefined) { - minimumBalance = 0 + + 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 (maximumBalance === undefined) { - maximumBalance = 10000000000000000 + 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 > minimumBalance && balance < maximumBalance) { - - /* - 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. + /* + 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. + 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++) { + for (let j = 0; j < tradingSystem.strategies.length; j++) { - let strategy = tradingSystem.strategies[j]; + let strategy = tradingSystem.strategies[j]; - let triggerStage = strategy.triggerStage + let triggerStage = strategy.triggerStage - if (triggerStage !== undefined) { + if (triggerStage !== undefined) { - if (triggerStage.triggerOn !== undefined) { + if (triggerStage.triggerOn !== undefined) { - for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { + for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { - let situation = triggerStage.triggerOn.situations[k]; - let passed = true; + let situation = triggerStage.triggerOn.situations[k]; + let 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; - } - - if (value === false) { passed = false; } + let value = false + if (conditions.get(key) !== undefined) { + value = conditions.get(key).value; } - if (passed) { + if (value === false) { passed = false; } + } - strategyStage = 'Trigger Stage'; - checkAnnouncements(triggerStage) + if (passed) { - currentStrategyIndex = 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 + strategyStage = 'Trigger Stage'; + checkAnnouncements(triggerStage) - 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; - } + currentStrategyIndex = 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 + + 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."); } - break; } + + 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."); } + break; } } } } - } else { - let stopRunningDate = new Date(candle.begin) - if (balance <= minimumBalance) { - tradingSystem.error = "Min Balance @ " + stopRunningDate.toLocaleString() - } - if (balance >= maximumBalance) { - tradingSystem.error = "Max Balance @ " + stopRunningDate.toLocaleString() - } } + } /* Trigger Off Condition */