From 6549595802ba37aa19aee92a9f76505dffb6845b Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 24 Feb 2019 17:02:05 +0100 Subject: [PATCH 001/244] Initial commit --- .gitattributes | 2 + .gitignore | 11 + AAJason-Indicator-Bot.sln | 25 ++ Commons.js | 83 ++++ LICENSE | 24 + Multi-Period-Daily/User.Bot.js | 753 ++++++++++++++++++++++++++++++++ Multi-Period-Market/User.Bot.js | 593 +++++++++++++++++++++++++ Project.njsproj | 91 ++++ README.md | 7 + package.json | 13 + this.bot.config.json | 154 +++++++ 11 files changed, 1756 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 AAJason-Indicator-Bot.sln create mode 100644 Commons.js create mode 100644 LICENSE create mode 100644 Multi-Period-Daily/User.Bot.js create mode 100644 Multi-Period-Market/User.Bot.js create mode 100644 Project.njsproj create mode 100644 README.md create mode 100644 package.json create mode 100644 this.bot.config.json diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..dfe077042 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..82c487bdd --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ + +.vs/* +obj/* + +bin/* + +*.config +*.log +*.cache +node_modules/* + diff --git a/AAJason-Indicator-Bot.sln b/AAJason-Indicator-Bot.sln new file mode 100644 index 000000000..da30e179e --- /dev/null +++ b/AAJason-Indicator-Bot.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2027 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "Project", "Project.njsproj", "{AA2901BC-8F81-40F0-A402-5CA79A3F22AD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AA2901BC-8F81-40F0-A402-5CA79A3F22AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AA2901BC-8F81-40F0-A402-5CA79A3F22AD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA2901BC-8F81-40F0-A402-5CA79A3F22AD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AA2901BC-8F81-40F0-A402-5CA79A3F22AD}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B4BDAEAF-E863-458A-87C1-CC6D8C490784} + EndGlobalSection +EndGlobal diff --git a/Commons.js b/Commons.js new file mode 100644 index 000000000..7436a4d56 --- /dev/null +++ b/Commons.js @@ -0,0 +1,83 @@ +exports.newCommons = function newCommons(bot, logger, UTILITIES) { + + const FULL_LOG = true; + const LOG_FILE_CONTENT = false; + + const MODULE_NAME = "Commons"; + + const GMT_SECONDS = ':00.000 GMT+0000'; + + let thisObject = { + initializeStorage: initializeStorage + }; + + let utilities = UTILITIES.newCloudUtilities(bot, logger); + + return thisObject; + + function initializeStorage(chrisStorage, jasonStorage, oliviaStorage, callBackFunction) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initializeStorage -> Entering function."); } + + initializetomStorage(); + + function initializetomStorage() { + + jasonStorage.initialize(bot.devTeam, onBruceInizialized); + + function onBruceInizialized(err) { + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + initializeChrisStorage(); + + } else { + logger.write(MODULE_NAME, "[ERROR] initializeStorage -> initializetomStorage -> onBruceInizialized -> err = " + err.message); + callBackFunction(err); + } + } + } + + function initializeChrisStorage() { + + chrisStorage.initialize(bot.devTeam, onChrisInizialized); + + function onChrisInizialized(err) { + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + initializeOliviaStorage(); + + } else { + logger.write(MODULE_NAME, "[ERROR] initializeStorage -> initializeChrisStorage -> onChrisInizialized -> err = " + err.message); + callBackFunction(err); + } + } + } + + function initializeOliviaStorage() { + + oliviaStorage.initialize(bot.devTeam, onOliviaInizialized); + + function onOliviaInizialized(err) { + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + callBackFunction(global.DEFAULT_OK_RESPONSE); + + } else { + logger.write(MODULE_NAME, "[ERROR] initializeStorage -> initializeChrisStorage -> onChrisInizialized -> err = " + err.message); + callBackFunction(err); + } + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] initializeStorage -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + +}; \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..10e295746 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +Financial Beings License + +Collective Copyright by the Advanced Algos Community + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software including without limitation the rights to use, copy, modify, +merge, publish, distribute and sublicense copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following +conditions: + + 1. Using, copying, modifying, publishing, distributing and sublicensing rights + are restricted to the Advanced Algos Platform, meaning the rights granted can + only be exercised through the Advanced Algos Service. + + 2. The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js new file mode 100644 index 000000000..abcd97979 --- /dev/null +++ b/Multi-Period-Daily/User.Bot.js @@ -0,0 +1,753 @@ +exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, FILE_STORAGE) { + + const FULL_LOG = true; + const INTENSIVE_LOG = false; + const LOG_FILE_CONTENT = false; + + const GMT_SECONDS = ':00.000 GMT+0000'; + const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; + + const MODULE_NAME = "User Bot"; + + const EXCHANGE_NAME = "Poloniex"; + + const TRADES_FOLDER_NAME = "Trades"; + + const CANDLES_FOLDER_NAME = "Bands"; + const SIMULATED_TRADES_FOLDER_NAME = "Trading-Simulation"; + + const commons = COMMONS.newCommons(bot, logger, UTILITIES); + + thisObject = { + initialize: initialize, + start: start + }; + + let chrisStorage = BLOB_STORAGE.newBlobStorage(bot, logger); + let jasonStorage = BLOB_STORAGE.newBlobStorage(bot, logger); + + let utilities = UTILITIES.newCloudUtilities(bot, logger); + + let statusDependencies; + + return thisObject; + + function initialize(pStatusDependencies, pMonth, pYear, callBackFunction) { + + try { + + logger.fileName = MODULE_NAME; + logger.initialize(); + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } + + statusDependencies = pStatusDependencies; + + commons.initializeStorage(chrisStorage, jasonStorage, onInizialized); + + function onInizialized(err) { + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> onInizialized -> Initialization Succeed."); } + callBackFunction(global.DEFAULT_OK_RESPONSE); + + } else { + logger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> err = " + err.message); + callBackFunction(err); + } + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + /* + + This process is going to do the following: + + Read the bands from Chris and produce daily files with bollinger trades. + + */ + + function start(callBackFunction) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); } + + let market = global.MARKET; + + /* Context Variables */ + + let contextVariables = { + lastTradeFile: undefined, // Datetime of the last file files sucessfully produced by this process. + firstTradeFile: undefined, // Datetime of the first trade file in the whole market history. + maxTradeFile: undefined // Datetime of the last file available to be used as an input of this process. + }; + + let previousDay; // Holds the date of the previous day relative to the processing date. + let processDate; // Holds the processing date. + + getContextVariables(); + + function getContextVariables() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Entering function."); } + + let thisReport; + let reportKey; + let statusReport; + + /* We look first for Charly in order to get when the market starts. */ + + reportKey = "AAMasters" + "-" + "AACharly" + "-" + "Poloniex-Historic-Trades" + "-" + "dataSet.V1"; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); } + + statusReport = statusDependencies.statusReports.get(reportKey); + + if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. "); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; + } + + if (statusReport.status === "Status Report is corrupt.") { + logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. "); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; + } + + thisReport = statusDependencies.statusReports.get(reportKey).file; + + if (thisReport.lastFile === undefined) { + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey); + logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> It is too early too run this process since the trade history of the market is not there yet."); + + let customOK = { + result: global.CUSTOM_OK_RESPONSE.result, + message: "Dependency does not exist." + } + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message); + callBackFunction(customOK); + return; + } + + contextVariables.firstTradeFile = new Date(thisReport.lastFile.year + "-" + thisReport.lastFile.month + "-" + thisReport.lastFile.days + " " + thisReport.lastFile.hours + ":" + thisReport.lastFile.minutes + GMT_SECONDS); + + /* Second, we get the report from Chris, to know when the marted ends. */ + + reportKey = "AAMasters" + "-" + "AAChris" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1"; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); } + + statusReport = statusDependencies.statusReports.get(reportKey); + + if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. "); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; + } + + if (statusReport.status === "Status Report is corrupt.") { + logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. "); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; + } + + thisReport = statusDependencies.statusReports.get(reportKey).file; + + if (thisReport.lastFile === undefined) { + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey); + + let customOK = { + result: global.CUSTOM_OK_RESPONSE.result, + message: "Dependency not ready." + } + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message); + callBackFunction(customOK); + return; + } + + contextVariables.maxTradeFile = new Date(thisReport.lastFile.valueOf()); + + /* Finally we get our own Status Report. */ + + reportKey = "AAMasters" + "-" + "AAJason" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1"; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); } + + statusReport = statusDependencies.statusReports.get(reportKey); + + if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. + logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. "); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; + } + + if (statusReport.status === "Status Report is corrupt.") { + logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process."); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return; + } + + thisReport = statusDependencies.statusReports.get(reportKey).file; + + if (thisReport.lastFile !== undefined) { + + contextVariables.lastTradeFile = new Date(thisReport.lastFile); + + /* + The trades objects needs to be calculated over more than one day in some situations. In order to simplify the calculations we will + always load the last 2 days of bands, and run the calculations on that array. + + 1. So first we will load the bands file of processDay -1. + 2. Secondly we will load the bands file of processDay. + + After reading these two files we will add all bands to a unique array. + */ + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> thisReport.lastFile !== undefined"); } + + buildTrades(); + return; + + } else { + + /* + In the case when there is no status report, we take the date of the file with the first trades as the begining of the market. Then we will + go one day further in time, so that the previous day does fine a file at the begining of the market. + */ + + contextVariables.lastTradeFile = new Date(contextVariables.firstTradeFile.getUTCFullYear() + "-" + (contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" + contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" + GMT_SECONDS); + contextVariables.lastTradeFile = new Date(contextVariables.lastTradeFile.valueOf() + ONE_DAY_IN_MILISECONDS); + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> thisReport.lastFile === undefined"); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> contextVariables.lastTradeFile = " + contextVariables.lastTradeFile); } + + buildTrades(); + return; + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> err = " + err.message); + if (err.message === "Cannot read property 'file' of undefined") { + logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. "); + logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys)); + } + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildTrades() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> Entering function."); } + + let n; + processDate = new Date(contextVariables.lastTradeFile.valueOf() - ONE_DAY_IN_MILISECONDS); // Go back one day to start well when we advance time at the begining of the loop. + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> processDate = " + processDate); } + + advanceTime(); + + function advanceTime() { + + try { + + logger.newInternalLoop(bot.codeName, bot.process); + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> advanceTime -> Entering function."); } + + processDate = new Date(processDate.valueOf() + ONE_DAY_IN_MILISECONDS); + previousDay = new Date(processDate.valueOf() - ONE_DAY_IN_MILISECONDS); + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> advanceTime -> processDate = " + processDate); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> advanceTime -> previousDay = " + previousDay); } + + /* Validation that we are not going past the head of the market. */ + + if (processDate.valueOf() > contextVariables.maxTradeFile.valueOf()) { + + const logText = "Head of the market found @ " + previousDay.getUTCFullYear() + "/" + (previousDay.getUTCMonth() + 1) + "/" + previousDay.getUTCDate() + "."; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> advanceTime -> " + logText); } + + callBackFunction(global.DEFAULT_OK_RESPONSE); + return; + + } + + periodsLoop(); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> advanceTime -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function periodsLoop() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> periodsLoop -> Entering function."); } + + /* + + We will iterate through all posible timePeriods. + + */ + + n = 0 // loop Variable representing each possible period as defined at the periods array. + + loopBody(); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function loopBody() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> Entering function."); } + + const timePeriod = global.dailyFilePeriods[n][1]; + + let bands = []; // Here we will put all the bands of the 2 files read. + + let previousDayFile; + let processDayFile; + + getPreviousDayFile(); + + function getPreviousDayFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> getPreviousDayFile -> Entering function."); } + + let dateForPath = previousDay.getUTCFullYear() + '/' + utilities.pad(previousDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(previousDay.getUTCDate(), 2); + let fileName = market.assetA + '_' + market.assetB + ".json" + + let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + "Multi-Period-Daily" + "/" + timePeriod + "/" + dateForPath; + + chrisStorage.getTextFile(filePath, fileName, onCurrentDayFileReceived, true); + + function onCurrentDayFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> text = " + text); } + + previousDayFile = JSON.parse(text); + getProcessDayFile() + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> market = " + market.assetA + '_' + market.assetB); + + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + } + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> getPreviousDayFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function getProcessDayFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> getProcessDayFile -> Entering function."); } + + let dateForPath = processDate.getUTCFullYear() + '/' + utilities.pad(processDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(processDate.getUTCDate(), 2); + let fileName = market.assetA + '_' + market.assetB + ".json" + + let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + "Multi-Period-Daily" + "/" + timePeriod + "/" + dateForPath; + + chrisStorage.getTextFile(filePath, fileName, onCurrentDayFileReceived, true); + + function onCurrentDayFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> text = " + text); } + + processDayFile = JSON.parse(text); + buildTrades(); + + } catch (err) { + + if (processDate.valueOf() > contextVariables.maxTradeFile.valueOf()) { + + processDayFile = []; // we are past the head of the market, then no worries if this file is non existent. + buildTrades(); + + } else { + + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> market = " + market.assetA + '_' + market.assetB); + + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; + } + } + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> getProcessDayFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildTrades() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> buildTrades -> Entering function."); } + + addBandsToSingleArray(previousDayFile); + addBandsToSingleArray(processDayFile); + calculateTrades(); + + function addBandsToSingleArray(bandsFile) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> buildTrades -> addBandsToSingleArray -> Entering function."); } + + for (let i = 0; i < bandsFile.length; i++) { + + let band = { + open: undefined, + close: undefined, + min: 10000000000000, + max: 0, + begin: undefined, + end: undefined, + direction: undefined + }; + + band.min = bandsFile[i][0]; + band.max = bandsFile[i][1]; + + band.open = bandsFile[i][2]; + band.close = bandsFile[i][3]; + + band.begin = bandsFile[i][4]; + band.end = bandsFile[i][5]; + + if (band.open > band.close) { band.direction = 'down'; } + if (band.open < band.close) { band.direction = 'up'; } + if (band.open === band.close) { band.direction = 'side'; } + + bands.push(band); + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> buildTrades -> addBandsToSingleArray -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return; + } + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> buildTrades -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return; + } + } + + function calculateTrades() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> calculateTrades -> Entering function."); } + + let tradesArray = []; + let numberOfPeriods = 20; + + /* Building trades */ + + let trade; + + for (let i = numberOfPeriods - 1; i < bands.length; i++) { // Go through all the bands to generate a trade segment for each of them. + + let movingAverage = 0; + for (let j = i - numberOfPeriods + 1; j < i + 1; j++) { // go through the last n bands to calculate the moving average. + movingAverage = movingAverage + bands[j].close; + } + movingAverage = movingAverage / numberOfPeriods; + + let standardDeviation = 0; + for (let j = i - numberOfPeriods + 1; j < i + 1; j++) { // go through the last n bands to calculate the standard deviation. + standardDeviation = standardDeviation + Math.pow(bands[j].close - movingAverage, 2); + } + standardDeviation = standardDeviation / numberOfPeriods; + standardDeviation = Math.sqrt(standardDeviation); + + trade = { + begin: bands[i].begin, + end: bands[i].end, + movingAverage: movingAverage, + standardDeviation: standardDeviation + }; + + /* Will only add to the array the trades of the current day */ + + if (trade.begin >= processDate.valueOf()) { tradesArray.push(trade); } + + } + + writeFile(tradesArray); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> calculateTrades -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return; + } + } + + function writeFile(pTrades, callback) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> writeTradeTradesFile -> writeFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (i = 0; i < pTrades.length; i++) { + + let trade = pTrades[i]; + + fileContent = fileContent + separator + '[' + + trade.begin + "," + + trade.end + "," + + trade.movingAverage + "," + + trade.standardDeviation + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + + let dateForPath = processDate.getUTCFullYear() + '/' + utilities.pad(processDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(processDate.getUTCDate(), 2); + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + SIMULATED_TRADES_FOLDER_NAME + "/" + bot.process + "/" + timePeriod + "/" + dateForPath; + + jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> writeTradeTradesFile -> writeFile -> onFileCreated -> Entering function."); } + + if (LOG_FILE_CONTENT === true) { + logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> writeTradeTradesFile -> writeFile -> onFileCreated -> Content written = " + fileContent); + } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> loopBody -> writeTradeTradesFile -> writeFile -> onFileCreated -> err = " + err.message); + callBackFunction(err); + return; + } + + const logText = "[WARN] Finished with File @ " + market.assetA + "_" + market.assetB + ", " + fileRecordCounter + " records inserted into " + filePath + "/" + fileName + ""; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> writeTradeTradesFile -> writeFile -> onFileCreated -> " + logText); } + + controlLoop(); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> writeTradeTradesFile -> writeFile -> onFileCreated -> err = " + err.message); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + } + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> writeTradeTradesFile -> writeFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + + + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function controlLoop() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> controlLoop -> Entering function."); } + + n++; + + if (n < global.dailyFilePeriods.length) { + + loopBody(); + + } else { + + n = 0; + + writeDataRanges(onWritten); + + function onWritten(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> controlLoop -> onWritten -> Entering function."); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> controlLoop -> onWritten -> err = " + err.message); + callBackFunction(err); + return; + } + + writeStatusReport(processDate, advanceTime); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> controlLoop -> onWritten -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> controlLoop -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> err.message = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeDataRanges(callBack) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRanges -> Entering function."); } + + writeDataRange(contextVariables.firstTradeFile, processDate, SIMULATED_TRADES_FOLDER_NAME, onTradesTradesDataRangeWritten); + + function onTradesTradesDataRangeWritten(err) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRanges -> Entering function."); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, "[ERROR] writeDataRanges -> writeDataRanges -> onTradesTradesDataRangeWritten -> err = " + err.message); + callBack(err); + return; + } + + callBack(global.DEFAULT_OK_RESPONSE); + + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDataRanges -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + + } + + function writeDataRange(pBegin, pEnd, pProductFolder, callBack) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> Entering function."); } + + let dataRange = { + begin: pBegin.valueOf(), + end: pEnd.valueOf() + }; + + let fileContent = JSON.stringify(dataRange); + + let fileName = 'Data.Range.' + market.assetA + '_' + market.assetB + '.json'; + let filePath = bot.filePathRoot + "/Output/" + pProductFolder + "/" + bot.process; + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> fileName = " + fileName); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> filePath = " + filePath); } + + jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Entering function."); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> onFileCreated -> err = " + err.message); + callBack(err); + return; + } + + if (LOG_FILE_CONTENT === true) { + logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Content written = " + fileContent); + } + + callBack(global.DEFAULT_OK_RESPONSE); + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeStatusReport(lastFileDate, callBack) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> lastFileDate = " + lastFileDate); } + + try { + + let reportKey = "AAMasters" + "-" + "AAJason" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1"; + let thisReport = statusDependencies.statusReports.get(reportKey); + + thisReport.file.lastExecution = bot.processDatetime; + thisReport.file.lastFile = lastFileDate; + thisReport.save(callBack); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> err.message = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } +}; diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js new file mode 100644 index 000000000..a2da081dd --- /dev/null +++ b/Multi-Period-Market/User.Bot.js @@ -0,0 +1,593 @@ +exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, FILE_STORAGE) { + + const FULL_LOG = true; + const LOG_FILE_CONTENT = false; + + const MODULE_NAME = "User Bot"; + + const EXCHANGE_NAME = "Poloniex"; + + const PERCENTAGE_BANDWIDTH_FOLDER_NAME = "Percentage-Bandwidth"; + const CANDLES_FOLDER_NAME = "Candles"; + const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; + + const commons = COMMONS.newCommons(bot, logger, UTILITIES); + + thisObject = { + initialize: initialize, + start: start + }; + + let chrisStorage = BLOB_STORAGE.newBlobStorage(bot, logger); + let oliviaStorage = BLOB_STORAGE.newBlobStorage(bot, logger); + let jasonStorage = BLOB_STORAGE.newBlobStorage(bot, logger); + + let utilities = UTILITIES.newCloudUtilities(bot, logger); + + let statusDependencies; + + return thisObject; + + function initialize(pStatusDependencies, pMonth, pYear, callBackFunction) { + + try { + + logger.fileName = MODULE_NAME; + logger.initialize(); + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } + + statusDependencies = pStatusDependencies; + + commons.initializeStorage(chrisStorage, jasonStorage, oliviaStorage, onInizialized); + + function onInizialized(err) { + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> onInizialized -> Initialization Succeed."); } + callBackFunction(global.DEFAULT_OK_RESPONSE); + + } else { + logger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> err = " + err.message); + callBackFunction(err); + } + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + + + function start(callBackFunction) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); } + + let market = global.MARKET; + + buildRecords(); + + function buildRecords() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> Entering function."); } + + try { + + let n; + + periodsLoop(); + + function periodsLoop() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> periodsLoop -> Entering function."); } + + /* + + We will iterate through all posible periods. + + */ + + n = 0 // loop Variable representing each possible period as defined at the periods array. + + loopBody(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> periodsLoop -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function loopBody() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> Entering function."); } + + const outputPeriod = global.marketFilesPeriods[n][0]; + const timePeriod = global.marketFilesPeriods[n][1]; + + let marketFile; + + let percentgeBandwidthArray = new Map(); + let candles = []; + let recordsArray = []; + + nextChrisFile(); + + function nextChrisFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextChrisFile -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + PERCENTAGE_BANDWIDTH_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextChrisFile -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextChrisFile -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextChrisFile -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildPercentgeBandwidthArray(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextChrisFile -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextChrisFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildPercentgeBandwidthArray() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildPercentgeBandwidthArray -> Entering function."); } + + try { + + for (let i = 0; i < marketFile.length; i++) { + + let percentgeBandwidth = { + begin: marketFile[i][0], + end: marketFile[i][1], + value: marketFile[i][2], + movingAverage: marketFile[i][3] + }; + + percentgeBandwidthArray.set(percentgeBandwidth.begin, percentgeBandwidth); + + } + + nextCandlesFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildPercentgeBandwidthArray -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function nextCandlesFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = bot.devTeam + "/" + "AAOlivia" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + oliviaStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildCandles(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildCandles() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildCandles -> Entering function."); } + + try { + + for (let i = 0; i < marketFile.length; i++) { + + let candle = { + open: undefined, + close: undefined, + min: 10000000000000, + max: 0, + begin: undefined, + end: undefined, + direction: undefined + }; + + candle.min = marketFile[i][0]; + candle.max = marketFile[i][1]; + + candle.open = marketFile[i][2]; + candle.close = marketFile[i][3]; + + candle.begin = marketFile[i][4]; + candle.end = marketFile[i][5]; + + if (candle.open > candle.close) { candle.direction = 'down'; } + if (candle.open < candle.close) { candle.direction = 'up'; } + if (candle.open === candle.close) { candle.direction = 'side'; } + + candles.push(candle); + + } + + buildRecords(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildCandles -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildRecords() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildRecords -> Entering function."); } + + /* Building records */ + + let stopLossPercentage = 1; + let initialBalanceA = 1; + let record; + let lastOperation = 'Buy'; + let initialDate = new Date("2018-08-01"); + let balanceAssetA = initialBalanceA; + let balanceAssetB = 0; + let profit = 0; + let lastProfit = 0; + let stopLoss = 0; + let previousBalanceAssetA = 0; + let roundtrips = 0; + let hits = 0; + let fails = 0; + let hitRatio = 0; + let ROI = 0; + let periods = 0; + let days = 0; + let anualizedRateOfReturn = 0; + let type = ''; + let rate = 0; + let previousPBMovingAverage = 0; + let trailingStop = false; + + for (let i = 0; i < candles.length; i++) { + + let candle = candles[i]; + let percentgeBandwidth = percentgeBandwidthArray.get(candle.begin); + + if (percentgeBandwidth === undefined) { continue;} + + if (candle.begin < initialDate.valueOf()) { continue; } + + periods++; + + /* Sell condition */ + + if ( + percentgeBandwidth.value >= 80 && + lastOperation === 'Buy' && + (previousPBMovingAverage > percentgeBandwidth.movingAverage) + ) { + + previousBalanceAssetA = balanceAssetA; + lastProfit = 0; + + balanceAssetB = balanceAssetA * candle.close; + balanceAssetA = 0; + stopLoss = candle.close + candle.close * stopLossPercentage / 100; + rate = candle.close; + + type = '"Sell"'; + lastOperation = 'Sell'; + + addRecord(); + + continue; + }; + + /* Stop Loss condition */ + + let mustBuy = false; + + if (candle.max >= stopLoss && lastOperation === 'Sell') { + + balanceAssetA = balanceAssetB / stopLoss; + balanceAssetB = 0; + rate = stopLoss; + mustBuy = true; + } + + /* Buy condition */ + + if (percentgeBandwidth.value <= 50 && lastOperation === 'Sell' && mustBuy === false) { + + balanceAssetA = balanceAssetB / candle.close; + balanceAssetB = 0; + rate = candle.close; + mustBuy = true; + }; + + if (mustBuy === true) { + + stopLoss = 0; + trailingStop = false; + roundtrips++; + lastProfit = balanceAssetA - previousBalanceAssetA; + profit = profit + lastProfit; + ROI = (initialBalanceA + profit) / initialBalanceA - 1; + + if (lastProfit > 0) { + hits++; + } else { + fails++; + } + hitRatio = hits / roundtrips; + + let miliSecondsPerDay = 24 * 60 * 60 * 1000; + days = periods * outputPeriod / miliSecondsPerDay; + anualizedRateOfReturn = ROI / days * 365; + + type = '"Buy"'; + lastOperation = 'Buy'; + + addRecord(); + + continue; + + } + + /* Not a buy or sell condition */ + + type = '""'; + addRecord(); + previousPBMovingAverage = percentgeBandwidth.movingAverage; + + function addRecord() { + + record = { + begin: candle.begin, + end: candle.end, + type: type, + rate: rate, + amount: 1, + balanceA: balanceAssetA, + balanceB: balanceAssetB, + profit: profit, + lastProfit: lastProfit, + stopLoss: stopLoss, + roundtrips: roundtrips, + hits: hits, + fails: fails, + hitRatio: hitRatio, + ROI: ROI, + periods: periods, + days: days, + anualizedRateOfReturn: anualizedRateOfReturn + } + + recordsArray.push(record); + } + } + + writeRecordsFile(); + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildRecords -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeRecordsFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (i = 0; i < recordsArray.length; i++) { + + let record = recordsArray[i]; + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.type + "," + + record.rate + "," + + record.amount + "," + + record.balanceA + "," + + record.balanceB + "," + + record.profit + "," + + record.lastProfit + "," + + record.stopLoss + "," + + record.roundtrips + "," + + record.hits + "," + + record.fails + "," + + record.hitRatio + "," + + record.ROI + "," + + record.periods + "," + + record.days + "," + + record.anualizedRateOfReturn + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + controlLoop(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function controlLoop() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> controlLoop -> Entering function."); } + + n++; + + if (n < global.marketFilesPeriods.length) { + + loopBody(); + + } else { + + writeStatusReport(callBackFunction); + + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> controlLoop -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeStatusReport(callBack) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> Entering function."); } + + try { + + let reportKey = "AAMasters" + "-" + "AAJason" + "-" + "Multi-Period-Market" + "-" + "dataSet.V1"; + let thisReport = statusDependencies.statusReports.get(reportKey); + + thisReport.file.lastExecution = bot.processDatetime; + thisReport.save(callBack); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } +}; diff --git a/Project.njsproj b/Project.njsproj new file mode 100644 index 000000000..4cab6c556 --- /dev/null +++ b/Project.njsproj @@ -0,0 +1,91 @@ + + + + Debug + 2.0 + {aa2901bc-8f81-40f0-a402-5ca79a3f22ad} + + ShowAllFiles + + + c:\users\luis\source\repos\AAOlivia\Multi-Period-Market + . + {3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD} + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + Project + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + True + 0 + / + http://localhost:48022/ + False + True + http://localhost:1337 + False + + + + + + + CurrentPage + True + False + False + False + + + + + + + + + False + False + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 000000000..099b74e58 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# I'm Jason, an AA i-Bot! + +# Disclaimer + +THE AA MASTERS BOTS AND THEIR ASSOCIATED PRODUCTS AND SERVICES ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, SUITABILITY FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + +IN NO EVENT WILL ADVANCED ALGOS BE LIABLE TO ANY PARTY FOR ANY DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY USE OF THE AACLOUD, THE AA ARENA COMPETITION, THE AA MASTERS BOTS, OR ANY OTHER ASSOCIATED SERVICE OR WEB SITE, INCLUDING, WITHOUT LIMITATION, ANY LOST PROFITS, BUSINESS INTERRUPTION, LOSS OF FUNDS, PROGRAMS OR OTHER DATA OR OTHERWISE, EVEN IF WE ARE EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. diff --git a/package.json b/package.json new file mode 100644 index 000000000..11cc6a7f1 --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "name": "AAToma", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Luis-Fernando-Molina", + "license": "ISC", + "dependencies": { + } +} diff --git a/this.bot.config.json b/this.bot.config.json new file mode 100644 index 000000000..e4aeadbf9 --- /dev/null +++ b/this.bot.config.json @@ -0,0 +1,154 @@ +{ + "displayName": "Jason", + "codeName": "AAJason", + "type": "Indicator", + "version": { + "major": 1, + "minor": 0, + "patch": 0 + }, + "devTeam": "AAMasters", + "profilePicture": "Jason.png", + "dataSetVersion": "dataSet.V1", + "processes": [ + { + "name": "Multi-Period-Market", + "description": "Produces a single file for each time period covering all the market.", + "startMode": { + "allMonths": { + "run": "false", + "minYear": "", + "maxYear": "" + }, + "oneMonth": { + "run": "false", + "year": "", + "month": "" + }, + "noTime": { + "run": "true" + }, + "fixedInterval": { + "run": "false", + "interval": 0 + } + }, + "normalWaitTime": 60000, + "retryWaitTime": 10000, + "sleepWaitTime": 3600000, + "comaWaitTime": 86400000, + "statusDependencies": [ + { + "devTeam": "AAMasters", + "bot": "AAJason", + "botVersion": { + "major": 1, + "minor": 0 + }, + "process": "Multi-Period-Market", + "dataSetVersion": "dataSet.V1" + } + ] + }, + { + "name": "Multi-Period-Daily", + "description": "Produces a Daily File at each time period.", + "startMode": { + "allMonths": { + "run": "false", + "minYear": "", + "maxYear": "" + }, + "oneMonth": { + "run": "false", + "year": "", + "month": "" + }, + "noTime": { + "run": "true" + }, + "fixedInterval": { + "run": "false", + "interval": 0 + } + }, + "normalWaitTime": 60000, + "retryWaitTime": 10000, + "sleepWaitTime": 3600000, + "comaWaitTime": 86400000, + "statusDependencies": [ + { + "devTeam": "AAMasters", + "bot": "AACharly", + "botVersion": { + "major": 1, + "minor": 0 + }, + "process": "Poloniex-Historic-Records", + "dataSetVersion": "dataSet.V1" + }, + { + "devTeam": "AAMasters", + "bot": "AAChris", + "botVersion": { + "major": 1, + "minor": 0 + }, + "process": "Multi-Period-Daily", + "dataSetVersion": "dataSet.V1" + }, + { + "devTeam": "AAMasters", + "bot": "AAJason", + "botVersion": { + "major": 1, + "minor": 0 + }, + "process": "Multi-Period-Daily", + "dataSetVersion": "dataSet.V1" + } + ] + } + ], + "products": [ + { + "codeName": "Trading-Simulation", + "displayName": "Trading Simulation", + "description": "Trading Simulation", + "storageAccount": "aajason", + "dataSets": [ + { + "codeName": "Multi-Period-Market", + "type": "Market Files", + "validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs" ], + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Trading-Simulation/Multi-Period-Market/@Period", + "fileName": "@AssetA_@AssetB.json" + }, + { + "codeName": "Multi-Period-Daily", + "type": "Daily Files", + "validPeriods": [ "45-min", "40-min", "30-min", "20-min", "15-min", "10-min", "05-min", "04-min", "03-min", "02-min", "01-min" ], + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Trading-Simulation/Multi-Period-Daily/@Period/@Year/@Month/@Day", + "fileName": "@AssetA_@AssetB.json", + "dataRange": { + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Trading-Simulation/Multi-Period-Daily", + "fileName": "Data.Range.@AssetA_@AssetB.json" + } + } + ], + "exchangeList": [ + { + "name": "Poloniex" + } + ], + "plotter": { + "devTeam": "AAMasters", + "codeName": "PlottersTradingSimulation", + "moduleName": "TradingSimulation" + } + } + ] +} + + + From 4d755f8c88bcd0e200feb16ca9d8aace0b603ab8 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 24 Feb 2019 17:27:50 +0100 Subject: [PATCH 002/244] Trailing Stop Implemented --- Multi-Period-Market/User.Bot.js | 121 +++++++++++++++++++++++++++----- 1 file changed, 105 insertions(+), 16 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index a2da081dd..746dfcef0 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -8,6 +8,7 @@ const EXCHANGE_NAME = "Poloniex"; const PERCENTAGE_BANDWIDTH_FOLDER_NAME = "Percentage-Bandwidth"; + const BOLLINGER_BANDS_FOLDER_NAME = "Bollinger-Bands"; const CANDLES_FOLDER_NAME = "Candles"; const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; @@ -116,17 +117,19 @@ let marketFile; - let percentgeBandwidthArray = new Map(); + let percentgeBandwidthMap = new Map(); + let bollingerBandsMap = new Map(); + let candles = []; let recordsArray = []; - nextChrisFile(); + nextPercentageBandwidth(); - function nextChrisFile() { + function nextPercentageBandwidth() { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextChrisFile -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> Entering function."); } let fileName = market.assetA + '_' + market.assetB + ".json"; @@ -139,12 +142,12 @@ try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextChrisFile -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextChrisFile -> onFileReceived -> text = " + text); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> text = " + text); } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextChrisFile -> onFileReceived -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> err = " + err.message); callBackFunction(err); return; @@ -152,25 +155,25 @@ marketFile = JSON.parse(text); - buildPercentgeBandwidthArray(); + buildPercentageBandwidthMap(); } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextChrisFile -> onFileReceived -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextChrisFile -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - function buildPercentgeBandwidthArray() { + function buildPercentageBandwidthMap() { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildPercentgeBandwidthArray -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildPercentageBandwidthMap -> Entering function."); } try { @@ -183,7 +186,82 @@ movingAverage: marketFile[i][3] }; - percentgeBandwidthArray.set(percentgeBandwidth.begin, percentgeBandwidth); + percentgeBandwidthMap.set(percentgeBandwidth.begin, percentgeBandwidth); + + } + + nextBollingerBands(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildPercentageBandwidthMap -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function nextBollingerBands() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + BOLLINGER_BANDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildBollingerBandsMap(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildBollingerBandsMap() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerBandsMap -> Entering function."); } + + try { + + for (let i = 0; i < marketFile.length; i++) { + + let bollingerBands = { + begin: marketFile[i][0], + end: marketFile[i][1], + movingAverage: marketFile[i][2], + standardDeviation: marketFile[i][3], + deviation: marketFile[i][4] + }; + + bollingerBandsMap.set(bollingerBands.begin, bollingerBands); } @@ -191,7 +269,7 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildPercentgeBandwidthArray -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerBandsMap -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -321,7 +399,9 @@ for (let i = 0; i < candles.length; i++) { let candle = candles[i]; - let percentgeBandwidth = percentgeBandwidthArray.get(candle.begin); + let percentgeBandwidth = percentgeBandwidthMap.get(candle.begin); + let band = bollingerBandsMap.get(candle.begin); + if (percentgeBandwidth === undefined) { continue;} @@ -353,6 +433,14 @@ continue; }; + /* Start Trailing Stop Condition */ + + if (candle.max < band.movingAverage && lastOperation === 'Sell') { + + stopLoss = band.movingAverage; + + } + /* Stop Loss condition */ let mustBuy = false; @@ -366,7 +454,7 @@ } /* Buy condition */ - + /* if (percentgeBandwidth.value <= 50 && lastOperation === 'Sell' && mustBuy === false) { balanceAssetA = balanceAssetB / candle.close; @@ -374,6 +462,7 @@ rate = candle.close; mustBuy = true; }; + */ if (mustBuy === true) { From 60c111641bfc3aef4beb29cd0f14db521cf0351d Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 25 Feb 2019 00:41:39 +0100 Subject: [PATCH 003/244] Pre Sell logic --- Multi-Period-Market/User.Bot.js | 60 ++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 746dfcef0..9fb82e7e1 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -326,7 +326,9 @@ try { - for (let i = 0; i < marketFile.length; i++) { + let initialBuffer = 3; + + for (let i = 0 + initialBuffer; i < marketFile.length; i++) { let candle = { open: undefined, @@ -372,7 +374,7 @@ /* Building records */ - let stopLossPercentage = 1; + let stopLossPercentage = 2; let initialBalanceA = 1; let record; let lastOperation = 'Buy'; @@ -394,7 +396,11 @@ let type = ''; let rate = 0; let previousPBMovingAverage = 0; + let previousPreviousPBMovingAverage = 0; + let previousBandMovingAverage = 0; + let previousStopLoss = 0; let trailingStop = false; + let pBOK = false; for (let i = 0; i < candles.length; i++) { @@ -409,12 +415,25 @@ periods++; - /* Sell condition */ + /* PB Coming Down from the roof enables condition to sell */ if ( - percentgeBandwidth.value >= 80 && + percentgeBandwidth.value >= 70 && lastOperation === 'Buy' && - (previousPBMovingAverage > percentgeBandwidth.movingAverage) + (previousPreviousPBMovingAverage > previousPBMovingAverage) && + (previousPBMovingAverage > percentgeBandwidth.movingAverage ) + ) { + + pBOK = true; + + }; + + /* Sell Condition */ + + if ( + pBOK === true && + previousBandMovingAverage > band.movingAverage && + lastOperation === 'Buy' ) { previousBalanceAssetA = balanceAssetA; @@ -427,18 +446,36 @@ type = '"Sell"'; lastOperation = 'Sell'; + pBOK = false; addRecord(); continue; - }; + + } /* Start Trailing Stop Condition */ - if (candle.max < band.movingAverage && lastOperation === 'Sell') { + if ( + candle.max < band.movingAverage && + lastOperation === 'Sell' && + (previousBandMovingAverage > band.movingAverage) && + (candle.min < band.movingAverage - band.deviation) + ) { - stopLoss = band.movingAverage; + trailingStop = true; + + } + if (trailingStop === true) { + + let newStopLoss = band.movingAverage + band.movingAverage * stopLossPercentage / 100; + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } } /* Stop Loss condition */ @@ -468,6 +505,7 @@ stopLoss = 0; trailingStop = false; + roundtrips++; lastProfit = balanceAssetA - previousBalanceAssetA; profit = profit + lastProfit; @@ -497,7 +535,6 @@ type = '""'; addRecord(); - previousPBMovingAverage = percentgeBandwidth.movingAverage; function addRecord() { @@ -523,6 +560,11 @@ } recordsArray.push(record); + + previousPreviousPBMovingAverage = previousPBMovingAverage + previousPBMovingAverage = percentgeBandwidth.movingAverage; + previousBandMovingAverage = band.movingAverage; + previousStopLoss = stopLoss; } } From 67929701864237951fdc424acdc12bf06024765b Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 25 Feb 2019 01:06:38 +0100 Subject: [PATCH 004/244] Initial Buffer --- Multi-Period-Market/User.Bot.js | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 9fb82e7e1..0cafc0c13 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -326,9 +326,7 @@ try { - let initialBuffer = 3; - - for (let i = 0 + initialBuffer; i < marketFile.length; i++) { + for (let i = 0; i < marketFile.length; i++) { let candle = { open: undefined, @@ -395,14 +393,13 @@ let anualizedRateOfReturn = 0; let type = ''; let rate = 0; - let previousPBMovingAverage = 0; - let previousPreviousPBMovingAverage = 0; - let previousBandMovingAverage = 0; let previousStopLoss = 0; let trailingStop = false; let pBOK = false; - for (let i = 0; i < candles.length; i++) { + let initialBuffer = 3; + + for (let i = 0 + initialBuffer; i < candles.length; i++) { let candle = candles[i]; let percentgeBandwidth = percentgeBandwidthMap.get(candle.begin); @@ -420,8 +417,8 @@ if ( percentgeBandwidth.value >= 70 && lastOperation === 'Buy' && - (previousPreviousPBMovingAverage > previousPBMovingAverage) && - (previousPBMovingAverage > percentgeBandwidth.movingAverage ) + (percentgeBandwidthMap.get(candles[i - 2].begin).movingAverage > percentgeBandwidthMap.get(candles[i - 1].begin).movingAverage) && + (percentgeBandwidthMap.get(candles[i - 1].begin).movingAverage > percentgeBandwidth.movingAverage ) ) { pBOK = true; @@ -432,7 +429,8 @@ if ( pBOK === true && - previousBandMovingAverage > band.movingAverage && + bollingerBandsMap.get(candles[i - 2].begin).movingAverage > bollingerBandsMap.get(candles[i - 1].begin).movingAverage && + bollingerBandsMap.get(candles[i - 1].begin).movingAverage > band.movingAverage && lastOperation === 'Buy' ) { @@ -459,7 +457,7 @@ if ( candle.max < band.movingAverage && lastOperation === 'Sell' && - (previousBandMovingAverage > band.movingAverage) && + (bollingerBandsMap.get(candles[i - 1].begin).movingAverage > band.movingAverage) && (candle.min < band.movingAverage - band.deviation) ) { @@ -561,9 +559,6 @@ recordsArray.push(record); - previousPreviousPBMovingAverage = previousPBMovingAverage - previousPBMovingAverage = percentgeBandwidth.movingAverage; - previousBandMovingAverage = band.movingAverage; previousStopLoss = stopLoss; } } From 8dbe86f1cf603d8601e811405f389c5207c36de7 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 25 Feb 2019 01:31:52 +0100 Subject: [PATCH 005/244] stop loss decay --- Multi-Period-Market/User.Bot.js | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 0cafc0c13..a0f438a71 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -373,6 +373,12 @@ /* Building records */ let stopLossPercentage = 2; + let previousStopLoss = 0; + let trailingStop = false; + let stopLoss = 0; + let stopLossDecay = 0; + let stopLossDecayIncrement = 0.05; + let initialBalanceA = 1; let record; let lastOperation = 'Buy'; @@ -381,7 +387,8 @@ let balanceAssetB = 0; let profit = 0; let lastProfit = 0; - let stopLoss = 0; + let sellRate = 0; + let previousBalanceAssetA = 0; let roundtrips = 0; let hits = 0; @@ -393,8 +400,7 @@ let anualizedRateOfReturn = 0; let type = ''; let rate = 0; - let previousStopLoss = 0; - let trailingStop = false; + let pBOK = false; let initialBuffer = 3; @@ -420,7 +426,7 @@ (percentgeBandwidthMap.get(candles[i - 2].begin).movingAverage > percentgeBandwidthMap.get(candles[i - 1].begin).movingAverage) && (percentgeBandwidthMap.get(candles[i - 1].begin).movingAverage > percentgeBandwidth.movingAverage ) ) { - + type = '"Pre-Sell"'; pBOK = true; }; @@ -439,12 +445,16 @@ balanceAssetB = balanceAssetA * candle.close; balanceAssetA = 0; - stopLoss = candle.close + candle.close * stopLossPercentage / 100; + rate = candle.close; + sellRate = rate; + + stopLoss = sellRate + sellRate * stopLossPercentage / 100; type = '"Sell"'; lastOperation = 'Sell'; pBOK = false; + stopLossDecay = 0; addRecord(); @@ -467,13 +477,15 @@ if (trailingStop === true) { - let newStopLoss = band.movingAverage + band.movingAverage * stopLossPercentage / 100; + let newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; if (newStopLoss < previousStopLoss) { stopLoss = newStopLoss; } else { stopLoss = previousStopLoss; } + } else { + stopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; } /* Stop Loss condition */ @@ -502,6 +514,7 @@ if (mustBuy === true) { stopLoss = 0; + sellRate = 0; trailingStop = false; roundtrips++; @@ -530,8 +543,7 @@ } /* Not a buy or sell condition */ - - type = '""'; + addRecord(); function addRecord() { @@ -560,6 +572,10 @@ recordsArray.push(record); previousStopLoss = stopLoss; + stopLossDecay = stopLossDecay + stopLossDecayIncrement; + + type = '""'; + } } From cb96f465f76a5b75d91c29eb125d9f08e4dd92ce Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 25 Feb 2019 01:45:38 +0100 Subject: [PATCH 006/244] Bug fixed type null --- Multi-Period-Market/User.Bot.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index a0f438a71..1b4e40220 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -398,7 +398,7 @@ let periods = 0; let days = 0; let anualizedRateOfReturn = 0; - let type = ''; + let type = '""'; let rate = 0; let pBOK = false; @@ -423,7 +423,7 @@ if ( percentgeBandwidth.value >= 70 && lastOperation === 'Buy' && - (percentgeBandwidthMap.get(candles[i - 2].begin).movingAverage > percentgeBandwidthMap.get(candles[i - 1].begin).movingAverage) && + // (percentgeBandwidthMap.get(candles[i - 2].begin).movingAverage > percentgeBandwidthMap.get(candles[i - 1].begin).movingAverage) && (percentgeBandwidthMap.get(candles[i - 1].begin).movingAverage > percentgeBandwidth.movingAverage ) ) { type = '"Pre-Sell"'; From f475c7eb1af0eeb46160a39d7659455456fe4db0 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 25 Feb 2019 03:05:05 +0100 Subject: [PATCH 007/244] sellRate to plotter --- Multi-Period-Market/User.Bot.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 1b4e40220..8b60b9b1b 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -377,7 +377,7 @@ let trailingStop = false; let stopLoss = 0; let stopLossDecay = 0; - let stopLossDecayIncrement = 0.05; + let stopLossDecayIncrement = 0.06; let initialBalanceA = 1; let record; @@ -543,7 +543,8 @@ } /* Not a buy or sell condition */ - + + rate = candle.close; addRecord(); function addRecord() { @@ -566,14 +567,20 @@ ROI: ROI, periods: periods, days: days, - anualizedRateOfReturn: anualizedRateOfReturn + anualizedRateOfReturn: anualizedRateOfReturn, + sellRate: sellRate } recordsArray.push(record); previousStopLoss = stopLoss; - stopLossDecay = stopLossDecay + stopLossDecayIncrement; + if (bollingerBandsMap.get(candles[i - 1].begin).movingAverage < band.movingAverage) { + stopLossDecay = stopLossDecay + stopLossDecayIncrement * 2; + } else { + stopLossDecay = stopLossDecay - stopLossDecayIncrement / 2; + } + type = '""'; } @@ -620,7 +627,8 @@ record.ROI + "," + record.periods + "," + record.days + "," + - record.anualizedRateOfReturn + "]"; + record.anualizedRateOfReturn + "," + + record.sellRate + "]"; if (separator === "") { separator = ","; } From 06124085f8e62eb7f4d6a3955d47243d1757f285 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 25 Feb 2019 03:55:26 +0100 Subject: [PATCH 008/244] % profit --- Multi-Period-Market/User.Bot.js | 69 ++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 8b60b9b1b..2e956d046 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -372,7 +372,7 @@ /* Building records */ - let stopLossPercentage = 2; + let stopLossPercentage = 1; let previousStopLoss = 0; let trailingStop = false; let stopLoss = 0; @@ -387,6 +387,7 @@ let balanceAssetB = 0; let profit = 0; let lastProfit = 0; + let lastProfitPercent = 0; let sellRate = 0; let previousBalanceAssetA = 0; @@ -418,48 +419,78 @@ periods++; + let band1 = bollingerBandsMap.get(candles[i - 1].begin); + let band2 = bollingerBandsMap.get(candles[i - 2].begin); + let band3 = bollingerBandsMap.get(candles[i - 3].begin); + + let percentgeBandwidth1 = percentgeBandwidthMap.get(candles[i - 1].begin); + let percentgeBandwidth2 = percentgeBandwidthMap.get(candles[i - 2].begin); + let percentgeBandwidth3 = percentgeBandwidthMap.get(candles[i - 3].begin); + /* PB Coming Down from the roof enables condition to sell */ if ( percentgeBandwidth.value >= 70 && lastOperation === 'Buy' && - // (percentgeBandwidthMap.get(candles[i - 2].begin).movingAverage > percentgeBandwidthMap.get(candles[i - 1].begin).movingAverage) && - (percentgeBandwidthMap.get(candles[i - 1].begin).movingAverage > percentgeBandwidth.movingAverage ) + (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage ) ) { type = '"Pre-Sell"'; pBOK = true; }; - /* Sell Condition */ + let mustSell = false; + + /* Sell Condition #1 */ if ( pBOK === true && - bollingerBandsMap.get(candles[i - 2].begin).movingAverage > bollingerBandsMap.get(candles[i - 1].begin).movingAverage && - bollingerBandsMap.get(candles[i - 1].begin).movingAverage > band.movingAverage && + band2.movingAverage > band1.movingAverage && + band1.movingAverage > band.movingAverage && + lastOperation === 'Buy' + ) { + + type = '"Sell-1"'; + mustSell = true; + } + + /* Sell Condition #2 */ + + if ( + candles[i - 3].min < band3.movingAverage - band3.deviation && + candles[i - 2].min < band2.movingAverage - band2.deviation && + candles[i - 1].min < band1.movingAverage - band1.deviation && + candle.min < band.movingAverage - band.deviation && lastOperation === 'Buy' ) { + type = '"Sell-2"'; + mustSell = true; + + } + + if (mustSell === true) { + previousBalanceAssetA = balanceAssetA; lastProfit = 0; + lastProfitPercent = 0; balanceAssetB = balanceAssetA * candle.close; balanceAssetA = 0; - + rate = candle.close; sellRate = rate; stopLoss = sellRate + sellRate * stopLossPercentage / 100; - type = '"Sell"'; lastOperation = 'Sell'; pBOK = false; stopLossDecay = 0; addRecord(); + mustSell = false; continue; - } /* Start Trailing Stop Condition */ @@ -467,7 +498,7 @@ if ( candle.max < band.movingAverage && lastOperation === 'Sell' && - (bollingerBandsMap.get(candles[i - 1].begin).movingAverage > band.movingAverage) && + band1.movingAverage > band.movingAverage && (candle.min < band.movingAverage - band.deviation) ) { @@ -500,17 +531,6 @@ mustBuy = true; } - /* Buy condition */ - /* - if (percentgeBandwidth.value <= 50 && lastOperation === 'Sell' && mustBuy === false) { - - balanceAssetA = balanceAssetB / candle.close; - balanceAssetB = 0; - rate = candle.close; - mustBuy = true; - }; - */ - if (mustBuy === true) { stopLoss = 0; @@ -519,6 +539,7 @@ roundtrips++; lastProfit = balanceAssetA - previousBalanceAssetA; + lastProfitPercent = lastProfit / previousBalanceAssetA * 100; profit = profit + lastProfit; ROI = (initialBalanceA + profit) / initialBalanceA - 1; @@ -568,7 +589,8 @@ periods: periods, days: days, anualizedRateOfReturn: anualizedRateOfReturn, - sellRate: sellRate + sellRate: sellRate, + lastProfitPercent: lastProfitPercent } recordsArray.push(record); @@ -628,7 +650,8 @@ record.periods + "," + record.days + "," + record.anualizedRateOfReturn + "," + - record.sellRate + "]"; + record.sellRate + "," + + record.lastProfitPercent + "]"; if (separator === "") { separator = ","; } From ef8aa6e40e217343aba66435a82a158b8e2be2f2 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 25 Feb 2019 17:42:02 +0100 Subject: [PATCH 009/244] Experimenting with stoploss size --- Multi-Period-Market/User.Bot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 2e956d046..b7fc2c96b 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -372,7 +372,7 @@ /* Building records */ - let stopLossPercentage = 1; + let stopLossPercentage = 1.5; let previousStopLoss = 0; let trailingStop = false; let stopLoss = 0; From 93a6cc05803e529b0684b5a0d54812bb29f70e30 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 25 Feb 2019 20:38:57 +0100 Subject: [PATCH 010/244] Tyding code, comments --- Multi-Period-Market/User.Bot.js | 88 ++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 34 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index b7fc2c96b..6acc84af6 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -370,6 +370,12 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildRecords -> Entering function."); } + /* Initial Values */ + + let lastOperation = 'Buy'; + let initialDate = new Date("2018-08-01"); + let initialBalanceA = 1; + /* Building records */ let stopLossPercentage = 1.5; @@ -379,10 +385,7 @@ let stopLossDecay = 0; let stopLossDecayIncrement = 0.06; - let initialBalanceA = 1; let record; - let lastOperation = 'Buy'; - let initialDate = new Date("2018-08-01"); let balanceAssetA = initialBalanceA; let balanceAssetB = 0; let profit = 0; @@ -400,21 +403,22 @@ let days = 0; let anualizedRateOfReturn = 0; let type = '""'; + let signal = '""'; let rate = 0; - let pBOK = false; + let presellModeIsActive = false; let initialBuffer = 3; + /* Main Simulation Loop: We go thourgh all the candles at this time period. */ + for (let i = 0 + initialBuffer; i < candles.length; i++) { let candle = candles[i]; let percentgeBandwidth = percentgeBandwidthMap.get(candle.begin); let band = bollingerBandsMap.get(candle.begin); - - if (percentgeBandwidth === undefined) { continue;} - + if (percentgeBandwidth === undefined) { continue;} // percentageBandwidth might start after the first few candles. if (candle.begin < initialDate.valueOf()) { continue; } periods++; @@ -427,31 +431,39 @@ let percentgeBandwidth2 = percentgeBandwidthMap.get(candles[i - 2].begin); let percentgeBandwidth3 = percentgeBandwidthMap.get(candles[i - 3].begin); - /* PB Coming Down from the roof enables condition to sell */ + /* Strategy #1: Range Trading. */ + /* + Strategy Summary: Once Percentage Bandwidth (PB) moving average is going dow and + it is abobe 70%, we enter into Pre-Sell mode, which means that we are ready to + sell as soon as the trend starts going down. The trend should be measured by the + Bollinger Bands moving average. + */ + if ( percentgeBandwidth.value >= 70 && lastOperation === 'Buy' && - (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage ) + (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) && + presellModeIsActive === false ) { - type = '"Pre-Sell"'; - pBOK = true; + signal = '"Pre-Sell"'; + presellModeIsActive = true; }; - let mustSell = false; + let sellSignalActivated = false; /* Sell Condition #1 */ if ( - pBOK === true && + presellModeIsActive === true && band2.movingAverage > band1.movingAverage && band1.movingAverage > band.movingAverage && lastOperation === 'Buy' ) { type = '"Sell-1"'; - mustSell = true; + sellSignalActivated = true; } /* Sell Condition #2 */ @@ -465,11 +477,11 @@ ) { type = '"Sell-2"'; - mustSell = true; + sellSignalActivated = true; } - if (mustSell === true) { + if (sellSignalActivated === true) { previousBalanceAssetA = balanceAssetA; lastProfit = 0; @@ -484,12 +496,12 @@ stopLoss = sellRate + sellRate * stopLossPercentage / 100; lastOperation = 'Sell'; - pBOK = false; + presellModeIsActive = false; stopLossDecay = 0; addRecord(); - mustSell = false; + sellSignalActivated = false; continue; } @@ -499,39 +511,44 @@ candle.max < band.movingAverage && lastOperation === 'Sell' && band1.movingAverage > band.movingAverage && - (candle.min < band.movingAverage - band.deviation) + candle.min < band.movingAverage - band.deviation ) { trailingStop = true; } + /* Stop Loss Management: Initially it is tied to the sell rate but when it enters + into trailing mode it follows the moving average of the band.*/ + + let newStopLoss; + if (trailingStop === true) { - - let newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } + newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; } else { - stopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; + newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; + } + /* A trailing stop loss can never go higher. */ + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; } - /* Stop Loss condition */ + /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - let mustBuy = false; + let buySignalActivated = false; if (candle.max >= stopLoss && lastOperation === 'Sell') { balanceAssetA = balanceAssetB / stopLoss; balanceAssetB = 0; rate = stopLoss; - mustBuy = true; + buySignalActivated = true; } - if (mustBuy === true) { + if (buySignalActivated === true) { stopLoss = 0; sellRate = 0; @@ -590,7 +607,8 @@ days: days, anualizedRateOfReturn: anualizedRateOfReturn, sellRate: sellRate, - lastProfitPercent: lastProfitPercent + lastProfitPercent: lastProfitPercent, + signal: signal } recordsArray.push(record); @@ -604,6 +622,7 @@ } type = '""'; + signal = '""'; } } @@ -651,7 +670,8 @@ record.days + "," + record.anualizedRateOfReturn + "," + record.sellRate + "," + - record.lastProfitPercent + "]"; + record.lastProfitPercent + "," + + record.signal + "]"; if (separator === "") { separator = ","; } From 45dbbf8c9d17fed2b23092dbc032d75291869662 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 26 Feb 2019 15:59:38 +0100 Subject: [PATCH 011/244] Strategy and Stratey Phase added --- Multi-Period-Market/User.Bot.js | 230 ++++++++++++++++++++------------ 1 file changed, 144 insertions(+), 86 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 6acc84af6..79b564180 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -376,6 +376,11 @@ let initialDate = new Date("2018-08-01"); let initialBalanceA = 1; + /* Strategy and Phases */ + + let strategy = 0; + let strategyPhase = 0; + /* Building records */ let stopLossPercentage = 1.5; @@ -431,110 +436,159 @@ let percentgeBandwidth2 = percentgeBandwidthMap.get(candles[i - 2].begin); let percentgeBandwidth3 = percentgeBandwidthMap.get(candles[i - 3].begin); - /* Strategy #1: Range Trading. */ + if (strategy === 0) { - /* - Strategy Summary: Once Percentage Bandwidth (PB) moving average is going dow and - it is abobe 70%, we enter into Pre-Sell mode, which means that we are ready to - sell as soon as the trend starts going down. The trend should be measured by the - Bollinger Bands moving average. - */ - - if ( - percentgeBandwidth.value >= 70 && - lastOperation === 'Buy' && - (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) && - presellModeIsActive === false - ) { - signal = '"Pre-Sell"'; - presellModeIsActive = true; + /* + 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 need a new indicator called Bollinger Channels, + which I dont have right now, so for the time being, I will choose the strategy + manually. + */ - let sellSignalActivated = false; - - /* Sell Condition #1 */ - - if ( - presellModeIsActive === true && - band2.movingAverage > band1.movingAverage && - band1.movingAverage > band.movingAverage && - lastOperation === 'Buy' - ) { - - type = '"Sell-1"'; - sellSignalActivated = true; + strategy = 1; } - /* Sell Condition #2 */ + if (strategy === 1) { - if ( - candles[i - 3].min < band3.movingAverage - band3.deviation && - candles[i - 2].min < band2.movingAverage - band2.deviation && - candles[i - 1].min < band1.movingAverage - band1.deviation && - candle.min < band.movingAverage - band.deviation && - lastOperation === 'Buy' - ) { + /* Strategy #1: Trend Following. */ - type = '"Sell-2"'; - sellSignalActivated = true; + /* + Strategy Summary: + + Once Percentage Bandwidth (PB) moving average is going down and + it is abobe 70%, we enter into Pre-Sell mode, which means that we are ready to + sell as soon as the trend starts going down. The trend should be measured by the + Bollinger Bands moving average. + + Once the band's moving average starts going down we Sell and we set the stop loss, + which initially is static or going down if the prices starts going up too. + + Once the candles minimun goes out of the lower Bollinger band, we enter into stop loss + trailing mode, which means that the stop loss will follow the band's moving average + from there on, getting closer or farther from it depending on the slope of the moving average + itself. + + */ - } + if ( + percentgeBandwidth.value >= 70 && + lastOperation === 'Buy' && + (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) && + presellModeIsActive === false + ) { + signal = '"Pre-Sell"'; + presellModeIsActive = true; - if (sellSignalActivated === true) { + }; - previousBalanceAssetA = balanceAssetA; - lastProfit = 0; - lastProfitPercent = 0; + let sellSignalActivated = false; - balanceAssetB = balanceAssetA * candle.close; - balanceAssetA = 0; + /* Sell Condition #1 */ - rate = candle.close; - sellRate = rate; - - stopLoss = sellRate + sellRate * stopLossPercentage / 100; - - lastOperation = 'Sell'; - presellModeIsActive = false; - stopLossDecay = 0; - - addRecord(); - - sellSignalActivated = false; - continue; - } - - /* Start Trailing Stop Condition */ - - if ( - candle.max < band.movingAverage && - lastOperation === 'Sell' && - band1.movingAverage > band.movingAverage && - candle.min < band.movingAverage - band.deviation + if ( + presellModeIsActive === true && + band2.movingAverage > band1.movingAverage && + band1.movingAverage > band.movingAverage && + lastOperation === 'Buy' ) { - trailingStop = true; - + type = '"Sell-1"'; + sellSignalActivated = true; + } + + /* Sell Condition #2 */ + + if ( + candles[i - 3].min < band3.movingAverage - band3.deviation && + candles[i - 2].min < band2.movingAverage - band2.deviation && + candles[i - 1].min < band1.movingAverage - band1.deviation && + candle.min < band.movingAverage - band.deviation && + lastOperation === 'Buy' + ) { + + type = '"Sell-2"'; + sellSignalActivated = true; + + } + + if (sellSignalActivated === true) { + + previousBalanceAssetA = balanceAssetA; + lastProfit = 0; + lastProfitPercent = 0; + + balanceAssetB = balanceAssetA * candle.close; + balanceAssetA = 0; + + rate = candle.close; + sellRate = rate; + + stopLoss = sellRate + sellRate * stopLossPercentage / 100; + + lastOperation = 'Sell'; + presellModeIsActive = false; + stopLossDecay = 0; + + addRecord(); + + sellSignalActivated = false; + continue; + } + + /* Start Trailing Stop Condition */ + + if ( + candle.max < band.movingAverage && + lastOperation === 'Sell' && + band1.movingAverage > band.movingAverage && + candle.min < band.movingAverage - band.deviation + ) { + + trailingStop = true; + + } + + /* Stop Loss Management: Initially it is tied to the sell rate but when it enters + into trailing mode it follows the moving average of the band.*/ + + let newStopLoss; + + if (trailingStop === true) { + newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; + } else { + newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; + } + /* A trailing stop loss can never go higher. */ + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } + } - /* Stop Loss Management: Initially it is tied to the sell rate but when it enters - into trailing mode it follows the moving average of the band.*/ + if (strategy === 2) { - let newStopLoss; + /* Strategy #2: Range Trading. */ - if (trailingStop === true) { - newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; - } else { - newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; + /* + Strategy Summary: + + Once the candles maximun gets above the Bollinger Upper Band we wait until the B% moving average points + downward and then we Sell. + + We keep our buy order just below the the Bollinger Bands moving average. + + */ } - /* A trailing stop loss can never go higher. */ + - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } + + + /* Common Logic */ /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ @@ -608,7 +662,9 @@ anualizedRateOfReturn: anualizedRateOfReturn, sellRate: sellRate, lastProfitPercent: lastProfitPercent, - signal: signal + signal: signal, + strategy: 0, + strategyPhase: 0 } recordsArray.push(record); @@ -671,7 +727,9 @@ record.anualizedRateOfReturn + "," + record.sellRate + "," + record.lastProfitPercent + "," + - record.signal + "]"; + record.signal + "," + + record.strategy + "," + + record.strategyPhase + "]"; if (separator === "") { separator = ","; } From 3d13adeef8cfaee50cb72ab7dd6c2ba4131c3d75 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 26 Feb 2019 22:46:01 +0100 Subject: [PATCH 012/244] Strategies and Phases working --- Multi-Period-Market/User.Bot.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 79b564180..da9cdf057 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -480,6 +480,7 @@ ) { signal = '"Pre-Sell"'; presellModeIsActive = true; + strategyPhase = 1; }; @@ -496,6 +497,7 @@ type = '"Sell-1"'; sellSignalActivated = true; + strategyPhase = 2; } /* Sell Condition #2 */ @@ -510,7 +512,7 @@ type = '"Sell-2"'; sellSignalActivated = true; - + strategyPhase = 2; } if (sellSignalActivated === true) { @@ -546,6 +548,7 @@ candle.min < band.movingAverage - band.deviation ) { + strategyPhase = 3; trailingStop = true; } @@ -627,6 +630,7 @@ type = '"Buy"'; lastOperation = 'Buy'; + strategy = 0; addRecord(); @@ -663,8 +667,8 @@ sellRate: sellRate, lastProfitPercent: lastProfitPercent, signal: signal, - strategy: 0, - strategyPhase: 0 + strategy: strategy, + strategyPhase: strategyPhase } recordsArray.push(record); From afaed2f5778953bd7e808aa3216e07d63f0b38c1 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 27 Feb 2019 08:28:07 +0100 Subject: [PATCH 013/244] Simulation Function Separated --- Multi-Period-Market/User.Bot.js | 666 ++++++++++++++++---------------- 1 file changed, 334 insertions(+), 332 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index da9cdf057..271d9ebb0 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -355,7 +355,7 @@ } - buildRecords(); + runSimulation(candles, bollingerBandsMap, percentgeBandwidthMap, recordsArray, outputPeriod, writeRecordsFile) } catch (err) { @@ -364,337 +364,6 @@ } } - function buildRecords() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildRecords -> Entering function."); } - - /* Initial Values */ - - let lastOperation = 'Buy'; - let initialDate = new Date("2018-08-01"); - let initialBalanceA = 1; - - /* Strategy and Phases */ - - let strategy = 0; - let strategyPhase = 0; - - /* Building records */ - - let stopLossPercentage = 1.5; - let previousStopLoss = 0; - let trailingStop = false; - let stopLoss = 0; - let stopLossDecay = 0; - let stopLossDecayIncrement = 0.06; - - let record; - let balanceAssetA = initialBalanceA; - let balanceAssetB = 0; - let profit = 0; - let lastProfit = 0; - let lastProfitPercent = 0; - let sellRate = 0; - - let previousBalanceAssetA = 0; - let roundtrips = 0; - let hits = 0; - let fails = 0; - let hitRatio = 0; - let ROI = 0; - let periods = 0; - let days = 0; - let anualizedRateOfReturn = 0; - let type = '""'; - let signal = '""'; - let rate = 0; - - let presellModeIsActive = false; - - let initialBuffer = 3; - - /* Main Simulation Loop: We go thourgh all the candles at this time period. */ - - for (let i = 0 + initialBuffer; i < candles.length; i++) { - - let candle = candles[i]; - let percentgeBandwidth = percentgeBandwidthMap.get(candle.begin); - let band = bollingerBandsMap.get(candle.begin); - - if (percentgeBandwidth === undefined) { continue;} // percentageBandwidth might start after the first few candles. - if (candle.begin < initialDate.valueOf()) { continue; } - - periods++; - - let band1 = bollingerBandsMap.get(candles[i - 1].begin); - let band2 = bollingerBandsMap.get(candles[i - 2].begin); - let band3 = bollingerBandsMap.get(candles[i - 3].begin); - - let percentgeBandwidth1 = percentgeBandwidthMap.get(candles[i - 1].begin); - let percentgeBandwidth2 = percentgeBandwidthMap.get(candles[i - 2].begin); - let percentgeBandwidth3 = percentgeBandwidthMap.get(candles[i - 3].begin); - - if (strategy === 0) { - - /* - 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 need a new indicator called Bollinger Channels, - which I dont have right now, so for the time being, I will choose the strategy - manually. - */ - - strategy = 1; - } - - if (strategy === 1) { - - /* Strategy #1: Trend Following. */ - - /* - Strategy Summary: - - Once Percentage Bandwidth (PB) moving average is going down and - it is abobe 70%, we enter into Pre-Sell mode, which means that we are ready to - sell as soon as the trend starts going down. The trend should be measured by the - Bollinger Bands moving average. - - Once the band's moving average starts going down we Sell and we set the stop loss, - which initially is static or going down if the prices starts going up too. - - Once the candles minimun goes out of the lower Bollinger band, we enter into stop loss - trailing mode, which means that the stop loss will follow the band's moving average - from there on, getting closer or farther from it depending on the slope of the moving average - itself. - - */ - - if ( - percentgeBandwidth.value >= 70 && - lastOperation === 'Buy' && - (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) && - presellModeIsActive === false - ) { - signal = '"Pre-Sell"'; - presellModeIsActive = true; - strategyPhase = 1; - - }; - - let sellSignalActivated = false; - - /* Sell Condition #1 */ - - if ( - presellModeIsActive === true && - band2.movingAverage > band1.movingAverage && - band1.movingAverage > band.movingAverage && - lastOperation === 'Buy' - ) { - - type = '"Sell-1"'; - sellSignalActivated = true; - strategyPhase = 2; - } - - /* Sell Condition #2 */ - - if ( - candles[i - 3].min < band3.movingAverage - band3.deviation && - candles[i - 2].min < band2.movingAverage - band2.deviation && - candles[i - 1].min < band1.movingAverage - band1.deviation && - candle.min < band.movingAverage - band.deviation && - lastOperation === 'Buy' - ) { - - type = '"Sell-2"'; - sellSignalActivated = true; - strategyPhase = 2; - } - - if (sellSignalActivated === true) { - - previousBalanceAssetA = balanceAssetA; - lastProfit = 0; - lastProfitPercent = 0; - - balanceAssetB = balanceAssetA * candle.close; - balanceAssetA = 0; - - rate = candle.close; - sellRate = rate; - - stopLoss = sellRate + sellRate * stopLossPercentage / 100; - - lastOperation = 'Sell'; - presellModeIsActive = false; - stopLossDecay = 0; - - addRecord(); - - sellSignalActivated = false; - continue; - } - - /* Start Trailing Stop Condition */ - - if ( - candle.max < band.movingAverage && - lastOperation === 'Sell' && - band1.movingAverage > band.movingAverage && - candle.min < band.movingAverage - band.deviation - ) { - - strategyPhase = 3; - trailingStop = true; - - } - - /* Stop Loss Management: Initially it is tied to the sell rate but when it enters - into trailing mode it follows the moving average of the band.*/ - - let newStopLoss; - - if (trailingStop === true) { - newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; - } else { - newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; - } - /* A trailing stop loss can never go higher. */ - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } - - } - - if (strategy === 2) { - - /* Strategy #2: Range Trading. */ - - /* - Strategy Summary: - - Once the candles maximun gets above the Bollinger Upper Band we wait until the B% moving average points - downward and then we Sell. - - We keep our buy order just below the the Bollinger Bands moving average. - - */ - } - - - - - /* Common Logic */ - - /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - - let buySignalActivated = false; - - if (candle.max >= stopLoss && lastOperation === 'Sell') { - - balanceAssetA = balanceAssetB / stopLoss; - balanceAssetB = 0; - rate = stopLoss; - buySignalActivated = true; - } - - if (buySignalActivated === true) { - - stopLoss = 0; - sellRate = 0; - trailingStop = false; - - roundtrips++; - lastProfit = balanceAssetA - previousBalanceAssetA; - lastProfitPercent = lastProfit / previousBalanceAssetA * 100; - profit = profit + lastProfit; - ROI = (initialBalanceA + profit) / initialBalanceA - 1; - - if (lastProfit > 0) { - hits++; - } else { - fails++; - } - hitRatio = hits / roundtrips; - - let miliSecondsPerDay = 24 * 60 * 60 * 1000; - days = periods * outputPeriod / miliSecondsPerDay; - anualizedRateOfReturn = ROI / days * 365; - - type = '"Buy"'; - lastOperation = 'Buy'; - strategy = 0; - - addRecord(); - - continue; - - } - - /* Not a buy or sell condition */ - - rate = candle.close; - addRecord(); - - function addRecord() { - - record = { - begin: candle.begin, - end: candle.end, - type: type, - rate: rate, - amount: 1, - balanceA: balanceAssetA, - balanceB: balanceAssetB, - profit: profit, - lastProfit: lastProfit, - stopLoss: stopLoss, - roundtrips: roundtrips, - hits: hits, - fails: fails, - hitRatio: hitRatio, - ROI: ROI, - periods: periods, - days: days, - anualizedRateOfReturn: anualizedRateOfReturn, - sellRate: sellRate, - lastProfitPercent: lastProfitPercent, - signal: signal, - strategy: strategy, - strategyPhase: strategyPhase - } - - recordsArray.push(record); - - previousStopLoss = stopLoss; - - if (bollingerBandsMap.get(candles[i - 1].begin).movingAverage < band.movingAverage) { - stopLossDecay = stopLossDecay + stopLossDecayIncrement * 2; - } else { - stopLossDecay = stopLossDecay - stopLossDecayIncrement / 2; - } - - type = '""'; - signal = '""'; - - } - } - - writeRecordsFile(); - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildRecords -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - function writeRecordsFile() { try { @@ -839,7 +508,340 @@ callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } + + function runSimulation(candles, bollingerBandsMap, percentgeBandwidthMap, recordsArray, outputPeriod, callback) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> runSimulation -> Entering function."); } + + /* Initial Values */ + + let lastOperation = 'Buy'; + let initialDate = new Date("2018-08-01"); + let initialBalanceA = 1; + + /* Strategy and Phases */ + + let strategy = 0; + let strategyPhase = 0; + + /* Building records */ + + let stopLossPercentage = 1.5; + let previousStopLoss = 0; + let trailingStop = false; + let stopLoss = 0; + let stopLossDecay = 0; + let stopLossDecayIncrement = 0.06; + + let record; + let balanceAssetA = initialBalanceA; + let balanceAssetB = 0; + let profit = 0; + let lastProfit = 0; + let lastProfitPercent = 0; + let sellRate = 0; + + let previousBalanceAssetA = 0; + let roundtrips = 0; + let hits = 0; + let fails = 0; + let hitRatio = 0; + let ROI = 0; + let periods = 0; + let days = 0; + let anualizedRateOfReturn = 0; + let type = '""'; + let signal = '""'; + let rate = 0; + + let presellModeIsActive = false; + + let initialBuffer = 3; + + /* Main Simulation Loop: We go thourgh all the candles at this time period. */ + + for (let i = 0 + initialBuffer; i < candles.length; i++) { + + let candle = candles[i]; + let percentgeBandwidth = percentgeBandwidthMap.get(candle.begin); + let band = bollingerBandsMap.get(candle.begin); + + if (percentgeBandwidth === undefined) { continue; } // percentageBandwidth might start after the first few candles. + if (candle.begin < initialDate.valueOf()) { continue; } + + periods++; + + let band1 = bollingerBandsMap.get(candles[i - 1].begin); + let band2 = bollingerBandsMap.get(candles[i - 2].begin); + let band3 = bollingerBandsMap.get(candles[i - 3].begin); + + let percentgeBandwidth1 = percentgeBandwidthMap.get(candles[i - 1].begin); + let percentgeBandwidth2 = percentgeBandwidthMap.get(candles[i - 2].begin); + let percentgeBandwidth3 = percentgeBandwidthMap.get(candles[i - 3].begin); + + if (strategy === 0) { + + /* + 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 need a new indicator called Bollinger Channels, + which I dont have right now, so for the time being, I will choose the strategy + manually. + */ + + strategy = 1; + } + + if (strategy === 1) { + + /* Strategy #1: Trend Following. */ + + /* + Strategy Summary: + + Once Percentage Bandwidth (PB) moving average is going down and + it is abobe 70%, we enter into Pre-Sell mode, which means that we are ready to + sell as soon as the trend starts going down. The trend should be measured by the + Bollinger Bands moving average. + + Once the band's moving average starts going down we Sell and we set the stop loss, + which initially is static or going down if the prices starts going up too. + + Once the candles minimun goes out of the lower Bollinger band, we enter into stop loss + trailing mode, which means that the stop loss will follow the band's moving average + from there on, getting closer or farther from it depending on the slope of the moving average + itself. + + */ + + if ( + percentgeBandwidth.value >= 70 && + lastOperation === 'Buy' && + (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) && + presellModeIsActive === false + ) { + signal = '"Pre-Sell"'; + presellModeIsActive = true; + strategyPhase = 1; + + }; + + let sellSignalActivated = false; + + /* Sell Condition #1 */ + + if ( + presellModeIsActive === true && + band2.movingAverage > band1.movingAverage && + band1.movingAverage > band.movingAverage && + lastOperation === 'Buy' + ) { + + type = '"Sell-1"'; + sellSignalActivated = true; + strategyPhase = 2; + } + + /* Sell Condition #2 */ + + if ( + candles[i - 3].min < band3.movingAverage - band3.deviation && + candles[i - 2].min < band2.movingAverage - band2.deviation && + candles[i - 1].min < band1.movingAverage - band1.deviation && + candle.min < band.movingAverage - band.deviation && + lastOperation === 'Buy' + ) { + + type = '"Sell-2"'; + sellSignalActivated = true; + strategyPhase = 2; + } + + if (sellSignalActivated === true) { + + previousBalanceAssetA = balanceAssetA; + lastProfit = 0; + lastProfitPercent = 0; + + balanceAssetB = balanceAssetA * candle.close; + balanceAssetA = 0; + + rate = candle.close; + sellRate = rate; + + stopLoss = sellRate + sellRate * stopLossPercentage / 100; + + lastOperation = 'Sell'; + presellModeIsActive = false; + stopLossDecay = 0; + + addRecord(); + + sellSignalActivated = false; + continue; + } + + /* Start Trailing Stop Condition */ + + if ( + candle.max < band.movingAverage && + lastOperation === 'Sell' && + band1.movingAverage > band.movingAverage && + candle.min < band.movingAverage - band.deviation + ) { + + strategyPhase = 3; + trailingStop = true; + + } + + /* Stop Loss Management: Initially it is tied to the sell rate but when it enters + into trailing mode it follows the moving average of the band.*/ + + let newStopLoss; + + if (trailingStop === true) { + newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; + } else { + newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; + } + /* A trailing stop loss can never go higher. */ + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } + + } + + if (strategy === 2) { + + /* Strategy #2: Range Trading. */ + + /* + Strategy Summary: + + Once the candles maximun gets above the Bollinger Upper Band we wait until the B% moving average points + downward and then we Sell. + + We keep our buy order just below the the Bollinger Bands moving average. + + */ + } + + + + + /* Common Logic */ + + /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ + + let buySignalActivated = false; + + if (candle.max >= stopLoss && lastOperation === 'Sell') { + + balanceAssetA = balanceAssetB / stopLoss; + balanceAssetB = 0; + rate = stopLoss; + buySignalActivated = true; + } + + if (buySignalActivated === true) { + + stopLoss = 0; + sellRate = 0; + trailingStop = false; + + roundtrips++; + lastProfit = balanceAssetA - previousBalanceAssetA; + lastProfitPercent = lastProfit / previousBalanceAssetA * 100; + profit = profit + lastProfit; + ROI = (initialBalanceA + profit) / initialBalanceA - 1; + + if (lastProfit > 0) { + hits++; + } else { + fails++; + } + hitRatio = hits / roundtrips; + + let miliSecondsPerDay = 24 * 60 * 60 * 1000; + days = periods * outputPeriod / miliSecondsPerDay; + anualizedRateOfReturn = ROI / days * 365; + + type = '"Buy"'; + lastOperation = 'Buy'; + strategy = 0; + + addRecord(); + + continue; + + } + + /* Not a buy or sell condition */ + + rate = candle.close; + addRecord(); + + function addRecord() { + + record = { + begin: candle.begin, + end: candle.end, + type: type, + rate: rate, + amount: 1, + balanceA: balanceAssetA, + balanceB: balanceAssetB, + profit: profit, + lastProfit: lastProfit, + stopLoss: stopLoss, + roundtrips: roundtrips, + hits: hits, + fails: fails, + hitRatio: hitRatio, + ROI: ROI, + periods: periods, + days: days, + anualizedRateOfReturn: anualizedRateOfReturn, + sellRate: sellRate, + lastProfitPercent: lastProfitPercent, + signal: signal, + strategy: strategy, + strategyPhase: strategyPhase + } + + recordsArray.push(record); + + previousStopLoss = stopLoss; + + if (bollingerBandsMap.get(candles[i - 1].begin).movingAverage < band.movingAverage) { + stopLossDecay = stopLossDecay + stopLossDecayIncrement * 2; + } else { + stopLossDecay = stopLossDecay - stopLossDecayIncrement / 2; + } + + type = '""'; + signal = '""'; + + } + } + + callback(); + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> runSimulation -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); From 797a9fb25fed9990101ef37189b9f3f8260de3f9 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 27 Feb 2019 13:57:36 +0100 Subject: [PATCH 014/244] Buy Order Implemented --- Multi-Period-Market/User.Bot.js | 172 ++++++++++++++++++++++++-------- 1 file changed, 133 insertions(+), 39 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 271d9ebb0..1670f5145 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -402,7 +402,8 @@ record.lastProfitPercent + "," + record.signal + "," + record.strategy + "," + - record.strategyPhase + "]"; + record.strategyPhase + "," + + record.buyOrder + "]"; if (separator === "") { separator = ","; } @@ -526,15 +527,24 @@ let strategy = 0; let strategyPhase = 0; - /* Building records */ + /* Stop Loss Management */ let stopLossPercentage = 1.5; let previousStopLoss = 0; - let trailingStop = false; let stopLoss = 0; let stopLossDecay = 0; let stopLossDecayIncrement = 0.06; + /* Buy Order Management */ + + let buyOrderPercentage = 1; + let previousBuyOrder = 0; + let buyOrder = 0; + let buyOrderDecay = 0; + let buyOrderDecayIncrement = 0.01; + + /* Building records */ + let record; let balanceAssetA = initialBalanceA; let balanceAssetB = 0; @@ -555,6 +565,7 @@ let type = '""'; let signal = '""'; let rate = 0; + let newStopLoss; let presellModeIsActive = false; @@ -660,6 +671,102 @@ strategyPhase = 2; } + if (strategyPhase === 2) { + + buyOrderDecay = buyOrderDecay + buyOrderDecayIncrement; + + buyOrder = band.movingAverage - band.standardDeviation * 10; //+ band.movingAverage - band.standardDeviation * 4 * (buyOrderPercentage + buyOrderDecay) / 100; + + newStopLoss = newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } + + if ( + candle.max < band.movingAverage && + lastOperation === 'Sell' && + band1.movingAverage > band.movingAverage && + candle.min < band.movingAverage - band.deviation + ) { + + strategyPhase = 3; + + } + } + + if (strategyPhase === 3) { + + buyOrder = band.movingAverage - band.standardDeviation * 10; + + newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } + + if ( + percentgeBandwidth1.movingAverage < percentgeBandwidth.movingAverage && + percentgeBandwidth.movingAverage > 0 + ) { + strategyPhase = 4; + } + } + + if (strategyPhase === 4) { + + buyOrder = band.movingAverage - band.standardDeviation * 4; + + newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } + + if (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) { + strategyPhase = 5; + } + } + + if (strategyPhase === 5) { + + buyOrder = band.movingAverage - band.standardDeviation * 3; + + newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } + + if ( + percentgeBandwidth1.movingAverage < percentgeBandwidth.movingAverage && + percentgeBandwidth.movingAverage > 30 + ) { + strategyPhase = 6; + } + } + + if (strategyPhase === 6) { + + buyOrder = band.movingAverage - band.standardDeviation * 2; + + newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } + } + if (sellSignalActivated === true) { previousBalanceAssetA = balanceAssetA; @@ -683,39 +790,6 @@ sellSignalActivated = false; continue; } - - /* Start Trailing Stop Condition */ - - if ( - candle.max < band.movingAverage && - lastOperation === 'Sell' && - band1.movingAverage > band.movingAverage && - candle.min < band.movingAverage - band.deviation - ) { - - strategyPhase = 3; - trailingStop = true; - - } - - /* Stop Loss Management: Initially it is tied to the sell rate but when it enters - into trailing mode it follows the moving average of the band.*/ - - let newStopLoss; - - if (trailingStop === true) { - newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; - } else { - newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; - } - /* A trailing stop loss can never go higher. */ - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } - } if (strategy === 2) { @@ -745,8 +819,22 @@ if (candle.max >= stopLoss && lastOperation === 'Sell') { balanceAssetA = balanceAssetB / stopLoss; + //if (isNaN(balanceAssetA)) { balanceAssetA = 0; } + balanceAssetB = 0; rate = stopLoss; + type = '"Buy@StopLoss"'; + buySignalActivated = true; + } + + if (candle.min <= buyOrder && lastOperation === 'Sell' && buySignalActivated === false) { + + balanceAssetA = balanceAssetB / buyOrder; + //if (isNaN(balanceAssetA)) { balanceAssetA = 0; } + + balanceAssetB = 0; + rate = buyOrder; + type = '"Buy@BuyOrder"'; buySignalActivated = true; } @@ -754,13 +842,19 @@ stopLoss = 0; sellRate = 0; - trailingStop = false; + buyOrder = 0; + strategyPhase = 0; roundtrips++; lastProfit = balanceAssetA - previousBalanceAssetA; + lastProfitPercent = lastProfit / previousBalanceAssetA * 100; + if (isNaN(lastProfitPercent)) { lastProfitPercent = 0; } + profit = profit + lastProfit; + ROI = (initialBalanceA + profit) / initialBalanceA - 1; + //if (isNaN(ROI)) { ROI = 0; } if (lastProfit > 0) { hits++; @@ -773,7 +867,6 @@ days = periods * outputPeriod / miliSecondsPerDay; anualizedRateOfReturn = ROI / days * 365; - type = '"Buy"'; lastOperation = 'Buy'; strategy = 0; @@ -813,7 +906,8 @@ lastProfitPercent: lastProfitPercent, signal: signal, strategy: strategy, - strategyPhase: strategyPhase + strategyPhase: strategyPhase, + buyOrder: buyOrder } recordsArray.push(record); From f3e4639e1f6ad27a04c684e65694cb14354d35ca Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 27 Feb 2019 15:35:36 +0100 Subject: [PATCH 015/244] Common Logic goes up --- Multi-Period-Market/User.Bot.js | 62 ++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 1670f5145..6e27d8c57 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -606,6 +606,38 @@ strategy = 1; } + /* Checking what happened since the last execution. We need to know if the Stop Loss + or our Buy Order were hit. */ + + /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ + + let buySignalActivated = false; + + if (candle.max >= stopLoss && lastOperation === 'Sell') { + + balanceAssetA = balanceAssetB / stopLoss; + //if (isNaN(balanceAssetA)) { balanceAssetA = 0; } + + balanceAssetB = 0; + rate = stopLoss; + type = '"Buy@StopLoss"'; + buySignalActivated = true; + } + + /* Buy Order condition: Here we verify if the Buy Order was filled or not. */ + + if (candle.min <= buyOrder && lastOperation === 'Sell' && buySignalActivated === false) { + + balanceAssetA = balanceAssetB / buyOrder; + //if (isNaN(balanceAssetA)) { balanceAssetA = 0; } + + balanceAssetB = 0; + rate = buyOrder; + type = '"Buy@BuyOrder"'; + buySignalActivated = true; + } + + if (strategy === 1) { /* Strategy #1: Trend Following. */ @@ -810,33 +842,7 @@ - /* Common Logic */ - - /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - - let buySignalActivated = false; - - if (candle.max >= stopLoss && lastOperation === 'Sell') { - - balanceAssetA = balanceAssetB / stopLoss; - //if (isNaN(balanceAssetA)) { balanceAssetA = 0; } - - balanceAssetB = 0; - rate = stopLoss; - type = '"Buy@StopLoss"'; - buySignalActivated = true; - } - - if (candle.min <= buyOrder && lastOperation === 'Sell' && buySignalActivated === false) { - - balanceAssetA = balanceAssetB / buyOrder; - //if (isNaN(balanceAssetA)) { balanceAssetA = 0; } - - balanceAssetB = 0; - rate = buyOrder; - type = '"Buy@BuyOrder"'; - buySignalActivated = true; - } + /* Here we define what to do if the conditions to buy were activated. */ if (buySignalActivated === true) { @@ -914,7 +920,7 @@ previousStopLoss = stopLoss; - if (bollingerBandsMap.get(candles[i - 1].begin).movingAverage < band.movingAverage) { + if (band1.movingAverage < band.movingAverage) { stopLossDecay = stopLossDecay + stopLossDecayIncrement * 2; } else { stopLossDecay = stopLossDecay - stopLossDecayIncrement / 2; From d26c926e98b4bc2cd6eedc65b596645463f507c7 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 27 Feb 2019 17:15:09 +0100 Subject: [PATCH 016/244] Checkpoint: working --- Multi-Period-Market/User.Bot.js | 375 ++++++++++++++++---------------- 1 file changed, 190 insertions(+), 185 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 6e27d8c57..41a783116 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -637,207 +637,212 @@ buySignalActivated = true; } + if (buySignalActivated === false) { - if (strategy === 1) { + if (strategy === 1) { - /* Strategy #1: Trend Following. */ + /* Strategy #1: Trend Following. */ - /* - Strategy Summary: - - Once Percentage Bandwidth (PB) moving average is going down and - it is abobe 70%, we enter into Pre-Sell mode, which means that we are ready to - sell as soon as the trend starts going down. The trend should be measured by the - Bollinger Bands moving average. - - Once the band's moving average starts going down we Sell and we set the stop loss, - which initially is static or going down if the prices starts going up too. - - Once the candles minimun goes out of the lower Bollinger band, we enter into stop loss - trailing mode, which means that the stop loss will follow the band's moving average - from there on, getting closer or farther from it depending on the slope of the moving average - itself. - - */ - - if ( - percentgeBandwidth.value >= 70 && - lastOperation === 'Buy' && - (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) && - presellModeIsActive === false - ) { - signal = '"Pre-Sell"'; - presellModeIsActive = true; - strategyPhase = 1; - - }; - - let sellSignalActivated = false; - - /* Sell Condition #1 */ - - if ( - presellModeIsActive === true && - band2.movingAverage > band1.movingAverage && - band1.movingAverage > band.movingAverage && - lastOperation === 'Buy' - ) { - - type = '"Sell-1"'; - sellSignalActivated = true; - strategyPhase = 2; - } - - /* Sell Condition #2 */ - - if ( - candles[i - 3].min < band3.movingAverage - band3.deviation && - candles[i - 2].min < band2.movingAverage - band2.deviation && - candles[i - 1].min < band1.movingAverage - band1.deviation && - candle.min < band.movingAverage - band.deviation && - lastOperation === 'Buy' - ) { - - type = '"Sell-2"'; - sellSignalActivated = true; - strategyPhase = 2; - } - - if (strategyPhase === 2) { - - buyOrderDecay = buyOrderDecay + buyOrderDecayIncrement; - - buyOrder = band.movingAverage - band.standardDeviation * 10; //+ band.movingAverage - band.standardDeviation * 4 * (buyOrderPercentage + buyOrderDecay) / 100; - - newStopLoss = newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } + /* + Strategy Summary: + + Once Percentage Bandwidth (PB) moving average is going down and + it is abobe 70%, we enter into Pre-Sell mode, which means that we are ready to + sell as soon as the trend starts going down. The trend should be measured by the + Bollinger Bands moving average. + + Once the band's moving average starts going down we Sell and we set the stop loss, + which initially is static or going down if the prices starts going up too. + + Once the candles minimun goes out of the lower Bollinger band, we enter into stop loss + trailing mode, which means that the stop loss will follow the band's moving average + from there on, getting closer or farther from it depending on the slope of the moving average + itself. + + */ if ( - candle.max < band.movingAverage && - lastOperation === 'Sell' && + percentgeBandwidth.value >= 70 && + lastOperation === 'Buy' && + (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) && + presellModeIsActive === false + ) { + signal = '"Pre-Sell"'; + presellModeIsActive = true; + strategyPhase = 1; + + }; + + let sellSignalActivated = false; + + /* Sell Condition #1 */ + + if ( + presellModeIsActive === true && + band2.movingAverage > band1.movingAverage && band1.movingAverage > band.movingAverage && - candle.min < band.movingAverage - band.deviation + lastOperation === 'Buy' ) { - strategyPhase = 3; - + type = '"Sell-1"'; + sellSignalActivated = true; + strategyPhase = 2; } - } - if (strategyPhase === 3) { - - buyOrder = band.movingAverage - band.standardDeviation * 10; - - newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } + /* Sell Condition #2 */ if ( - percentgeBandwidth1.movingAverage < percentgeBandwidth.movingAverage && - percentgeBandwidth.movingAverage > 0 + candles[i - 3].min < band3.movingAverage - band3.deviation && + candles[i - 2].min < band2.movingAverage - band2.deviation && + candles[i - 1].min < band1.movingAverage - band1.deviation && + candle.min < band.movingAverage - band.deviation && + lastOperation === 'Buy' + ) { + + type = '"Sell-2"'; + sellSignalActivated = true; + strategyPhase = 2; + } + + if (strategyPhase === 2) { + + buyOrderDecay = buyOrderDecay + buyOrderDecayIncrement; + + buyOrder = band.movingAverage - band.standardDeviation * 10; //+ band.movingAverage - band.standardDeviation * 4 * (buyOrderPercentage + buyOrderDecay) / 100; + + newStopLoss = newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } + + if ( + candle.max < band.movingAverage && + lastOperation === 'Sell' && + band1.movingAverage > band.movingAverage && + candle.min < band.movingAverage - band.deviation ) { - strategyPhase = 4; + + strategyPhase = 3; + + } + } + + if (strategyPhase === 3) { + + buyOrder = band.movingAverage - band.standardDeviation * 10; + + newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } + + if ( + percentgeBandwidth1.movingAverage < percentgeBandwidth.movingAverage && + percentgeBandwidth.movingAverage > 0 + ) { + strategyPhase = 4; + } + } + + if (strategyPhase === 4) { + + buyOrder = band.movingAverage - band.standardDeviation * 4; + + newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } + + if (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) { + strategyPhase = 5; + } + } + + if (strategyPhase === 5) { + + buyOrder = band.movingAverage - band.standardDeviation * 3; + + newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } + + if ( + percentgeBandwidth1.movingAverage < percentgeBandwidth.movingAverage && + percentgeBandwidth.movingAverage > 30 + ) { + strategyPhase = 6; + } + } + + if (strategyPhase === 6) { + + buyOrder = band.movingAverage - band.standardDeviation * 2; + + newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } + } + + if (sellSignalActivated === true) { + + previousBalanceAssetA = balanceAssetA; + lastProfit = 0; + lastProfitPercent = 0; + + balanceAssetB = balanceAssetA * candle.close; + balanceAssetA = 0; + + rate = candle.close; + sellRate = rate; + + stopLoss = sellRate + sellRate * stopLossPercentage / 100; + + lastOperation = 'Sell'; + presellModeIsActive = false; + stopLossDecay = 0; + + addRecord(); + + sellSignalActivated = false; + continue; } } - if (strategyPhase === 4) { + if (strategy === 2) { - buyOrder = band.movingAverage - band.standardDeviation * 4; + /* Strategy #2: Range Trading. */ - newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } - - if (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) { - strategyPhase = 5; - } + /* + Strategy Summary: + + Once the candles maximun gets above the Bollinger Upper Band we wait until the B% moving average points + downward and then we Sell. + + We keep our buy order just below the the Bollinger Bands moving average. + + */ } - if (strategyPhase === 5) { - - buyOrder = band.movingAverage - band.standardDeviation * 3; - - newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } - - if ( - percentgeBandwidth1.movingAverage < percentgeBandwidth.movingAverage && - percentgeBandwidth.movingAverage > 30 - ) { - strategyPhase = 6; - } - } - - if (strategyPhase === 6) { - - buyOrder = band.movingAverage - band.standardDeviation * 2; - - newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } - } - - if (sellSignalActivated === true) { - - previousBalanceAssetA = balanceAssetA; - lastProfit = 0; - lastProfitPercent = 0; - - balanceAssetB = balanceAssetA * candle.close; - balanceAssetA = 0; - - rate = candle.close; - sellRate = rate; - - stopLoss = sellRate + sellRate * stopLossPercentage / 100; - - lastOperation = 'Sell'; - presellModeIsActive = false; - stopLossDecay = 0; - - addRecord(); - - sellSignalActivated = false; - continue; - } } - if (strategy === 2) { - /* Strategy #2: Range Trading. */ - - /* - Strategy Summary: - - Once the candles maximun gets above the Bollinger Upper Band we wait until the B% moving average points - downward and then we Sell. - - We keep our buy order just below the the Bollinger Bands moving average. - - */ - } @@ -846,11 +851,6 @@ if (buySignalActivated === true) { - stopLoss = 0; - sellRate = 0; - buyOrder = 0; - strategyPhase = 0; - roundtrips++; lastProfit = balanceAssetA - previousBalanceAssetA; @@ -874,10 +874,15 @@ anualizedRateOfReturn = ROI / days * 365; lastOperation = 'Buy'; - strategy = 0; - + addRecord(); + strategy = 0; + stopLoss = 0; + sellRate = 0; + buyOrder = 0; + strategyPhase = 0; + continue; } From 738f2bb493fb8c9d015daac116ee888017839f9d Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 27 Feb 2019 19:49:35 +0100 Subject: [PATCH 017/244] Stop Loss Phases independent from Buy Order Phases --- Multi-Period-Market/User.Bot.js | 112 ++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 42 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 41a783116..fcfdab68d 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -403,7 +403,9 @@ record.signal + "," + record.strategy + "," + record.strategyPhase + "," + - record.buyOrder + "]"; + record.buyOrder + "," + + record.stopLossPhase + "," + + record.buyOrderPhase + "]"; if (separator === "") { separator = ","; } @@ -534,6 +536,7 @@ let stopLoss = 0; let stopLossDecay = 0; let stopLossDecayIncrement = 0.06; + let stopLossPhase = 0; /* Buy Order Management */ @@ -542,6 +545,7 @@ let buyOrder = 0; let buyOrderDecay = 0; let buyOrderDecayIncrement = 0.01; + let buyOrderPhase = 0; /* Building records */ @@ -661,6 +665,9 @@ */ + + + if ( percentgeBandwidth.value >= 70 && lastOperation === 'Buy' && @@ -687,6 +694,8 @@ type = '"Sell-1"'; sellSignalActivated = true; strategyPhase = 2; + stopLossPhase = 1; + buyOrderPhase = 1; } /* Sell Condition #2 */ @@ -702,13 +711,11 @@ type = '"Sell-2"'; sellSignalActivated = true; strategyPhase = 2; + stopLossPhase = 1; + buyOrderPhase = 1; } - if (strategyPhase === 2) { - - buyOrderDecay = buyOrderDecay + buyOrderDecayIncrement; - - buyOrder = band.movingAverage - band.standardDeviation * 10; //+ band.movingAverage - band.standardDeviation * 4 * (buyOrderPercentage + buyOrderDecay) / 100; + if (stopLossPhase === 1) { newStopLoss = newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; @@ -721,18 +728,15 @@ if ( candle.max < band.movingAverage && lastOperation === 'Sell' && - band1.movingAverage > band.movingAverage && - candle.min < band.movingAverage - band.deviation + band1.movingAverage > band.movingAverage ) { - strategyPhase = 3; + stopLossPhase = 2; } } - if (strategyPhase === 3) { - - buyOrder = band.movingAverage - band.standardDeviation * 10; + if (stopLossPhase === 2) { newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; @@ -742,62 +746,82 @@ stopLoss = previousStopLoss; } + if ( + candle.max < band.movingAverage - band.deviation + ) { + stopLossPhase = 3; + } + } + + if (stopLossPhase === 3) { + + newStopLoss = band.movingAverage; + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } + } + + + + + if (buyOrderPhase === 1) { + + buyOrderDecay = buyOrderDecay + buyOrderDecayIncrement; + + buyOrder = band.movingAverage - band.standardDeviation * 10; //+ band.movingAverage - band.standardDeviation * 4 * (buyOrderPercentage + buyOrderDecay) / 100; + + if ( + candle.max < band.movingAverage && + lastOperation === 'Sell' && + band1.movingAverage > band.movingAverage && + candle.min < band.movingAverage - band.deviation + ) { + + buyOrderPhase = 2; + + } + } + + if (buyOrderPhase === 2) { + + buyOrder = band.movingAverage - band.standardDeviation * 10; + if ( percentgeBandwidth1.movingAverage < percentgeBandwidth.movingAverage && percentgeBandwidth.movingAverage > 0 ) { - strategyPhase = 4; + buyOrderPhase = 3; } } - if (strategyPhase === 4) { + if (buyOrderPhase === 3) { buyOrder = band.movingAverage - band.standardDeviation * 4; - newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } - if (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) { - strategyPhase = 5; + buyOrderPhase = 4; } } - if (strategyPhase === 5) { + if (buyOrderPhase === 4) { buyOrder = band.movingAverage - band.standardDeviation * 3; - newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } - if ( percentgeBandwidth1.movingAverage < percentgeBandwidth.movingAverage && percentgeBandwidth.movingAverage > 30 ) { - strategyPhase = 6; + buyOrderPhase = 5; } } - if (strategyPhase === 6) { + if (buyOrderPhase === 5) { buyOrder = band.movingAverage - band.standardDeviation * 2; - newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } } if (sellSignalActivated === true) { @@ -882,6 +906,8 @@ sellRate = 0; buyOrder = 0; strategyPhase = 0; + stopLossPhase = 0; + buyOrderPhase = 0; continue; @@ -918,7 +944,9 @@ signal: signal, strategy: strategy, strategyPhase: strategyPhase, - buyOrder: buyOrder + buyOrder: buyOrder, + stopLossPhase: stopLossPhase, + buyOrderPhase: buyOrderPhase } recordsArray.push(record); From ba054989379052ec43d3303eff3acb7e295a9a0a Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 5 Mar 2019 11:12:44 +0100 Subject: [PATCH 018/244] Reading Channels and SubChannels files --- Multi-Period-Market/User.Bot.js | 187 +++++++++++++++++++++++++++++++- 1 file changed, 184 insertions(+), 3 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index fcfdab68d..2ff259c79 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -9,6 +9,8 @@ const PERCENTAGE_BANDWIDTH_FOLDER_NAME = "Percentage-Bandwidth"; const BOLLINGER_BANDS_FOLDER_NAME = "Bollinger-Bands"; + const BOLLINGER_CHANNELS_FOLDER_NAME = "Bollinger-Channels"; + const BOLLINGER_SUB_CHANNELS_FOLDER_NAME = "Bollinger-Sub-Channels"; const CANDLES_FOLDER_NAME = "Candles"; const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; @@ -119,7 +121,9 @@ let percentgeBandwidthMap = new Map(); let bollingerBandsMap = new Map(); - + let bollingerChannelsArray = []; + let bollingerSubChannelsArray = []; + let candles = []; let recordsArray = []; @@ -265,7 +269,7 @@ } - nextCandlesFile(); + nextBollingerChannels(); } catch (err) { @@ -274,6 +278,163 @@ } } + function nextBollingerChannels() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + BOLLINGER_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildBollingerChannelsArray(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildBollingerChannelsArray() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerChannelsArray -> Entering function."); } + + try { + + for (let i = 0; i < marketFile.length; i++) { + + let bollingerChannel = { + begin: marketFile[i][0], + end: marketFile[i][1], + direction: marketFile[i][2], + period: marketFile[i][3], + firstMovingAverage: marketFile[i][4], + lastMovingAverage: marketFile[i][5], + firstDeviation: marketFile[i][6], + lastDeviation: marketFile[i][7] + }; + + bollingerChannelsArray.push(bollingerChannel); + + } + + nextBollingerSubChannels(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerChannelsArray -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function nextBollingerSubChannels() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + BOLLINGER_SUB_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildBollingerChannelsArray(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildBollingerSubChannelsArray() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerSubChannelsArray -> Entering function."); } + + try { + + for (let i = 0; i < marketFile.length; i++) { + + let bollingerSubChannel = { + begin: marketFile[i][0], + end: marketFile[i][1], + direction: marketFile[i][2], + slope: marketFile[i][3], + period: marketFile[i][4], + firstMovingAverage: marketFile[i][5], + lastMovingAverage: marketFile[i][6], + firstDeviation: marketFile[i][7], + lastDeviation: marketFile[i][8] + }; + + bollingerSubChannelsArray.push(bollingerSubChannel); + + } + + nextCandlesFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerSubChannelsArray -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + function nextCandlesFile() { try { @@ -355,7 +516,15 @@ } - runSimulation(candles, bollingerBandsMap, percentgeBandwidthMap, recordsArray, outputPeriod, writeRecordsFile) + runSimulation( + candles, + bollingerBandsMap, + percentgeBandwidthMap, + bollingerChannelsArray, + bollingerSubChannelsArray, + recordsArray, + outputPeriod, + writeRecordsFile) } catch (err) { @@ -966,6 +1135,18 @@ } callback(); + + function getElement(pArray, begin, end) { + + for (let i = 0; i < pArray.length; i++) { + + let element = pArray[i]; + + if (begin >= element.begin && end <= element.end) { + return element + } + } + } } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> runSimulation -> err = " + err.message); From 03f0e8ad8c71af560f49a905084d057190a0242c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 5 Mar 2019 11:36:34 +0100 Subject: [PATCH 019/244] Standarizing the usage of Strategy Phase --- Multi-Period-Market/User.Bot.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 2ff259c79..9de5a3ac5 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -696,7 +696,7 @@ /* Strategy and Phases */ let strategy = 0; - let strategyPhase = 0; + let strategyPhase = 0; // So far we will consider 3 possible phases: 0 = Initial state, 1 = Signal to buy, 2 = Buy, 3 = Sell. /* Stop Loss Management */ @@ -776,7 +776,7 @@ manually. */ - strategy = 1; + strategy = 2; } /* Checking what happened since the last execution. We need to know if the Stop Loss @@ -784,9 +784,9 @@ /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - let buySignalActivated = false; - - if (candle.max >= stopLoss && lastOperation === 'Sell') { + if (candle.max >= stopLoss && + lastOperation === 'Sell' && + strategyPhase === 2) { balanceAssetA = balanceAssetB / stopLoss; //if (isNaN(balanceAssetA)) { balanceAssetA = 0; } @@ -794,12 +794,14 @@ balanceAssetB = 0; rate = stopLoss; type = '"Buy@StopLoss"'; - buySignalActivated = true; + strategyPhase = 3; } /* Buy Order condition: Here we verify if the Buy Order was filled or not. */ - if (candle.min <= buyOrder && lastOperation === 'Sell' && buySignalActivated === false) { + if (candle.min <= buyOrder && + lastOperation === 'Sell' && + strategyPhase === 2) { balanceAssetA = balanceAssetB / buyOrder; //if (isNaN(balanceAssetA)) { balanceAssetA = 0; } @@ -807,10 +809,10 @@ balanceAssetB = 0; rate = buyOrder; type = '"Buy@BuyOrder"'; - buySignalActivated = true; + strategyPhase = 3; } - if (buySignalActivated === false) { + if (strategyPhase < 3) { if (strategy === 1) { @@ -1042,7 +1044,7 @@ /* Here we define what to do if the conditions to buy were activated. */ - if (buySignalActivated === true) { + if (strategyPhase === 3) { roundtrips++; lastProfit = balanceAssetA - previousBalanceAssetA; From 70439e1d4517dcd0085413781aea7e396e554be9 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 5 Mar 2019 12:00:09 +0100 Subject: [PATCH 020/244] 5 phase strategy implemented --- Multi-Period-Market/User.Bot.js | 42 +++++++++++++-------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 9de5a3ac5..72b69ef7c 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -689,14 +689,13 @@ /* Initial Values */ - let lastOperation = 'Buy'; let initialDate = new Date("2018-08-01"); let initialBalanceA = 1; /* Strategy and Phases */ let strategy = 0; - let strategyPhase = 0; // So far we will consider 3 possible phases: 0 = Initial state, 1 = Signal to buy, 2 = Buy, 3 = Sell. + let strategyPhase = 0; // So far we will consider 5 possible phases: 0 = Initial state, 1 = Signal to buy, 2 = Buy, 3 = After Buy, 4 = Sell. /* Stop Loss Management */ @@ -776,7 +775,7 @@ manually. */ - strategy = 2; + strategy = 1; } /* Checking what happened since the last execution. We need to know if the Stop Loss @@ -785,7 +784,6 @@ /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ if (candle.max >= stopLoss && - lastOperation === 'Sell' && strategyPhase === 2) { balanceAssetA = balanceAssetB / stopLoss; @@ -794,13 +792,12 @@ balanceAssetB = 0; rate = stopLoss; type = '"Buy@StopLoss"'; - strategyPhase = 3; + strategyPhase = 4; } /* Buy Order condition: Here we verify if the Buy Order was filled or not. */ if (candle.min <= buyOrder && - lastOperation === 'Sell' && strategyPhase === 2) { balanceAssetA = balanceAssetB / buyOrder; @@ -809,7 +806,7 @@ balanceAssetB = 0; rate = buyOrder; type = '"Buy@BuyOrder"'; - strategyPhase = 3; + strategyPhase = 4; } if (strategyPhase < 3) { @@ -840,8 +837,8 @@ if ( - percentgeBandwidth.value >= 70 && - lastOperation === 'Buy' && + strategyPhase === 0 && + percentgeBandwidth.value >= 70 && (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) && presellModeIsActive === false ) { @@ -851,19 +848,17 @@ }; - let sellSignalActivated = false; - /* Sell Condition #1 */ if ( + strategyPhase === 1 && presellModeIsActive === true && band2.movingAverage > band1.movingAverage && - band1.movingAverage > band.movingAverage && - lastOperation === 'Buy' + band1.movingAverage > band.movingAverage ) { type = '"Sell-1"'; - sellSignalActivated = true; + strategyPhase = 2; stopLossPhase = 1; buyOrderPhase = 1; @@ -872,15 +867,15 @@ /* Sell Condition #2 */ if ( + strategyPhase <= 1 && candles[i - 3].min < band3.movingAverage - band3.deviation && candles[i - 2].min < band2.movingAverage - band2.deviation && candles[i - 1].min < band1.movingAverage - band1.deviation && - candle.min < band.movingAverage - band.deviation && - lastOperation === 'Buy' + candle.min < band.movingAverage - band.deviation ) { type = '"Sell-2"'; - sellSignalActivated = true; + strategyPhase = 2; stopLossPhase = 1; buyOrderPhase = 1; @@ -897,8 +892,8 @@ } if ( + strategyPhase === 2 && candle.max < band.movingAverage && - lastOperation === 'Sell' && band1.movingAverage > band.movingAverage ) { @@ -945,8 +940,8 @@ buyOrder = band.movingAverage - band.standardDeviation * 10; //+ band.movingAverage - band.standardDeviation * 4 * (buyOrderPercentage + buyOrderDecay) / 100; if ( + strategyPhase === 2 && candle.max < band.movingAverage && - lastOperation === 'Sell' && band1.movingAverage > band.movingAverage && candle.min < band.movingAverage - band.deviation ) { @@ -995,7 +990,7 @@ } - if (sellSignalActivated === true) { + if (strategyPhase === 2) { previousBalanceAssetA = balanceAssetA; lastProfit = 0; @@ -1009,13 +1004,12 @@ stopLoss = sellRate + sellRate * stopLossPercentage / 100; - lastOperation = 'Sell'; presellModeIsActive = false; stopLossDecay = 0; addRecord(); - sellSignalActivated = false; + strategyPhase = 3; continue; } } @@ -1044,7 +1038,7 @@ /* Here we define what to do if the conditions to buy were activated. */ - if (strategyPhase === 3) { + if (strategyPhase === 4) { roundtrips++; lastProfit = balanceAssetA - previousBalanceAssetA; @@ -1067,8 +1061,6 @@ let miliSecondsPerDay = 24 * 60 * 60 * 1000; days = periods * outputPeriod / miliSecondsPerDay; anualizedRateOfReturn = ROI / days * 365; - - lastOperation = 'Buy'; addRecord(); From 51d85675847cfecd5bc4cc5f36d40c3a83abfefa Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 5 Mar 2019 12:17:12 +0100 Subject: [PATCH 021/244] File not found bug fixed --- Multi-Period-Market/User.Bot.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 72b69ef7c..95c7f170e 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -286,7 +286,7 @@ let fileName = market.assetA + '_' + market.assetB + ".json"; - let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePathRoot = bot.devTeam + "/" + "AAPaula" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; let filePath = filePathRoot + "/Output/" + BOLLINGER_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); @@ -364,7 +364,7 @@ let fileName = market.assetA + '_' + market.assetB + ".json"; - let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePathRoot = bot.devTeam + "/" + "AAPaula" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; let filePath = filePathRoot + "/Output/" + BOLLINGER_SUB_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); @@ -681,7 +681,15 @@ } } - function runSimulation(candles, bollingerBandsMap, percentgeBandwidthMap, recordsArray, outputPeriod, callback) { + function runSimulation( + candles, + bollingerBandsMap, + percentgeBandwidthMap, + bollingerChannelsArray, + bollingerSubChannelsArray, + recordsArray, + outputPeriod, + callback) { try { @@ -1027,6 +1035,10 @@ We keep our buy order just below the the Bollinger Bands moving average. */ + + let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); + + } } From fd8376ce73d5691ca95b44f2d4762737a7e79e42 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 5 Mar 2019 12:49:41 +0100 Subject: [PATCH 022/244] Last touches to strategy 1 --- Multi-Period-Market/User.Bot.js | 130 +++++++++++++++++--------------- 1 file changed, 69 insertions(+), 61 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 95c7f170e..c39bfab94 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -386,7 +386,7 @@ marketFile = JSON.parse(text); - buildBollingerChannelsArray(); + buildBollingerSubChannelsArray(); } @@ -792,7 +792,7 @@ /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ if (candle.max >= stopLoss && - strategyPhase === 2) { + strategyPhase === 3) { balanceAssetA = balanceAssetB / stopLoss; //if (isNaN(balanceAssetA)) { balanceAssetA = 0; } @@ -806,7 +806,7 @@ /* Buy Order condition: Here we verify if the Buy Order was filled or not. */ if (candle.min <= buyOrder && - strategyPhase === 2) { + strategyPhase === 3) { balanceAssetA = balanceAssetB / buyOrder; //if (isNaN(balanceAssetA)) { balanceAssetA = 0; } @@ -817,7 +817,7 @@ strategyPhase = 4; } - if (strategyPhase < 3) { + if (strategyPhase < 4) { // A buy condition has not been detected. if (strategy === 1) { @@ -844,17 +844,7 @@ - if ( - strategyPhase === 0 && - percentgeBandwidth.value >= 70 && - (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) && - presellModeIsActive === false - ) { - signal = '"Pre-Sell"'; - presellModeIsActive = true; - strategyPhase = 1; - }; /* Sell Condition #1 */ @@ -889,25 +879,31 @@ buyOrderPhase = 1; } - if (stopLossPhase === 1) { + /* Signal to be ready to Sell */ - newStopLoss = newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; + if ( + strategyPhase === 0 && + percentgeBandwidth.value >= 70 && + (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) && + presellModeIsActive === false + ) { + signal = '"Pre-Sell"'; + presellModeIsActive = true; + strategyPhase = 1; + + }; + + /* Stop Loss Management */ + + if (stopLossPhase === 3) { + + newStopLoss = band.movingAverage; if (newStopLoss < previousStopLoss) { stopLoss = newStopLoss; } else { stopLoss = previousStopLoss; } - - if ( - strategyPhase === 2 && - candle.max < band.movingAverage && - band1.movingAverage > band.movingAverage - ) { - - stopLossPhase = 2; - - } } if (stopLossPhase === 2) { @@ -927,38 +923,56 @@ } } - if (stopLossPhase === 3) { + if (stopLossPhase === 1) { - newStopLoss = band.movingAverage; + newStopLoss = newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; if (newStopLoss < previousStopLoss) { stopLoss = newStopLoss; } else { stopLoss = previousStopLoss; - } - } - - - - - if (buyOrderPhase === 1) { - - buyOrderDecay = buyOrderDecay + buyOrderDecayIncrement; - - buyOrder = band.movingAverage - band.standardDeviation * 10; //+ band.movingAverage - band.standardDeviation * 4 * (buyOrderPercentage + buyOrderDecay) / 100; + } if ( - strategyPhase === 2 && + strategyPhase === 3 && candle.max < band.movingAverage && - band1.movingAverage > band.movingAverage && - candle.min < band.movingAverage - band.deviation + band1.movingAverage > band.movingAverage ) { - buyOrderPhase = 2; + stopLossPhase = 2; } } + /* Buy Orders Management */ + + if (buyOrderPhase === 5) { + + buyOrder = band.movingAverage - band.standardDeviation * 2; + + } + + if (buyOrderPhase === 4) { + + buyOrder = band.movingAverage - band.standardDeviation * 3; + + if ( + percentgeBandwidth1.movingAverage < percentgeBandwidth.movingAverage && + percentgeBandwidth.movingAverage > 30 + ) { + buyOrderPhase = 5; + } + } + + if (buyOrderPhase === 3) { + + buyOrder = band.movingAverage - band.standardDeviation * 4; + + if (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) { + buyOrderPhase = 4; + } + } + if (buyOrderPhase === 2) { buyOrder = band.movingAverage - band.standardDeviation * 10; @@ -971,34 +985,28 @@ } } - if (buyOrderPhase === 3) { + if (buyOrderPhase === 1) { - buyOrder = band.movingAverage - band.standardDeviation * 4; + buyOrderDecay = buyOrderDecay + buyOrderDecayIncrement; - if (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) { - buyOrderPhase = 4; - } - } - - if (buyOrderPhase === 4) { - - buyOrder = band.movingAverage - band.standardDeviation * 3; + buyOrder = band.movingAverage - band.standardDeviation * 10; //+ band.movingAverage - band.standardDeviation * 4 * (buyOrderPercentage + buyOrderDecay) / 100; if ( - percentgeBandwidth1.movingAverage < percentgeBandwidth.movingAverage && - percentgeBandwidth.movingAverage > 30 + strategyPhase === 3 && + candle.max < band.movingAverage && + band1.movingAverage > band.movingAverage && + candle.min < band.movingAverage - band.deviation ) { - buyOrderPhase = 5; + + buyOrderPhase = 2; + } } - if (buyOrderPhase === 5) { - buyOrder = band.movingAverage - band.standardDeviation * 2; + /* Check if a Sell condition was found. */ - } - - if (strategyPhase === 2) { + if (strategyPhase === 2) { previousBalanceAssetA = balanceAssetA; lastProfit = 0; From 27eb3665cb9294b18e05991a98e9284f5481c550 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 5 Mar 2019 15:15:12 +0100 Subject: [PATCH 023/244] Strategy 2 Signal to Sell --- Multi-Period-Market/User.Bot.js | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index c39bfab94..f4a9acefc 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -747,8 +747,6 @@ let rate = 0; let newStopLoss; - let presellModeIsActive = false; - let initialBuffer = 3; /* Main Simulation Loop: We go thourgh all the candles at this time period. */ @@ -819,7 +817,7 @@ if (strategyPhase < 4) { // A buy condition has not been detected. - if (strategy === 1) { + if (strategy === 2) { /* Strategy #1: Trend Following. */ @@ -850,7 +848,6 @@ if ( strategyPhase === 1 && - presellModeIsActive === true && band2.movingAverage > band1.movingAverage && band1.movingAverage > band.movingAverage ) { @@ -884,11 +881,9 @@ if ( strategyPhase === 0 && percentgeBandwidth.value >= 70 && - (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) && - presellModeIsActive === false + (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) ) { signal = '"Pre-Sell"'; - presellModeIsActive = true; strategyPhase = 1; }; @@ -1020,7 +1015,6 @@ stopLoss = sellRate + sellRate * stopLossPercentage / 100; - presellModeIsActive = false; stopLossDecay = 0; addRecord(); @@ -1046,7 +1040,23 @@ let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); + /* Signal to be ready to Sell */ + + if ( + strategyPhase === 0 && + subChannel.direction === 'Up' && + ( + subChannel.slope === 'Side' || + subChannel.slope === 'Gentle' || + subChannel.slope === 'Medium' + ) + ) { + + signal = '"Pre-Sell"'; + strategyPhase = 1; + + } } } From 54ee78ddfe9d9ed906c878afc958ed9fda46e05c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 5 Mar 2019 15:40:06 +0100 Subject: [PATCH 024/244] Strategy 2 implemented --- Multi-Period-Market/User.Bot.js | 98 +++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 30 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index f4a9acefc..a78052dae 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -639,7 +639,7 @@ n++; - if (n < global.marketFilesPeriods.length) { + if (n < global.marketFilesPeriods.length - 1) { loopBody(); @@ -781,7 +781,7 @@ manually. */ - strategy = 1; + strategy = 2; } /* Checking what happened since the last execution. We need to know if the Stop Loss @@ -817,7 +817,7 @@ if (strategyPhase < 4) { // A buy condition has not been detected. - if (strategy === 2) { + if (strategy === 1) { /* Strategy #1: Trend Following. */ @@ -998,30 +998,6 @@ } } - - /* Check if a Sell condition was found. */ - - if (strategyPhase === 2) { - - previousBalanceAssetA = balanceAssetA; - lastProfit = 0; - lastProfitPercent = 0; - - balanceAssetB = balanceAssetA * candle.close; - balanceAssetA = 0; - - rate = candle.close; - sellRate = rate; - - stopLoss = sellRate + sellRate * stopLossPercentage / 100; - - stopLossDecay = 0; - - addRecord(); - - strategyPhase = 3; - continue; - } } if (strategy === 2) { @@ -1040,9 +1016,24 @@ let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); - /* Signal to be ready to Sell */ + /* Sell Condition #1 */ + + if ( + strategyPhase === 1 && + candle.max > band.movingAverage + band.deviation + ) { + + type = '"Sell-1"'; + + strategyPhase = 2; + stopLossPhase = 1; + buyOrderPhase = 1; + } + + /* Signal to be ready to Sell */ + if ( strategyPhase === 0 && subChannel.direction === 'Up' && @@ -1057,14 +1048,53 @@ strategyPhase = 1; } - } + /* Stop Loss Management */ + + if (stopLossPhase === 1) { + + newStopLoss = newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } + } + + /* Buy Orders Management */ + + if (buyOrderPhase === 1) { + + buyOrder = band.movingAverage; + + } + } } + /* Check if a Sell condition was found. */ + if (strategyPhase === 2) { + previousBalanceAssetA = balanceAssetA; + lastProfit = 0; + lastProfitPercent = 0; + balanceAssetB = balanceAssetA * candle.close; + balanceAssetA = 0; + rate = candle.close; + sellRate = rate; + + stopLoss = sellRate + sellRate * stopLossPercentage / 100; + + stopLossDecay = 0; + + addRecord(); + + strategyPhase = 3; + continue; + } /* Here we define what to do if the conditions to buy were activated. */ @@ -1162,14 +1192,22 @@ function getElement(pArray, begin, end) { + let element; + for (let i = 0; i < pArray.length; i++) { - let element = pArray[i]; + element = pArray[i]; if (begin >= element.begin && end <= element.end) { return element } } + + element = { + direction: 'unknown', + slope: 'unknown' + }; + return element; } } catch (err) { From a8c0dd695d9962a5015a9bb031d0166f2f674edd Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 5 Mar 2019 18:21:19 +0100 Subject: [PATCH 025/244] Strategy 2 Implemented --- Multi-Period-Market/User.Bot.js | 76 +++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 27 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index a78052dae..e19869640 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -119,7 +119,7 @@ let marketFile; - let percentgeBandwidthMap = new Map(); + let percentageBandwidthMap = new Map(); let bollingerBandsMap = new Map(); let bollingerChannelsArray = []; let bollingerSubChannelsArray = []; @@ -183,14 +183,14 @@ for (let i = 0; i < marketFile.length; i++) { - let percentgeBandwidth = { + let percentageBandwidth = { begin: marketFile[i][0], end: marketFile[i][1], value: marketFile[i][2], movingAverage: marketFile[i][3] }; - percentgeBandwidthMap.set(percentgeBandwidth.begin, percentgeBandwidth); + percentageBandwidthMap.set(percentageBandwidth.begin, percentageBandwidth); } @@ -519,7 +519,7 @@ runSimulation( candles, bollingerBandsMap, - percentgeBandwidthMap, + percentageBandwidthMap, bollingerChannelsArray, bollingerSubChannelsArray, recordsArray, @@ -639,7 +639,7 @@ n++; - if (n < global.marketFilesPeriods.length - 1) { + if (n < global.marketFilesPeriods.length) { loopBody(); @@ -684,7 +684,7 @@ function runSimulation( candles, bollingerBandsMap, - percentgeBandwidthMap, + percentageBandwidthMap, bollingerChannelsArray, bollingerSubChannelsArray, recordsArray, @@ -754,10 +754,10 @@ for (let i = 0 + initialBuffer; i < candles.length; i++) { let candle = candles[i]; - let percentgeBandwidth = percentgeBandwidthMap.get(candle.begin); + let percentageBandwidth = percentageBandwidthMap.get(candle.begin); let band = bollingerBandsMap.get(candle.begin); - if (percentgeBandwidth === undefined) { continue; } // percentageBandwidth might start after the first few candles. + if (percentageBandwidth === undefined) { continue; } // percentageBandwidth might start after the first few candles. if (candle.begin < initialDate.valueOf()) { continue; } periods++; @@ -766,9 +766,9 @@ let band2 = bollingerBandsMap.get(candles[i - 2].begin); let band3 = bollingerBandsMap.get(candles[i - 3].begin); - let percentgeBandwidth1 = percentgeBandwidthMap.get(candles[i - 1].begin); - let percentgeBandwidth2 = percentgeBandwidthMap.get(candles[i - 2].begin); - let percentgeBandwidth3 = percentgeBandwidthMap.get(candles[i - 3].begin); + let percentageBandwidth1 = percentageBandwidthMap.get(candles[i - 1].begin); + let percentageBandwidth2 = percentageBandwidthMap.get(candles[i - 2].begin); + let percentageBandwidth3 = percentageBandwidthMap.get(candles[i - 3].begin); if (strategy === 0) { @@ -880,8 +880,8 @@ if ( strategyPhase === 0 && - percentgeBandwidth.value >= 70 && - (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) + percentageBandwidth.value >= 70 && + (percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage) ) { signal = '"Pre-Sell"'; strategyPhase = 1; @@ -903,6 +903,12 @@ if (stopLossPhase === 2) { + if (band1.movingAverage < band.movingAverage) { + stopLossDecay = stopLossDecay + stopLossDecayIncrement * 2; + } else { + stopLossDecay = stopLossDecay - stopLossDecayIncrement / 2; + } + newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; if (newStopLoss < previousStopLoss) { @@ -920,6 +926,12 @@ if (stopLossPhase === 1) { + if (band1.movingAverage < band.movingAverage) { + stopLossDecay = stopLossDecay + stopLossDecayIncrement * 2; + } else { + stopLossDecay = stopLossDecay - stopLossDecayIncrement / 2; + } + newStopLoss = newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; if (newStopLoss < previousStopLoss) { @@ -952,8 +964,8 @@ buyOrder = band.movingAverage - band.standardDeviation * 3; if ( - percentgeBandwidth1.movingAverage < percentgeBandwidth.movingAverage && - percentgeBandwidth.movingAverage > 30 + percentageBandwidth1.movingAverage < percentageBandwidth.movingAverage && + percentageBandwidth.movingAverage > 30 ) { buyOrderPhase = 5; } @@ -963,7 +975,7 @@ buyOrder = band.movingAverage - band.standardDeviation * 4; - if (percentgeBandwidth1.movingAverage > percentgeBandwidth.movingAverage) { + if (percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage) { buyOrderPhase = 4; } } @@ -973,8 +985,8 @@ buyOrder = band.movingAverage - band.standardDeviation * 10; if ( - percentgeBandwidth1.movingAverage < percentgeBandwidth.movingAverage && - percentgeBandwidth.movingAverage > 0 + percentageBandwidth1.movingAverage < percentageBandwidth.movingAverage && + percentageBandwidth.movingAverage > 0 ) { buyOrderPhase = 3; } @@ -1022,7 +1034,9 @@ if ( strategyPhase === 1 && - candle.max > band.movingAverage + band.deviation + percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage && + percentageBandwidth1.movingAverage > 100 + ) { type = '"Sell-1"'; @@ -1041,7 +1055,8 @@ subChannel.slope === 'Side' || subChannel.slope === 'Gentle' || subChannel.slope === 'Medium' - ) + ) && + candle.max > band.movingAverage + band.deviation ) { signal = '"Pre-Sell"'; @@ -1049,6 +1064,19 @@ } + if ( + strategyPhase === 1 && + (subChannel.direction === 'Down' || + subChannel.slope === 'Steep' || + subChannel.slope === 'Extreme' + ) + ) { + + signal = '"Pre-Sell-Cancelled"'; + strategyPhase = 0; + + } + /* Stop Loss Management */ if (stopLossPhase === 1) { @@ -1066,7 +1094,7 @@ if (buyOrderPhase === 1) { - buyOrder = band.movingAverage; + buyOrder = band.movingAverage - band.standardDeviation; } } @@ -1176,12 +1204,6 @@ previousStopLoss = stopLoss; - if (band1.movingAverage < band.movingAverage) { - stopLossDecay = stopLossDecay + stopLossDecayIncrement * 2; - } else { - stopLossDecay = stopLossDecay - stopLossDecayIncrement / 2; - } - type = '""'; signal = '""'; From 0d28cb70c20c1226029cdb4e46eb3667cd9e7796 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 6 Mar 2019 11:46:59 +0100 Subject: [PATCH 026/244] New conditions for strategy 1 --- Multi-Period-Market/User.Bot.js | 178 ++++++++++++++++---------------- 1 file changed, 89 insertions(+), 89 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index e19869640..242da3510 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -569,7 +569,6 @@ record.anualizedRateOfReturn + "," + record.sellRate + "," + record.lastProfitPercent + "," + - record.signal + "," + record.strategy + "," + record.strategyPhase + "," + record.buyOrder + "," + @@ -699,6 +698,7 @@ let initialDate = new Date("2018-08-01"); let initialBalanceA = 1; + let minimunBalanceA = 0.5; /* Strategy and Phases */ @@ -743,7 +743,6 @@ let days = 0; let anualizedRateOfReturn = 0; let type = '""'; - let signal = '""'; let rate = 0; let newStopLoss; @@ -770,52 +769,84 @@ let percentageBandwidth2 = percentageBandwidthMap.get(candles[i - 2].begin); let percentageBandwidth3 = percentageBandwidthMap.get(candles[i - 3].begin); - if (strategy === 0) { + let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); + + if (strategy === 0 && + balanceAssetA > minimunBalanceA) { /* 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 need a new indicator called Bollinger Channels, - which I dont have right now, so for the time being, I will choose the strategy - manually. + To pick a new strategy we will evaluate what we call an entering condition. Once we enter + into one strategy, we will ignore market conditions for others. However there is also + a strategy exit condition which can be hit before entering into a trade. If hit, we would + be outside a strategy again and looking for the condition to enter all over again. + */ - strategy = 2; + /* Strategy 1 Entering Condition */ + + if ( + strategyPhase === 0 && + percentageBandwidth2.movingAverage > percentageBandwidth1.movingAverage && + percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage && + percentageBandwidth2.bandwidth < percentageBandwidth1.bandwidth && + percentageBandwidth1.bandwidth < percentageBandwidth.bandwidth + ) { + strategyPhase = 1; + strategy = 1; + + }; + + /* Strategy 2 Entering Condition */ + + if ( + strategyPhase === 0 && + subChannel.direction === 'Up' && + ( + subChannel.slope === 'Side' || + subChannel.slope === 'Gentle' || + subChannel.slope === 'Medium' + ) && + candle.close > band.movingAverage + band.deviation + ) { + strategyPhase = 1; + strategy = 2; + } } - /* Checking what happened since the last execution. We need to know if the Stop Loss - or our Buy Order were hit. */ + if (strategyPhase === 3) { - /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ + /* Checking what happened since the last execution. We need to know if the Stop Loss + or our Buy Order were hit. */ - if (candle.max >= stopLoss && - strategyPhase === 3) { + /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - balanceAssetA = balanceAssetB / stopLoss; - //if (isNaN(balanceAssetA)) { balanceAssetA = 0; } + if (candle.max >= stopLoss) { - balanceAssetB = 0; - rate = stopLoss; - type = '"Buy@StopLoss"'; - strategyPhase = 4; + balanceAssetA = balanceAssetB / stopLoss; + + balanceAssetB = 0; + rate = stopLoss; + type = '"Buy@StopLoss"'; + strategyPhase = 4; + } + + /* Buy Order condition: Here we verify if the Buy Order was filled or not. */ + + if (candle.min <= buyOrder) { + + balanceAssetA = balanceAssetB / buyOrder; + + balanceAssetB = 0; + rate = buyOrder; + type = '"Buy@BuyOrder"'; + strategyPhase = 4; + } } - /* Buy Order condition: Here we verify if the Buy Order was filled or not. */ - - if (candle.min <= buyOrder && - strategyPhase === 3) { - - balanceAssetA = balanceAssetB / buyOrder; - //if (isNaN(balanceAssetA)) { balanceAssetA = 0; } - - balanceAssetB = 0; - rate = buyOrder; - type = '"Buy@BuyOrder"'; - strategyPhase = 4; - } - - if (strategyPhase < 4) { // A buy condition has not been detected. + if (strategyPhase < 4) { // When a buy condition has not been detected yet. if (strategy === 1) { @@ -839,13 +870,18 @@ */ + /* Strategy Exit Condition */ - - - + if ( + strategyPhase === 1 && + candle.close > band.movingAverage + ) { + strategyPhase = 0; + strategy = 0; + }; /* Sell Condition #1 */ - + /* if ( strategyPhase === 1 && band2.movingAverage > band1.movingAverage && @@ -858,12 +894,11 @@ stopLossPhase = 1; buyOrderPhase = 1; } - + */ /* Sell Condition #2 */ if ( - strategyPhase <= 1 && - candles[i - 3].min < band3.movingAverage - band3.deviation && + strategyPhase === 1 && candles[i - 2].min < band2.movingAverage - band2.deviation && candles[i - 1].min < band1.movingAverage - band1.deviation && candle.min < band.movingAverage - band.deviation @@ -876,18 +911,6 @@ buyOrderPhase = 1; } - /* Signal to be ready to Sell */ - - if ( - strategyPhase === 0 && - percentageBandwidth.value >= 70 && - (percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage) - ) { - signal = '"Pre-Sell"'; - strategyPhase = 1; - - }; - /* Stop Loss Management */ if (stopLossPhase === 3) { @@ -1009,7 +1032,6 @@ } } - } if (strategy === 2) { @@ -1026,16 +1048,27 @@ */ - let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); + /* Exist Strategy Condition */ + if ( + strategyPhase === 1 && + (subChannel.direction === 'Down' || + subChannel.slope === 'Steep' || + subChannel.slope === 'Extreme' + ) + ) { + strategyPhase = 0; + strategy = 0; + + } /* Sell Condition #1 */ if ( strategyPhase === 1 && percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage && - percentageBandwidth1.movingAverage > 100 + percentageBandwidth1.movingAverage > 90 ) { @@ -1046,37 +1079,6 @@ buyOrderPhase = 1; } - /* Signal to be ready to Sell */ - - if ( - strategyPhase === 0 && - subChannel.direction === 'Up' && - ( - subChannel.slope === 'Side' || - subChannel.slope === 'Gentle' || - subChannel.slope === 'Medium' - ) && - candle.max > band.movingAverage + band.deviation - ) { - - signal = '"Pre-Sell"'; - strategyPhase = 1; - - } - - if ( - strategyPhase === 1 && - (subChannel.direction === 'Down' || - subChannel.slope === 'Steep' || - subChannel.slope === 'Extreme' - ) - ) { - - signal = '"Pre-Sell-Cancelled"'; - strategyPhase = 0; - - } - /* Stop Loss Management */ if (stopLossPhase === 1) { @@ -1124,7 +1126,7 @@ continue; } - /* Here we define what to do if the conditions to buy were activated. */ + /* Check if a Buy condition was found. */ if (strategyPhase === 4) { @@ -1192,7 +1194,6 @@ anualizedRateOfReturn: anualizedRateOfReturn, sellRate: sellRate, lastProfitPercent: lastProfitPercent, - signal: signal, strategy: strategy, strategyPhase: strategyPhase, buyOrder: buyOrder, @@ -1205,7 +1206,6 @@ previousStopLoss = stopLoss; type = '""'; - signal = '""'; } } From 2be28d3af4ca62280a02893af88fe6d2c209a5a5 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 6 Mar 2019 12:53:03 +0100 Subject: [PATCH 027/244] Only 1 hr --- Multi-Period-Market/User.Bot.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 242da3510..2d8e83676 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -117,6 +117,11 @@ const outputPeriod = global.marketFilesPeriods[n][0]; const timePeriod = global.marketFilesPeriods[n][1]; + if (timePeriod !== '01-hs') { + controlLoop(); + return; + } + let marketFile; let percentageBandwidthMap = new Map(); @@ -187,7 +192,8 @@ begin: marketFile[i][0], end: marketFile[i][1], value: marketFile[i][2], - movingAverage: marketFile[i][3] + movingAverage: marketFile[i][3], + bandwidth: marketFile[i][4] }; percentageBandwidthMap.set(percentageBandwidth.begin, percentageBandwidth); @@ -792,7 +798,9 @@ percentageBandwidth2.movingAverage > percentageBandwidth1.movingAverage && percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage && percentageBandwidth2.bandwidth < percentageBandwidth1.bandwidth && - percentageBandwidth1.bandwidth < percentageBandwidth.bandwidth + percentageBandwidth1.bandwidth < percentageBandwidth.bandwidth && + candles[i - 2].min < candles[i - 1].min && + candles[i - 1].min < candle.min ) { strategyPhase = 1; strategy = 1; From b6d598047d2bea428684fb344890c39c8c850911 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 6 Mar 2019 14:01:50 +0100 Subject: [PATCH 028/244] Conditions Abstracted --- Multi-Period-Market/User.Bot.js | 79 +++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 9 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 2d8e83676..a1bf0533a 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -550,10 +550,20 @@ let fileContent = ""; - for (i = 0; i < recordsArray.length; i++) { + for (let i = 0; i < recordsArray.length; i++) { let record = recordsArray[i]; + let conditions = "["; + let conditionsSeparator = ""; + + for (let j = 0; j < record.conditions.length; j++) { + conditions = conditions + conditionsSeparator + record.conditions[j]; + if (conditionsSeparator === "") { conditionsSeparator = ","; } + } + + conditions = conditions + "]"; + fileContent = fileContent + separator + '[' + record.begin + "," + record.end + "," + @@ -579,7 +589,8 @@ record.strategyPhase + "," + record.buyOrder + "," + record.stopLossPhase + "," + - record.buyOrderPhase + "]"; + record.buyOrderPhase + "," + + conditions + "]"; if (separator === "") { separator = ","; } @@ -753,11 +764,14 @@ let newStopLoss; let initialBuffer = 3; + let conditionsHeadersSent = false; /* Main Simulation Loop: We go thourgh all the candles at this time period. */ for (let i = 0 + initialBuffer; i < candles.length; i++) { + /* Update all the data objects available for the simulation. */ + let candle = candles[i]; let percentageBandwidth = percentageBandwidthMap.get(candle.begin); let band = bollingerBandsMap.get(candle.begin); @@ -777,6 +791,55 @@ let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); + let conditions = new Map; + let conditionsArray = []; + + /* We define and evaluate all conditions to be used later during the simulation loop. */ + + newCondition( + "%B Moving Average going up", + (percentageBandwidth2.movingAverage > percentageBandwidth1.movingAverage && + percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage) + ); + + newCondition( + "%B Bandwidth going up", + (percentageBandwidth2.bandwidth < percentageBandwidth1.bandwidth && + percentageBandwidth1.bandwidth < percentageBandwidth.bandwidth) + ); + + newCondition( + "Candles Min going down", + (candles[i - 2].min < candles[i - 1].min && + candles[i - 1].min < candle.min) + ); + + function newCondition(name, value) { + + let condition; + + condition = { + name: name, + value: value + }; + + conditions.set(condition.name, condition); + + if (conditionsHeadersSent === false) { + conditionsArray.push('"' + condition.name + '"'); + } else { + if (condition.value) { + conditionsArray.push(1); + } else { + conditionsArray.push(0); + } + } + } + + conditionsHeadersSent = true; + + /* While we are outside all strategies, we evaluate whether it is time to enter one or not. */ + if (strategy === 0 && balanceAssetA > minimunBalanceA) { @@ -795,12 +858,9 @@ if ( strategyPhase === 0 && - percentageBandwidth2.movingAverage > percentageBandwidth1.movingAverage && - percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage && - percentageBandwidth2.bandwidth < percentageBandwidth1.bandwidth && - percentageBandwidth1.bandwidth < percentageBandwidth.bandwidth && - candles[i - 2].min < candles[i - 1].min && - candles[i - 1].min < candle.min + conditions.get("%B Moving Average going up").value && + conditions.get("%B Bandwidth going up").value && + conditions.get("Candles Min going down").value ) { strategyPhase = 1; strategy = 1; @@ -1206,7 +1266,8 @@ strategyPhase: strategyPhase, buyOrder: buyOrder, stopLossPhase: stopLossPhase, - buyOrderPhase: buyOrderPhase + buyOrderPhase: buyOrderPhase, + conditions: conditionsArray } recordsArray.push(record); From 473f9711fa52c89980706fa61630f30f4334c130 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 6 Mar 2019 18:04:49 +0100 Subject: [PATCH 029/244] 6 conditions --- Multi-Period-Market/User.Bot.js | 37 +++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index a1bf0533a..aa8bf5ce8 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -116,12 +116,12 @@ const outputPeriod = global.marketFilesPeriods[n][0]; const timePeriod = global.marketFilesPeriods[n][1]; - + /* if (timePeriod !== '01-hs') { controlLoop(); return; } - + */ let marketFile; let percentageBandwidthMap = new Map(); @@ -810,8 +810,27 @@ newCondition( "Candles Min going down", - (candles[i - 2].min < candles[i - 1].min && - candles[i - 1].min < candle.min) + (candles[i - 2].min > candles[i - 1].min && + candles[i - 1].min > candle.min) + ); + + newCondition( + "Sub-Channel going up", + (subChannel.direction === 'Up') + ); + + newCondition( + "Sub-Channel Side|Gentle|Medium", + ( + subChannel.slope === 'Side' || + subChannel.slope === 'Gentle' || + subChannel.slope === 'Medium' + ) + ); + + newCondition( + "Candle Close above Lower Band", + (candle.close > band.movingAverage + band.deviation) ); function newCondition(name, value) { @@ -871,13 +890,9 @@ if ( strategyPhase === 0 && - subChannel.direction === 'Up' && - ( - subChannel.slope === 'Side' || - subChannel.slope === 'Gentle' || - subChannel.slope === 'Medium' - ) && - candle.close > band.movingAverage + band.deviation + conditions.get("Sub-Channel going up").value && + conditions.get("Sub-Channel Side|Gentle|Medium").value && + conditions.get("Candle Close above Lower Band").value ) { strategyPhase = 1; strategy = 2; From c1ec5dfb59089c1ef5629f4ab2ca449bb6160128 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 7 Mar 2019 00:47:05 +0100 Subject: [PATCH 030/244] Conditions File done --- Multi-Period-Market/User.Bot.js | 108 ++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 19 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index aa8bf5ce8..005fdf8fe 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -13,6 +13,7 @@ const BOLLINGER_SUB_CHANNELS_FOLDER_NAME = "Bollinger-Sub-Channels"; const CANDLES_FOLDER_NAME = "Candles"; const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; + const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; const commons = COMMONS.newCommons(bot, logger, UTILITIES); @@ -131,6 +132,7 @@ let candles = []; let recordsArray = []; + let conditionsArray = []; nextPercentageBandwidth(); @@ -529,6 +531,7 @@ bollingerChannelsArray, bollingerSubChannelsArray, recordsArray, + conditionsArray, outputPeriod, writeRecordsFile) @@ -554,16 +557,6 @@ let record = recordsArray[i]; - let conditions = "["; - let conditionsSeparator = ""; - - for (let j = 0; j < record.conditions.length; j++) { - conditions = conditions + conditionsSeparator + record.conditions[j]; - if (conditionsSeparator === "") { conditionsSeparator = ","; } - } - - conditions = conditions + "]"; - fileContent = fileContent + separator + '[' + record.begin + "," + record.end + "," + @@ -589,8 +582,7 @@ record.strategyPhase + "," + record.buyOrder + "," + record.stopLossPhase + "," + - record.buyOrderPhase + "," + - conditions + "]"; + record.buyOrderPhase + "]"; if (separator === "") { separator = ","; } @@ -625,7 +617,7 @@ } - controlLoop(); + writeConditionsFile(); } catch (err) { @@ -640,6 +632,79 @@ } } + function writeConditionsFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < conditionsArray.length; i++) { + + let record = conditionsArray[i]; + + let conditions = ""; + let conditionsSeparator = ""; + + for (let j = 0; j < record.length; j++) { + conditions = conditions + conditionsSeparator + record[j]; + if (conditionsSeparator === "") { conditionsSeparator = ","; } + } + + fileContent = fileContent + separator + '[' + conditions + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + controlLoop(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> err = " + err.message); @@ -704,6 +769,7 @@ bollingerChannelsArray, bollingerSubChannelsArray, recordsArray, + conditionsArray, outputPeriod, callback) { @@ -792,10 +858,13 @@ let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); let conditions = new Map; - let conditionsArray = []; + let conditionsArrayRecord = []; /* We define and evaluate all conditions to be used later during the simulation loop. */ + conditionsArrayRecord.push(candle.begin); + conditionsArrayRecord.push(candle.end); + newCondition( "%B Moving Average going up", (percentageBandwidth2.movingAverage > percentageBandwidth1.movingAverage && @@ -845,12 +914,12 @@ conditions.set(condition.name, condition); if (conditionsHeadersSent === false) { - conditionsArray.push('"' + condition.name + '"'); + conditionsArrayRecord.push('"' + condition.name + '"'); } else { if (condition.value) { - conditionsArray.push(1); + conditionsArrayRecord.push(1); } else { - conditionsArray.push(0); + conditionsArrayRecord.push(0); } } } @@ -1281,8 +1350,7 @@ strategyPhase: strategyPhase, buyOrder: buyOrder, stopLossPhase: stopLossPhase, - buyOrderPhase: buyOrderPhase, - conditions: conditionsArray + buyOrderPhase: buyOrderPhase } recordsArray.push(record); @@ -1291,6 +1359,8 @@ type = '""'; + conditionsArray.push(conditionsArrayRecord); + } } From 61aa4f568cc16bf8d20e35c559d4a407634935ab Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 7 Mar 2019 01:53:40 +0100 Subject: [PATCH 031/244] Conditions Plotter Configuration --- this.bot.config.json | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/this.bot.config.json b/this.bot.config.json index e4aeadbf9..47e91399d 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -146,6 +146,42 @@ "codeName": "PlottersTradingSimulation", "moduleName": "TradingSimulation" } + }, + { + "codeName": "SimulationConditions", + "displayName": "Simulation Conditions", + "description": "Simulation Conditions", + "storageAccount": "aajason", + "dataSets": [ + { + "codeName": "Multi-Period-Market", + "type": "Market Files", + "validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs" ], + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Conditions/Multi-Period-Market/@Period", + "fileName": "@AssetA_@AssetB.json" + }, + { + "codeName": "Multi-Period-Daily", + "type": "Daily Files", + "validPeriods": [ "45-min", "40-min", "30-min", "20-min", "15-min", "10-min", "05-min", "04-min", "03-min", "02-min", "01-min" ], + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Conditions/Multi-Period-Daily/@Period/@Year/@Month/@Day", + "fileName": "@AssetA_@AssetB.json", + "dataRange": { + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Trading-Simulation/Multi-Period-Daily", + "fileName": "Data.Range.@AssetA_@AssetB.json" + } + } + ], + "exchangeList": [ + { + "name": "Poloniex" + } + ], + "plotter": { + "devTeam": "AAMasters", + "codeName": "PlottersTradingSimulation", + "moduleName": "Conditions" + } } ] } From f1205ff63b9ec65b606c38575567681e4c360d4f Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 7 Mar 2019 11:23:52 +0100 Subject: [PATCH 032/244] First Implementation of simulation logic in a constant --- Multi-Period-Market/User.Bot.js | 169 ++++++++++++++++++++------------ 1 file changed, 106 insertions(+), 63 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 005fdf8fe..dc1ac283d 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -785,7 +785,7 @@ /* Strategy and Phases */ - let strategy = 0; + let strategyNumber = 0; let strategyPhase = 0; // So far we will consider 5 possible phases: 0 = Initial state, 1 = Signal to buy, 2 = Buy, 3 = After Buy, 4 = Sell. /* Stop Loss Management */ @@ -832,6 +832,59 @@ let initialBuffer = 3; let conditionsHeadersSent = false; + const simulationLogic = { + strategies: [ + { + name: "Trend Following", + entryPoint: { + situations: [ + { + name: "Price Collapsing", + conditions: [ + { + name: "%B Moving Average going up", + code: "percentageBandwidth2.movingAverage > percentageBandwidth1.movingAverage && percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage" + }, + { + name: "%B Bandwidth going up", + code: "percentageBandwidth2.bandwidth < percentageBandwidth1.bandwidth && percentageBandwidth1.bandwidth < percentageBandwidth.bandwidth" + }, + { + name: "Candles Min going down", + code: "candles[i - 2].min > candles[i - 1].min && candles[i - 1].min > candle.min" + } + ] + } + ] + } + }, + { + name: "Range Trading", + entryPoint: { + situations: [ + { + name: "Gentle Up Trend", + conditions: [ + { + name: "Sub-Channel going up", + code: "subChannel.direction === 'Up'" + }, + { + name: "Sub-Channel Side|Gentle|Medium", + code: "subChannel.slope === 'Side' || subChannel.slope === 'Gentle' || subChannel.slope === 'Medium'" + }, + { + name: "Candle Close above Lower Band", + code: "candle.close > band.movingAverage + band.deviation" + } + ] + } + ] + } + } + ] + }; + /* Main Simulation Loop: We go thourgh all the candles at this time period. */ for (let i = 0 + initialBuffer; i < candles.length; i++) { @@ -865,56 +918,37 @@ conditionsArrayRecord.push(candle.begin); conditionsArrayRecord.push(candle.end); - newCondition( - "%B Moving Average going up", - (percentageBandwidth2.movingAverage > percentageBandwidth1.movingAverage && - percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage) - ); + for (let j = 0; j < simulationLogic.strategies.length; j++) { - newCondition( - "%B Bandwidth going up", - (percentageBandwidth2.bandwidth < percentageBandwidth1.bandwidth && - percentageBandwidth1.bandwidth < percentageBandwidth.bandwidth) - ); + let strategy = simulationLogic.strategies[j]; - newCondition( - "Candles Min going down", - (candles[i - 2].min > candles[i - 1].min && - candles[i - 1].min > candle.min) - ); + for (let k = 0; k < strategy.entryPoint.situations.length; k++) { - newCondition( - "Sub-Channel going up", - (subChannel.direction === 'Up') - ); + let situation = strategy.entryPoint.situations[k]; - newCondition( - "Sub-Channel Side|Gentle|Medium", - ( - subChannel.slope === 'Side' || - subChannel.slope === 'Gentle' || - subChannel.slope === 'Medium' - ) - ); + for (let m = 0; m < situation.conditions.length; m++) { - newCondition( - "Candle Close above Lower Band", - (candle.close > band.movingAverage + band.deviation) - ); + let condition = situation.conditions[m]; + let key = strategy.name + '-' + situation.name + '-' + condition.name - function newCondition(name, value) { + newCondition(key, condition.code); + } + } + } + + function newCondition(key, code) { let condition; condition = { - name: name, - value: value + key: key, + value: eval(code) }; - conditions.set(condition.name, condition); + conditions.set(condition.key, condition); if (conditionsHeadersSent === false) { - conditionsArrayRecord.push('"' + condition.name + '"'); + conditionsArrayRecord.push('"' + condition.key + '"'); } else { if (condition.value) { conditionsArrayRecord.push(1); @@ -928,7 +962,7 @@ /* While we are outside all strategies, we evaluate whether it is time to enter one or not. */ - if (strategy === 0 && + if (strategyNumber === 0 && balanceAssetA > minimunBalanceA) { /* @@ -942,29 +976,38 @@ */ - /* Strategy 1 Entering Condition */ + checkEntryPoints(); - if ( - strategyPhase === 0 && - conditions.get("%B Moving Average going up").value && - conditions.get("%B Bandwidth going up").value && - conditions.get("Candles Min going down").value - ) { - strategyPhase = 1; - strategy = 1; + function checkEntryPoints() { - }; + for (let j = 0; j < simulationLogic.strategies.length; j++) { - /* Strategy 2 Entering Condition */ + let strategy = simulationLogic.strategies[j]; - if ( - strategyPhase === 0 && - conditions.get("Sub-Channel going up").value && - conditions.get("Sub-Channel Side|Gentle|Medium").value && - conditions.get("Candle Close above Lower Band").value - ) { - strategyPhase = 1; - strategy = 2; + for (let k = 0; k < strategy.entryPoint.situations.length; k++) { + + let situation = strategy.entryPoint.situations[k]; + let passed = true; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + situation.name + '-' + condition.name + + let value = conditions.get(key).value; + + if (value === false) { passed = false; } + } + + if (passed) { + + strategyPhase = 1; + strategyNumber = j + 1; + + return; + } + } + } } } @@ -1000,7 +1043,7 @@ if (strategyPhase < 4) { // When a buy condition has not been detected yet. - if (strategy === 1) { + if (strategyNumber === 1) { /* Strategy #1: Trend Following. */ @@ -1029,7 +1072,7 @@ candle.close > band.movingAverage ) { strategyPhase = 0; - strategy = 0; + strategyNumber = 0; }; /* Sell Condition #1 */ @@ -1186,7 +1229,7 @@ } } - if (strategy === 2) { + if (strategyNumber === 2) { /* Strategy #2: Range Trading. */ @@ -1211,7 +1254,7 @@ ) { strategyPhase = 0; - strategy = 0; + strategyNumber = 0; } @@ -1306,7 +1349,7 @@ addRecord(); - strategy = 0; + strategyNumber = 0; stopLoss = 0; sellRate = 0; buyOrder = 0; @@ -1346,7 +1389,7 @@ anualizedRateOfReturn: anualizedRateOfReturn, sellRate: sellRate, lastProfitPercent: lastProfitPercent, - strategy: strategy, + strategy: strategyNumber, strategyPhase: strategyPhase, buyOrder: buyOrder, stopLossPhase: stopLossPhase, From 5fd4d9045fe98c8d0dcae3e35231a66e76d0a50c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 7 Mar 2019 13:56:27 +0100 Subject: [PATCH 033/244] Conditions working from simulationLogic --- Multi-Period-Market/User.Bot.js | 122 +++++++++++++++----------------- 1 file changed, 58 insertions(+), 64 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index dc1ac283d..c75d7016e 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -133,6 +133,7 @@ let candles = []; let recordsArray = []; let conditionsArray = []; + let simulationLogic = {}; nextPercentageBandwidth(); @@ -532,6 +533,7 @@ bollingerSubChannelsArray, recordsArray, conditionsArray, + simulationLogic, outputPeriod, writeRecordsFile) @@ -664,7 +666,7 @@ } fileContent = "[" + fileContent + "]"; - + fileContent = "[" + JSON.stringify(simulationLogic) + "," + fileContent + "]"; let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; @@ -770,6 +772,7 @@ bollingerSubChannelsArray, recordsArray, conditionsArray, + simulationLogic, outputPeriod, callback) { @@ -830,61 +833,58 @@ let newStopLoss; let initialBuffer = 3; - let conditionsHeadersSent = false; - const simulationLogic = { - strategies: [ - { - name: "Trend Following", - entryPoint: { - situations: [ - { - name: "Price Collapsing", - conditions: [ - { - name: "%B Moving Average going up", - code: "percentageBandwidth2.movingAverage > percentageBandwidth1.movingAverage && percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage" - }, - { - name: "%B Bandwidth going up", - code: "percentageBandwidth2.bandwidth < percentageBandwidth1.bandwidth && percentageBandwidth1.bandwidth < percentageBandwidth.bandwidth" - }, - { - name: "Candles Min going down", - code: "candles[i - 2].min > candles[i - 1].min && candles[i - 1].min > candle.min" - } - ] - } - ] - } - }, - { - name: "Range Trading", - entryPoint: { - situations: [ - { - name: "Gentle Up Trend", - conditions: [ - { - name: "Sub-Channel going up", - code: "subChannel.direction === 'Up'" - }, - { - name: "Sub-Channel Side|Gentle|Medium", - code: "subChannel.slope === 'Side' || subChannel.slope === 'Gentle' || subChannel.slope === 'Medium'" - }, - { - name: "Candle Close above Lower Band", - code: "candle.close > band.movingAverage + band.deviation" - } - ] - } - ] - } + simulationLogic.strategies = [ + { + name: "Trend Following", + entryPoint: { + situations: [ + { + name: "Price Collapsing", + conditions: [ + { + name: "%B Moving Average going up", + code: "percentageBandwidth2.movingAverage > percentageBandwidth1.movingAverage && percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage" + }, + { + name: "%B Bandwidth going up", + code: "percentageBandwidth2.bandwidth < percentageBandwidth1.bandwidth && percentageBandwidth1.bandwidth < percentageBandwidth.bandwidth" + }, + { + name: "Candles Min going down", + code: "candles[i - 2].min > candles[i - 1].min && candles[i - 1].min > candle.min" + } + ] + } + ] } - ] - }; - + }, + { + name: "Range Trading", + entryPoint: { + situations: [ + { + name: "Gentle Up Trend", + conditions: [ + { + name: "Sub-Channel going up", + code: "subChannel.direction === 'Up'" + }, + { + name: "Sub-Channel Side|Gentle|Medium", + code: "subChannel.slope === 'Side' || subChannel.slope === 'Gentle' || subChannel.slope === 'Medium'" + }, + { + name: "Candle Close above Lower Band", + code: "candle.close > band.movingAverage + band.deviation" + } + ] + } + ] + } + } + ]; + /* Main Simulation Loop: We go thourgh all the candles at this time period. */ for (let i = 0 + initialBuffer; i < candles.length; i++) { @@ -947,19 +947,13 @@ conditions.set(condition.key, condition); - if (conditionsHeadersSent === false) { - conditionsArrayRecord.push('"' + condition.key + '"'); + if (condition.value) { + conditionsArrayRecord.push(1); } else { - if (condition.value) { - conditionsArrayRecord.push(1); - } else { - conditionsArrayRecord.push(0); - } - } + conditionsArrayRecord.push(0); + } } - conditionsHeadersSent = true; - /* While we are outside all strategies, we evaluate whether it is time to enter one or not. */ if (strategyNumber === 0 && From 0a824d898308ea8f21122fd1bba43b206d2f9e5f Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 7 Mar 2019 19:04:27 +0100 Subject: [PATCH 034/244] Exit Points Incorporated --- Multi-Period-Market/User.Bot.js | 131 ++++++++++++++++++++++++++------ 1 file changed, 106 insertions(+), 25 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index c75d7016e..9db2d3230 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -857,6 +857,32 @@ ] } ] + }, + exitPoint: { + situations: [ + { + name: "Market Reversing", + conditions: [ + { + name: "Close above Band Moving Average", + code: "candle.close > band.movingAverage" + } + ] + } + ] + }, + sellPoint: { + situations: [ + { + name: "Min below lower band.", + conditions: [ + { + name: "3 Candles MIN below Lower Band", + code: "candles[i - 2].min < band2.movingAverage - band2.deviation && candles[i - 1].min < band1.movingAverage - band1.deviation && candle.min < band.movingAverage - band.deviation" + } + ] + } + ] } }, { @@ -881,10 +907,40 @@ ] } ] + }, + exitPoint: { + situations: [ + { + name: "Outside Sub-Channel", + conditions: [ + { + name: "Going down or too Steep", + code: "subChannel.direction === 'Down' || subChannel.slope === 'Steep' || subChannel.slope === 'Extreme'" + } + ] + } + ] + }, + sellPoint: { + situations: [ + { + name: "Min below lower band.", + conditions: [ + { + name: "%B Moving Average going down", + code: "percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage" + }, + { + name: "%B Moving Average above 90", + code: "percentageBandwidth1.movingAverage > 90" + } + ] + } + ] } } ]; - + /* Main Simulation Loop: We go thourgh all the candles at this time period. */ for (let i = 0 + initialBuffer; i < candles.length; i++) { @@ -934,6 +990,19 @@ newCondition(key, condition.code); } } + + for (let k = 0; k < strategy.exitPoint.situations.length; k++) { + + let situation = strategy.exitPoint.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + situation.name + '-' + condition.name + + newCondition(key, condition.code); + } + } } function newCondition(key, code) { @@ -1005,6 +1074,42 @@ } } + /* Strategy Exit Condition */ + + if (strategyPhase === 1) { + + checkExitPoints(); + + function checkExitPoints() { + + let strategy = simulationLogic.strategies[strategyNumber - 1]; + + for (let k = 0; k < strategy.exitPoint.situations.length; k++) { + + let situation = strategy.exitPoint.situations[k]; + let passed = true; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + situation.name + '-' + condition.name + + let value = conditions.get(key).value; + + if (value === false) { passed = false; } + } + + if (passed) { + + strategyPhase = 0; + strategyNumber = 0; + + return; + } + } + } + } + if (strategyPhase === 3) { /* Checking what happened since the last execution. We need to know if the Stop Loss @@ -1059,16 +1164,6 @@ */ - /* Strategy Exit Condition */ - - if ( - strategyPhase === 1 && - candle.close > band.movingAverage - ) { - strategyPhase = 0; - strategyNumber = 0; - }; - /* Sell Condition #1 */ /* if ( @@ -1237,20 +1332,6 @@ */ - /* Exist Strategy Condition */ - - if ( - strategyPhase === 1 && - (subChannel.direction === 'Down' || - subChannel.slope === 'Steep' || - subChannel.slope === 'Extreme' - ) - ) { - - strategyPhase = 0; - strategyNumber = 0; - - } /* Sell Condition #1 */ From 1b50d14ba2a20bca58652adf5b994cfd050566d5 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 7 Mar 2019 19:31:23 +0100 Subject: [PATCH 035/244] Sell Points --- Multi-Period-Market/User.Bot.js | 99 +++++++++++++++++---------------- 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 9db2d3230..655fea32d 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -1003,6 +1003,19 @@ newCondition(key, condition.code); } } + + for (let k = 0; k < strategy.sellPoint.situations.length; k++) { + + let situation = strategy.sellPoint.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + situation.name + '-' + condition.name + + newCondition(key, condition.code); + } + } } function newCondition(key, code) { @@ -1110,6 +1123,45 @@ } } + /* Strategy Sell Condition */ + + if (strategyPhase === 1) { + + checkSellPoints(); + + function checkSellPoints() { + + let strategy = simulationLogic.strategies[strategyNumber - 1]; + + for (let k = 0; k < strategy.sellPoint.situations.length; k++) { + + let situation = strategy.sellPoint.situations[k]; + let passed = true; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + situation.name + '-' + condition.name + + let value = conditions.get(key).value; + + if (value === false) { passed = false; } + } + + if (passed) { + + type = '"Sell"'; + + strategyPhase = 2; + stopLossPhase = 1; + buyOrderPhase = 1; + + return; + } + } + } + } + if (strategyPhase === 3) { /* Checking what happened since the last execution. We need to know if the Stop Loss @@ -1164,37 +1216,6 @@ */ - /* Sell Condition #1 */ - /* - if ( - strategyPhase === 1 && - band2.movingAverage > band1.movingAverage && - band1.movingAverage > band.movingAverage - ) { - - type = '"Sell-1"'; - - strategyPhase = 2; - stopLossPhase = 1; - buyOrderPhase = 1; - } - */ - /* Sell Condition #2 */ - - if ( - strategyPhase === 1 && - candles[i - 2].min < band2.movingAverage - band2.deviation && - candles[i - 1].min < band1.movingAverage - band1.deviation && - candle.min < band.movingAverage - band.deviation - ) { - - type = '"Sell-2"'; - - strategyPhase = 2; - stopLossPhase = 1; - buyOrderPhase = 1; - } - /* Stop Loss Management */ if (stopLossPhase === 3) { @@ -1333,22 +1354,6 @@ */ - /* Sell Condition #1 */ - - if ( - strategyPhase === 1 && - percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage && - percentageBandwidth1.movingAverage > 90 - - ) { - - type = '"Sell-1"'; - - strategyPhase = 2; - stopLossPhase = 1; - buyOrderPhase = 1; - } - /* Stop Loss Management */ if (stopLossPhase === 1) { From ac898ea2740462da7fe644082e407557416108ed Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 8 Mar 2019 11:09:01 +0100 Subject: [PATCH 036/244] Stop Loss at simulation logic --- Multi-Period-Market/User.Bot.js | 167 +++++++++++++++++++++++++++----- 1 file changed, 142 insertions(+), 25 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 655fea32d..0bc7ba70e 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -883,6 +883,50 @@ ] } ] + }, + stopLoss: { + phases: [ + { + name: "Following Sell Rate", + code: "newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100", + situations: [ + { + name: "Candle below Moving Average", + conditions: [ + { + name: "Candle fully below Band Moving Average", + code: "candle.max < band.movingAverage" + }, + { + name: "Band Moving Average going down", + code: "band1.movingAverage > band.movingAverage" + } + ] + } + ] + }, + { + name: "Above Bands Moving Average", + code: "newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100", + situations: [ + { + name: "Candle below Moving Average", + conditions: [ + { + name: "Candle MAX below lower band", + code: "candle.max < band.movingAverage - band.deviation" + } + ] + } + ] + }, + { + name: "At Bands Moving Average", + code: "newStopLoss = band.movingAverage", + situations: [ + ] + } + ] } }, { @@ -937,6 +981,16 @@ ] } ] + }, + stopLoss: { + phases: [ + { + name: "Following Sell Rate", + code: "newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100", + situations: [ + ] + } + ] } } ]; @@ -985,7 +1039,7 @@ for (let m = 0; m < situation.conditions.length; m++) { let condition = situation.conditions[m]; - let key = strategy.name + '-' + situation.name + '-' + condition.name + let key = strategy.name + '-' + situation.name + '-' + condition.name; newCondition(key, condition.code); } @@ -998,7 +1052,7 @@ for (let m = 0; m < situation.conditions.length; m++) { let condition = situation.conditions[m]; - let key = strategy.name + '-' + situation.name + '-' + condition.name + let key = strategy.name + '-' + situation.name + '-' + condition.name; newCondition(key, condition.code); } @@ -1011,11 +1065,29 @@ for (let m = 0; m < situation.conditions.length; m++) { let condition = situation.conditions[m]; - let key = strategy.name + '-' + situation.name + '-' + condition.name + let key = strategy.name + '-' + situation.name + '-' + condition.name; newCondition(key, condition.code); } } + + for (let p = 0; p < strategy.stopLoss.phases.length; p++) { + + let phase = strategy.stopLoss.phases[p]; + + for (let k = 0; k < phase.situations.length; k++) { + + let situation = phase.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name; + + newCondition(key, condition.code); + } + } + } } function newCondition(key, code) { @@ -1123,6 +1195,36 @@ } } + if (strategyPhase === 3) { + + /* Checking what happened since the last execution. We need to know if the Stop Loss + or our Buy Order were hit. */ + + /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ + + if (candle.max >= stopLoss) { + + balanceAssetA = balanceAssetB / stopLoss; + + balanceAssetB = 0; + rate = stopLoss; + type = '"Buy@StopLoss"'; + strategyPhase = 4; + } + + /* Buy Order condition: Here we verify if the Buy Order was filled or not. */ + + if (candle.min <= buyOrder) { + + balanceAssetA = balanceAssetB / buyOrder; + + balanceAssetB = 0; + rate = buyOrder; + type = '"Buy@BuyOrder"'; + strategyPhase = 4; + } + } + /* Strategy Sell Condition */ if (strategyPhase === 1) { @@ -1162,33 +1264,48 @@ } } + /* Stop Loss Management */ + if (strategyPhase === 3) { - /* Checking what happened since the last execution. We need to know if the Stop Loss - or our Buy Order were hit. */ + checkStopLoss(); - /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ + function checkStopLoss() { - if (candle.max >= stopLoss) { + let strategy = simulationLogic.strategies[strategyNumber - 1]; + + let phase = strategy.stopLoss.phases[stopLossPhase - 1]; - balanceAssetA = balanceAssetB / stopLoss; + eval(phase.code); // Here is where we apply the formula given for the stop loss for this phase. - balanceAssetB = 0; - rate = stopLoss; - type = '"Buy@StopLoss"'; - strategyPhase = 4; - } + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } - /* Buy Order condition: Here we verify if the Buy Order was filled or not. */ + for (let k = 0; k < phase.situations.length; k++) { - if (candle.min <= buyOrder) { + let situation = phase.situations[k]; + let passed = true; - balanceAssetA = balanceAssetB / buyOrder; + for (let m = 0; m < situation.conditions.length; m++) { - balanceAssetB = 0; - rate = buyOrder; - type = '"Buy@BuyOrder"'; - strategyPhase = 4; + let condition = situation.conditions[m]; + let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name + + let value = conditions.get(key).value; + + if (value === false) { passed = false; } + } + + if (passed) { + + stopLossPhase++; + + return; + } + } } } @@ -1217,7 +1334,7 @@ */ /* Stop Loss Management */ - + /* if (stopLossPhase === 3) { newStopLoss = band.movingAverage; @@ -1260,7 +1377,7 @@ stopLossDecay = stopLossDecay - stopLossDecayIncrement / 2; } - newStopLoss = newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; + newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; if (newStopLoss < previousStopLoss) { stopLoss = newStopLoss; @@ -1278,7 +1395,7 @@ } } - + */ /* Buy Orders Management */ if (buyOrderPhase === 5) { @@ -1355,7 +1472,7 @@ /* Stop Loss Management */ - + /* if (stopLossPhase === 1) { newStopLoss = newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; @@ -1366,7 +1483,7 @@ stopLoss = previousStopLoss; } } - + */ /* Buy Orders Management */ if (buyOrderPhase === 1) { From a8eafaec8c86ef96c41a2d7ea765968359faf4c7 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 8 Mar 2019 11:41:33 +0100 Subject: [PATCH 037/244] Remove comments of old stop loss code --- Multi-Period-Market/User.Bot.js | 122 ++++++++++++-------------------- 1 file changed, 45 insertions(+), 77 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 0bc7ba70e..faac81319 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -927,6 +927,50 @@ ] } ] + }, + buyOrder: { + phases: [ + { + name: "Following Sell Rate", + code: "newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100", + situations: [ + { + name: "Candle below Moving Average", + conditions: [ + { + name: "Candle fully below Band Moving Average", + code: "candle.max < band.movingAverage" + }, + { + name: "Band Moving Average going down", + code: "band1.movingAverage > band.movingAverage" + } + ] + } + ] + }, + { + name: "Above Bands Moving Average", + code: "newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100", + situations: [ + { + name: "Candle below Moving Average", + conditions: [ + { + name: "Candle MAX below lower band", + code: "candle.max < band.movingAverage - band.deviation" + } + ] + } + ] + }, + { + name: "At Bands Moving Average", + code: "newStopLoss = band.movingAverage", + situations: [ + ] + } + ] } }, { @@ -1333,69 +1377,7 @@ */ - /* Stop Loss Management */ - /* - if (stopLossPhase === 3) { - - newStopLoss = band.movingAverage; - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } - } - - if (stopLossPhase === 2) { - - if (band1.movingAverage < band.movingAverage) { - stopLossDecay = stopLossDecay + stopLossDecayIncrement * 2; - } else { - stopLossDecay = stopLossDecay - stopLossDecayIncrement / 2; - } - - newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100; - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } - - if ( - candle.max < band.movingAverage - band.deviation - ) { - stopLossPhase = 3; - } - } - - if (stopLossPhase === 1) { - - if (band1.movingAverage < band.movingAverage) { - stopLossDecay = stopLossDecay + stopLossDecayIncrement * 2; - } else { - stopLossDecay = stopLossDecay - stopLossDecayIncrement / 2; - } - - newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } - - if ( - strategyPhase === 3 && - candle.max < band.movingAverage && - band1.movingAverage > band.movingAverage - ) { - - stopLossPhase = 2; - - } - } - */ + /* Buy Orders Management */ if (buyOrderPhase === 5) { @@ -1470,20 +1452,6 @@ */ - - /* Stop Loss Management */ - /* - if (stopLossPhase === 1) { - - newStopLoss = newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100; - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } - } - */ /* Buy Orders Management */ if (buyOrderPhase === 1) { From b77c9e935b77394b20ff2a5831de1a91fbbf6501 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 8 Mar 2019 12:36:55 +0100 Subject: [PATCH 038/244] Buy order added to simulation logic --- Multi-Period-Market/User.Bot.js | 207 ++++++++++++++++---------------- 1 file changed, 103 insertions(+), 104 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index faac81319..518f4ab60 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -805,8 +805,7 @@ let buyOrderPercentage = 1; let previousBuyOrder = 0; let buyOrder = 0; - let buyOrderDecay = 0; - let buyOrderDecayIncrement = 0.01; + let buyOrderDecay = 0; let buyOrderPhase = 0; /* Building records */ @@ -931,15 +930,19 @@ buyOrder: { phases: [ { - name: "Following Sell Rate", - code: "newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100", + name: "12 times standard deviation", + code: "buyOrder = band.movingAverage - band.standardDeviation * 12", situations: [ { - name: "Candle below Moving Average", + name: "Candle cut by lower band", conditions: [ { - name: "Candle fully below Band Moving Average", - code: "candle.max < band.movingAverage" + name: "Max above lower band", + code: "candle.max > band.movingAverage - band.deviation" + }, + { + name: "MIN below lower band", + code: "candle.min < band.movingAverage - band.deviation" }, { name: "Band Moving Average going down", @@ -950,23 +953,61 @@ ] }, { - name: "Above Bands Moving Average", - code: "newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100", + name: "10 times standard deviation", + code: "buyOrder = band.movingAverage - band.standardDeviation * 10", situations: [ { - name: "Candle below Moving Average", + name: "%B starting to revert", conditions: [ { - name: "Candle MAX below lower band", - code: "candle.max < band.movingAverage - band.deviation" + name: "%B Moving Average going up", + code: "percentageBandwidth1.movingAverage < percentageBandwidth.movingAverage" + }, + { + name: "%B Moving Average above 0", + code: "percentageBandwidth.movingAverage > 0" } ] } ] }, { - name: "At Bands Moving Average", - code: "newStopLoss = band.movingAverage", + name: "4 times standard deviation", + code: "buyOrder = band.movingAverage - band.standardDeviation * 4", + situations: [ + { + name: "%B going down again", + conditions: [ + { + name: "%B Moving Average going down", + code: "percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage" + } + ] + } + ] + }, + { + name: "3 times standard deviation", + code: "buyOrder = band.movingAverage - band.standardDeviation * 3", + situations: [ + { + name: "%B going up and above 30", + conditions: [ + { + name: "%B Moving Average going up", + code: "percentageBandwidth1.movingAverage < percentageBandwidth.movingAverag" + }, + { + name: "%B Moving Average above 30", + code: "percentageBandwidth.movingAverage > 30" + } + ] + } + ] + }, + { + name: "At lower band", + code: "buyOrder = band.movingAverage - band.standardDeviation * 2", situations: [ ] } @@ -1035,6 +1076,16 @@ ] } ] + }, + buyOrder: { + phases: [ + { + name: "Between Band Moving Average and Lower Band", + code: "buyOrder = band.movingAverage - band.standardDeviation", + situations: [ + ] + } + ] } } ]; @@ -1132,6 +1183,24 @@ } } } + + for (let p = 0; p < strategy.buyOrder.phases.length; p++) { + + let phase = strategy.buyOrder.phases[p]; + + for (let k = 0; k < phase.situations.length; k++) { + + let situation = phase.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name; + + newCondition(key, condition.code); + } + } + } } function newCondition(key, code) { @@ -1353,112 +1422,42 @@ } } - if (strategyPhase < 4) { // When a buy condition has not been detected yet. + /* Buy Order Management */ - if (strategyNumber === 1) { + if (strategyPhase === 3) { - /* Strategy #1: Trend Following. */ + checkBuyOrder(); - /* - Strategy Summary: - - Once Percentage Bandwidth (PB) moving average is going down and - it is abobe 70%, we enter into Pre-Sell mode, which means that we are ready to - sell as soon as the trend starts going down. The trend should be measured by the - Bollinger Bands moving average. - - Once the band's moving average starts going down we Sell and we set the stop loss, - which initially is static or going down if the prices starts going up too. - - Once the candles minimun goes out of the lower Bollinger band, we enter into stop loss - trailing mode, which means that the stop loss will follow the band's moving average - from there on, getting closer or farther from it depending on the slope of the moving average - itself. - - */ + function checkBuyOrder() { - - /* Buy Orders Management */ + let strategy = simulationLogic.strategies[strategyNumber - 1]; - if (buyOrderPhase === 5) { + let phase = strategy.buyOrder.phases[buyOrderPhase - 1]; - buyOrder = band.movingAverage - band.standardDeviation * 2; + eval(phase.code); // Here is where we apply the formula given for the buy order at this phase. - } + for (let k = 0; k < phase.situations.length; k++) { - if (buyOrderPhase === 4) { + let situation = phase.situations[k]; + let passed = true; - buyOrder = band.movingAverage - band.standardDeviation * 3; + for (let m = 0; m < situation.conditions.length; m++) { - if ( - percentageBandwidth1.movingAverage < percentageBandwidth.movingAverage && - percentageBandwidth.movingAverage > 30 - ) { - buyOrderPhase = 5; + let condition = situation.conditions[m]; + let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name + + let value = conditions.get(key).value; + + if (value === false) { passed = false; } } - } - if (buyOrderPhase === 3) { + if (passed) { - buyOrder = band.movingAverage - band.standardDeviation * 4; + buyOrderPhase++; - if (percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage) { - buyOrderPhase = 4; + return; } } - - if (buyOrderPhase === 2) { - - buyOrder = band.movingAverage - band.standardDeviation * 10; - - if ( - percentageBandwidth1.movingAverage < percentageBandwidth.movingAverage && - percentageBandwidth.movingAverage > 0 - ) { - buyOrderPhase = 3; - } - } - - if (buyOrderPhase === 1) { - - buyOrderDecay = buyOrderDecay + buyOrderDecayIncrement; - - buyOrder = band.movingAverage - band.standardDeviation * 10; //+ band.movingAverage - band.standardDeviation * 4 * (buyOrderPercentage + buyOrderDecay) / 100; - - if ( - strategyPhase === 3 && - candle.max < band.movingAverage && - band1.movingAverage > band.movingAverage && - candle.min < band.movingAverage - band.deviation - ) { - - buyOrderPhase = 2; - - } - } - } - - if (strategyNumber === 2) { - - /* Strategy #2: Range Trading. */ - - /* - Strategy Summary: - - Once the candles maximun gets above the Bollinger Upper Band we wait until the B% moving average points - downward and then we Sell. - - We keep our buy order just below the the Bollinger Bands moving average. - - */ - - /* Buy Orders Management */ - - if (buyOrderPhase === 1) { - - buyOrder = band.movingAverage - band.standardDeviation; - - } } } From ec1f339e67889070e78518189dea5ab08fbf7c5e Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 8 Mar 2019 13:57:40 +0100 Subject: [PATCH 039/244] Sending extra status information to Conditions File --- Multi-Period-Market/User.Bot.js | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 518f4ab60..a7b4c3477 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -652,12 +652,14 @@ let conditions = ""; let conditionsSeparator = ""; - for (let j = 0; j < record.length; j++) { + for (let j = 0; j < record.length - 1; j++) { conditions = conditions + conditionsSeparator + record[j]; if (conditionsSeparator === "") { conditionsSeparator = ","; } } - fileContent = fileContent + separator + '[' + conditions + "]"; + conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of condition values. + + fileContent = fileContent + separator + '[' + conditions + ']'; if (separator === "") { separator = ","; } @@ -1115,8 +1117,9 @@ let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); - let conditions = new Map; - let conditionsArrayRecord = []; + let conditions = new Map; // Here we store the conditions values that will be use in the simulator for decision making. + let conditionsArrayRecord = []; // These are the records that will be saved in a file for the plotter to consume. + let conditionsArrayValues = []; // Here we store the conditions values that will be written on file for the plotter. /* We define and evaluate all conditions to be used later during the simulation loop. */ @@ -1215,9 +1218,9 @@ conditions.set(condition.key, condition); if (condition.value) { - conditionsArrayRecord.push(1); + conditionsArrayValues.push(1); } else { - conditionsArrayRecord.push(0); + conditionsArrayValues.push(0); } } @@ -1461,7 +1464,7 @@ } } - /* Check if a Sell condition was found. */ + /* Check if we need to sell. */ if (strategyPhase === 2) { @@ -1485,7 +1488,7 @@ continue; } - /* Check if a Buy condition was found. */ + /* Check if we need to buy. */ if (strategyPhase === 4) { @@ -1566,6 +1569,12 @@ type = '""'; + conditionsArrayRecord.push(strategyNumber); + conditionsArrayRecord.push(strategyPhase); + conditionsArrayRecord.push(stopLossPhase); + conditionsArrayRecord.push(buyOrderPhase); + conditionsArrayRecord.push(conditionsArrayValues); + conditionsArray.push(conditionsArrayRecord); } From ead46b26b1c07211b0b518b0f5280d8e84d45e0c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 15 Mar 2019 08:50:54 +0100 Subject: [PATCH 040/244] LRC indicator added. --- Commons.js | 22 +++- Multi-Period-Market/User.Bot.js | 203 +++++++++++++++++++++++++++++++- 2 files changed, 221 insertions(+), 4 deletions(-) diff --git a/Commons.js b/Commons.js index 7436a4d56..a6da45316 100644 --- a/Commons.js +++ b/Commons.js @@ -15,7 +15,7 @@ return thisObject; - function initializeStorage(chrisStorage, jasonStorage, oliviaStorage, callBackFunction) { + function initializeStorage(chrisStorage, jasonStorage, oliviaStorage, gaussStorage, callBackFunction) { try { @@ -48,7 +48,7 @@ if (err.result === global.DEFAULT_OK_RESPONSE.result) { - initializeOliviaStorage(); + initializeGaussStorage(); } else { logger.write(MODULE_NAME, "[ERROR] initializeStorage -> initializeChrisStorage -> onChrisInizialized -> err = " + err.message); @@ -57,6 +57,23 @@ } } + function initializeGaussStorage() { + + gaussStorage.initialize("AAVikings", onGaussInizialized); + + function onGaussInizialized(err) { + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + initializeOliviaStorage(); + + } else { + logger.write(MODULE_NAME, "[ERROR] initializeStorage -> initializeGaussStorage -> onChrisInizialized -> err = " + err.message); + callBackFunction(err); + } + } + } + function initializeOliviaStorage() { oliviaStorage.initialize(bot.devTeam, onOliviaInizialized); @@ -73,6 +90,7 @@ } } } + } catch (err) { logger.write(MODULE_NAME, "[ERROR] initializeStorage -> err = " + err.message); diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index a7b4c3477..9187477de 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -7,6 +7,7 @@ const EXCHANGE_NAME = "Poloniex"; + const LRC_FOLDER_NAME = "LRC-Points"; const PERCENTAGE_BANDWIDTH_FOLDER_NAME = "Percentage-Bandwidth"; const BOLLINGER_BANDS_FOLDER_NAME = "Bollinger-Bands"; const BOLLINGER_CHANNELS_FOLDER_NAME = "Bollinger-Channels"; @@ -22,6 +23,7 @@ start: start }; + let gaussStorage = BLOB_STORAGE.newBlobStorage(bot, logger); let chrisStorage = BLOB_STORAGE.newBlobStorage(bot, logger); let oliviaStorage = BLOB_STORAGE.newBlobStorage(bot, logger); let jasonStorage = BLOB_STORAGE.newBlobStorage(bot, logger); @@ -43,7 +45,7 @@ statusDependencies = pStatusDependencies; - commons.initializeStorage(chrisStorage, jasonStorage, oliviaStorage, onInizialized); + commons.initializeStorage(chrisStorage, jasonStorage, oliviaStorage, gaussStorage, onInizialized); function onInizialized(err) { @@ -125,6 +127,7 @@ */ let marketFile; + let LRCMap = new Map(); let percentageBandwidthMap = new Map(); let bollingerBandsMap = new Map(); let bollingerChannelsArray = []; @@ -135,7 +138,101 @@ let conditionsArray = []; let simulationLogic = {}; - nextPercentageBandwidth(); + nextLRC(); + + function nextLRC() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = "AAVikings" + "/" + "AAGauss" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + LRC_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + gaussStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildLRC(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildLRC() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildLRC -> Entering function."); } + + try { + + let previousLRC; + + for (let i = 0; i < marketFile.length; i++) { + + let LRC = { + begin: marketFile[i][0], + end: marketFile[i][1], + _15: marketFile[i][2], + _30: marketFile[i][3], + _60: marketFile[i][4] + }; + + if (previousLRC !== undefined) { + + if (previousLRC._15 > LRC._15) { LRC.direction15 = 'down'; } + if (previousLRC._15 < LRC._15) { LRC.direction15 = 'up'; } + if (previousLRC._15 === LRC._15) { LRC.direction15 = 'side'; } + + if (previousLRC._30 > LRC._30) { LRC.direction30 = 'down'; } + if (previousLRC._30 < LRC._30) { LRC.direction30 = 'up'; } + if (previousLRC._30 === LRC._30) { LRC.direction30 = 'side'; } + + if (previousLRC._60 > LRC._60) { LRC.direction60 = 'down'; } + if (previousLRC._60 < LRC._60) { LRC.direction60 = 'up'; } + if (previousLRC._60 === LRC._60) { LRC.direction60 = 'side'; } + + } + + LRCMap.set(LRC.begin, LRC); + + previousLRC = LRC; + } + + nextPercentageBandwidth(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildLRC -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } function nextPercentageBandwidth() { @@ -529,6 +626,7 @@ candles, bollingerBandsMap, percentageBandwidthMap, + LRCMap, bollingerChannelsArray, bollingerSubChannelsArray, recordsArray, @@ -770,6 +868,7 @@ candles, bollingerBandsMap, percentageBandwidthMap, + LRCMap, bollingerChannelsArray, bollingerSubChannelsArray, recordsArray, @@ -854,6 +953,10 @@ { name: "Candles Min going down", code: "candles[i - 2].min > candles[i - 1].min && candles[i - 1].min > candle.min" + }, + { + name: "Impossible", + code: " 1 === 2" } ] } @@ -1034,6 +1137,10 @@ { name: "Candle Close above Lower Band", code: "candle.close > band.movingAverage + band.deviation" + }, + { + name: "Impossible", + code: " 1 === 2" } ] } @@ -1090,6 +1197,96 @@ ] } } + , + { + name: "LRC Strategy", + entryPoint: { + situations: [ + { + name: "Lines in the right order", + conditions: [ + { + name: "60 > 30", + code: "LRC._60 > LRC._30" + }, + { + name: "30 > 15", + code: "LRC._30 > LRC._15" + } + ] + } + ] + }, + exitPoint: { + situations: [ + { + name: "Lines out of order", + conditions: [ + { + name: "60 < 30 or 30 < 15", + code: "LRC._60 < LRC._30 || LRC._30 < LRC._15 " + } + ] + } + ] + }, + sellPoint: { + situations: [ + { + name: "All lines going down", + conditions: [ + { + name: "60 going down", + code: "LRC.direction60 === 'down'" + }, + { + name: "30 going down", + code: "LRC.direction30 === 'down'" + }, + { + name: "15 going down", + code: "LRC.direction15 === 'down'" + } + ] + } + ] + }, + stopLoss: { + phases: [ + { + name: "Following Sell Rate", + code: "newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100", + situations: [ + { + name: "Stop Loss < 60", + conditions: [ + { + name: "Stop Loss < 60", + code: "stopLoss < LRC._60" + } + ] + } + ] + }, + { + name: "Following 60", + code: "newStopLoss = LRC._60", + situations: [ + ] + } + ] + }, + buyOrder: { + phases: [ + { + name: "Between Band Moving Average and Lower Band", + code: "buyOrder = band.movingAverage - band.standardDeviation * 4", + situations: [ + ] + } + ] + } + } ]; /* Main Simulation Loop: We go thourgh all the candles at this time period. */ @@ -1101,7 +1298,9 @@ let candle = candles[i]; let percentageBandwidth = percentageBandwidthMap.get(candle.begin); let band = bollingerBandsMap.get(candle.begin); + let LRC = LRCMap.get(candle.begin); + if (LRC === undefined) { continue; } if (percentageBandwidth === undefined) { continue; } // percentageBandwidth might start after the first few candles. if (candle.begin < initialDate.valueOf()) { continue; } From aadfbf14c1aa5ee194a26a4d1462c2a932d0a17c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 15 Mar 2019 09:10:37 +0100 Subject: [PATCH 041/244] previous in candles implemented --- Multi-Period-Market/User.Bot.js | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 9187477de..a3f07666e 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -593,6 +593,8 @@ try { + let previous; + for (let i = 0; i < marketFile.length; i++) { let candle = { @@ -618,8 +620,11 @@ if (candle.open < candle.close) { candle.direction = 'up'; } if (candle.open === candle.close) { candle.direction = 'side'; } + candle.previous = previous; + candles.push(candle); + previous = candle; } runSimulation( @@ -952,11 +957,7 @@ }, { name: "Candles Min going down", - code: "candles[i - 2].min > candles[i - 1].min && candles[i - 1].min > candle.min" - }, - { - name: "Impossible", - code: " 1 === 2" + code: "candle.previous.previous.min > candle.previous.min && candle.previous.min > candle.min" } ] } @@ -982,7 +983,7 @@ conditions: [ { name: "3 Candles MIN below Lower Band", - code: "candles[i - 2].min < band2.movingAverage - band2.deviation && candles[i - 1].min < band1.movingAverage - band1.deviation && candle.min < band.movingAverage - band.deviation" + code: "candle.previous.previous.min < band2.movingAverage - band2.deviation && candle.previous.min < band1.movingAverage - band1.deviation && candle.min < band.movingAverage - band.deviation" } ] } @@ -1212,6 +1213,10 @@ { name: "30 > 15", code: "LRC._30 > LRC._15" + }, + { + name: "Impossible", + code: " 1 === 2" } ] } @@ -1306,13 +1311,13 @@ periods++; - let band1 = bollingerBandsMap.get(candles[i - 1].begin); - let band2 = bollingerBandsMap.get(candles[i - 2].begin); - let band3 = bollingerBandsMap.get(candles[i - 3].begin); + let band1 = bollingerBandsMap.get(candle.previous.begin); + let band2 = bollingerBandsMap.get(candle.previous.previous.begin); + let band3 = bollingerBandsMap.get(candle.previous.previous.previous.begin); - let percentageBandwidth1 = percentageBandwidthMap.get(candles[i - 1].begin); - let percentageBandwidth2 = percentageBandwidthMap.get(candles[i - 2].begin); - let percentageBandwidth3 = percentageBandwidthMap.get(candles[i - 3].begin); + let percentageBandwidth1 = percentageBandwidthMap.get(candle.previous.begin); + let percentageBandwidth2 = percentageBandwidthMap.get(candle.previous.previous.begin); + let percentageBandwidth3 = percentageBandwidthMap.get(candle.previous.previous.previous.begin); let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); From c22b6e69cce54272ae469a596b3addee9f6511a7 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 15 Mar 2019 09:27:56 +0100 Subject: [PATCH 042/244] percentage B and bollinger bands with previous --- Multi-Period-Market/User.Bot.js | 74 +++++++++++++++++---------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index a3f07666e..edba5515e 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -286,6 +286,8 @@ try { + let previous; + for (let i = 0; i < marketFile.length; i++) { let percentageBandwidth = { @@ -296,8 +298,11 @@ bandwidth: marketFile[i][4] }; + percentageBandwidth.previous = percentageBandwidth; + percentageBandwidthMap.set(percentageBandwidth.begin, percentageBandwidth); + previous = percentageBandwidth; } nextBollingerBands(); @@ -361,6 +366,8 @@ try { + let previous; + for (let i = 0; i < marketFile.length; i++) { let bollingerBands = { @@ -371,8 +378,11 @@ deviation: marketFile[i][4] }; + bollingerBands.previous = previous; + bollingerBandsMap.set(bollingerBands.begin, bollingerBands); + previous = bollingerBands; } nextBollingerChannels(); @@ -949,11 +959,11 @@ conditions: [ { name: "%B Moving Average going up", - code: "percentageBandwidth2.movingAverage > percentageBandwidth1.movingAverage && percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage" + code: "percentageBandwidth.previous.previous.movingAverage > percentageBandwidth.previous.movingAverage && percentageBandwidth.previous.movingAverage > percentageBandwidth.movingAverage" }, { name: "%B Bandwidth going up", - code: "percentageBandwidth2.bandwidth < percentageBandwidth1.bandwidth && percentageBandwidth1.bandwidth < percentageBandwidth.bandwidth" + code: "percentageBandwidth.previous.previous.bandwidth < percentageBandwidth.previous.bandwidth && percentageBandwidth.previous.bandwidth < percentageBandwidth.bandwidth" }, { name: "Candles Min going down", @@ -970,7 +980,7 @@ conditions: [ { name: "Close above Band Moving Average", - code: "candle.close > band.movingAverage" + code: "candle.close > bollingerBand.movingAverage" } ] } @@ -979,11 +989,11 @@ sellPoint: { situations: [ { - name: "Min below lower band.", + name: "Min below lower bollingerBand.", conditions: [ { name: "3 Candles MIN below Lower Band", - code: "candle.previous.previous.min < band2.movingAverage - band2.deviation && candle.previous.min < band1.movingAverage - band1.deviation && candle.min < band.movingAverage - band.deviation" + code: "candle.previous.previous.min < bollingerBand.previous.previous.movingAverage - bollingerBand.previous.previous.deviation && candle.previous.min < bollingerBand.previous.movingAverage - bollingerBand.previous.deviation && candle.min < bollingerBand.movingAverage - bollingerBand.deviation" } ] } @@ -1000,11 +1010,11 @@ conditions: [ { name: "Candle fully below Band Moving Average", - code: "candle.max < band.movingAverage" + code: "candle.max < bollingerBand.movingAverage" }, { name: "Band Moving Average going down", - code: "band1.movingAverage > band.movingAverage" + code: "bollingerBand.previous.movingAverage > bollingerBand.movingAverage" } ] } @@ -1012,14 +1022,14 @@ }, { name: "Above Bands Moving Average", - code: "newStopLoss = band.movingAverage + band.movingAverage * (stopLossPercentage - stopLossDecay) / 100", + code: "newStopLoss = bollingerBand.movingAverage + bollingerBand.movingAverage * (stopLossPercentage - stopLossDecay) / 100", situations: [ { name: "Candle below Moving Average", conditions: [ { name: "Candle MAX below lower band", - code: "candle.max < band.movingAverage - band.deviation" + code: "candle.max < bollingerBand.movingAverage - bollingerBand.deviation" } ] } @@ -1027,7 +1037,7 @@ }, { name: "At Bands Moving Average", - code: "newStopLoss = band.movingAverage", + code: "newStopLoss = bollingerBand.movingAverage", situations: [ ] } @@ -1037,22 +1047,22 @@ phases: [ { name: "12 times standard deviation", - code: "buyOrder = band.movingAverage - band.standardDeviation * 12", + code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 12", situations: [ { name: "Candle cut by lower band", conditions: [ { name: "Max above lower band", - code: "candle.max > band.movingAverage - band.deviation" + code: "candle.max > bollingerBand.movingAverage - bollingerBand.deviation" }, { name: "MIN below lower band", - code: "candle.min < band.movingAverage - band.deviation" + code: "candle.min < bollingerBand.movingAverage - bollingerBand.deviation" }, { name: "Band Moving Average going down", - code: "band1.movingAverage > band.movingAverage" + code: "bollingerBand.previous.movingAverage > bollingerBand.movingAverage" } ] } @@ -1060,14 +1070,14 @@ }, { name: "10 times standard deviation", - code: "buyOrder = band.movingAverage - band.standardDeviation * 10", + code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 10", situations: [ { name: "%B starting to revert", conditions: [ { name: "%B Moving Average going up", - code: "percentageBandwidth1.movingAverage < percentageBandwidth.movingAverage" + code: "percentageBandwidth.previous.movingAverage < percentageBandwidth.movingAverage" }, { name: "%B Moving Average above 0", @@ -1079,14 +1089,14 @@ }, { name: "4 times standard deviation", - code: "buyOrder = band.movingAverage - band.standardDeviation * 4", + code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 4", situations: [ { name: "%B going down again", conditions: [ { name: "%B Moving Average going down", - code: "percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage" + code: "percentageBandwidth.previous.movingAverage > percentageBandwidth.movingAverage" } ] } @@ -1094,14 +1104,14 @@ }, { name: "3 times standard deviation", - code: "buyOrder = band.movingAverage - band.standardDeviation * 3", + code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 3", situations: [ { name: "%B going up and above 30", conditions: [ { name: "%B Moving Average going up", - code: "percentageBandwidth1.movingAverage < percentageBandwidth.movingAverag" + code: "percentageBandwidth.previous.movingAverage < percentageBandwidth.movingAverag" }, { name: "%B Moving Average above 30", @@ -1113,7 +1123,7 @@ }, { name: "At lower band", - code: "buyOrder = band.movingAverage - band.standardDeviation * 2", + code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 2", situations: [ ] } @@ -1137,7 +1147,7 @@ }, { name: "Candle Close above Lower Band", - code: "candle.close > band.movingAverage + band.deviation" + code: "candle.close > bollingerBand.movingAverage + bollingerBand.deviation" }, { name: "Impossible", @@ -1163,15 +1173,15 @@ sellPoint: { situations: [ { - name: "Min below lower band.", + name: "Min below lower bollingerBand.", conditions: [ { name: "%B Moving Average going down", - code: "percentageBandwidth1.movingAverage > percentageBandwidth.movingAverage" + code: "percentageBandwidth.previous.movingAverage > percentageBandwidth.movingAverage" }, { name: "%B Moving Average above 90", - code: "percentageBandwidth1.movingAverage > 90" + code: "percentageBandwidth.previous.movingAverage > 90" } ] } @@ -1191,7 +1201,7 @@ phases: [ { name: "Between Band Moving Average and Lower Band", - code: "buyOrder = band.movingAverage - band.standardDeviation", + code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation", situations: [ ] } @@ -1285,7 +1295,7 @@ phases: [ { name: "Between Band Moving Average and Lower Band", - code: "buyOrder = band.movingAverage - band.standardDeviation * 4", + code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 4", situations: [ ] } @@ -1302,7 +1312,7 @@ let candle = candles[i]; let percentageBandwidth = percentageBandwidthMap.get(candle.begin); - let band = bollingerBandsMap.get(candle.begin); + let bollingerBand = bollingerBandsMap.get(candle.begin); let LRC = LRCMap.get(candle.begin); if (LRC === undefined) { continue; } @@ -1311,14 +1321,6 @@ periods++; - let band1 = bollingerBandsMap.get(candle.previous.begin); - let band2 = bollingerBandsMap.get(candle.previous.previous.begin); - let band3 = bollingerBandsMap.get(candle.previous.previous.previous.begin); - - let percentageBandwidth1 = percentageBandwidthMap.get(candle.previous.begin); - let percentageBandwidth2 = percentageBandwidthMap.get(candle.previous.previous.begin); - let percentageBandwidth3 = percentageBandwidthMap.get(candle.previous.previous.previous.begin); - let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); let conditions = new Map; // Here we store the conditions values that will be use in the simulator for decision making. From 908e3357c7b6381bccfea5c7d074df18aa6893a9 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 15 Mar 2019 09:36:54 +0100 Subject: [PATCH 043/244] name standarized --- Multi-Period-Market/User.Bot.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index edba5515e..c823d8da1 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -192,7 +192,7 @@ try { - let previousLRC; + let previous; for (let i = 0; i < marketFile.length; i++) { @@ -204,25 +204,25 @@ _60: marketFile[i][4] }; - if (previousLRC !== undefined) { + if (previous !== undefined) { - if (previousLRC._15 > LRC._15) { LRC.direction15 = 'down'; } - if (previousLRC._15 < LRC._15) { LRC.direction15 = 'up'; } - if (previousLRC._15 === LRC._15) { LRC.direction15 = 'side'; } + if (previous._15 > LRC._15) { LRC.direction15 = 'down'; } + if (previous._15 < LRC._15) { LRC.direction15 = 'up'; } + if (previous._15 === LRC._15) { LRC.direction15 = 'side'; } - if (previousLRC._30 > LRC._30) { LRC.direction30 = 'down'; } - if (previousLRC._30 < LRC._30) { LRC.direction30 = 'up'; } - if (previousLRC._30 === LRC._30) { LRC.direction30 = 'side'; } + if (previous._30 > LRC._30) { LRC.direction30 = 'down'; } + if (previous._30 < LRC._30) { LRC.direction30 = 'up'; } + if (previous._30 === LRC._30) { LRC.direction30 = 'side'; } - if (previousLRC._60 > LRC._60) { LRC.direction60 = 'down'; } - if (previousLRC._60 < LRC._60) { LRC.direction60 = 'up'; } - if (previousLRC._60 === LRC._60) { LRC.direction60 = 'side'; } + if (previous._60 > LRC._60) { LRC.direction60 = 'down'; } + if (previous._60 < LRC._60) { LRC.direction60 = 'up'; } + if (previous._60 === LRC._60) { LRC.direction60 = 'side'; } } LRCMap.set(LRC.begin, LRC); - previousLRC = LRC; + previous = LRC; } nextPercentageBandwidth(); @@ -298,7 +298,7 @@ bandwidth: marketFile[i][4] }; - percentageBandwidth.previous = percentageBandwidth; + percentageBandwidth.previous = previous; percentageBandwidthMap.set(percentageBandwidth.begin, percentageBandwidth); From 59fda24d28640cd463c65af89458c8f7b167a477 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 15 Mar 2019 09:56:19 +0100 Subject: [PATCH 044/244] direction implemented on strategy logic --- Multi-Period-Market/User.Bot.js | 34 ++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index c823d8da1..1797fa834 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -298,6 +298,14 @@ bandwidth: marketFile[i][4] }; + if (previous !== undefined) { + + if (previous.movingAverage > percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'down'; } + if (previous.movingAverage < percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'up'; } + if (previous.movingAverage === percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'side'; } + + } + percentageBandwidth.previous = previous; percentageBandwidthMap.set(percentageBandwidth.begin, percentageBandwidth); @@ -370,7 +378,7 @@ for (let i = 0; i < marketFile.length; i++) { - let bollingerBands = { + let bollingerBand = { begin: marketFile[i][0], end: marketFile[i][1], movingAverage: marketFile[i][2], @@ -378,11 +386,19 @@ deviation: marketFile[i][4] }; - bollingerBands.previous = previous; + if (previous !== undefined) { - bollingerBandsMap.set(bollingerBands.begin, bollingerBands); + if (previous.movingAverage > bollingerBand.movingAverage) { bollingerBand.direction = 'down'; } + if (previous.movingAverage < bollingerBand.movingAverage) { bollingerBand.direction = 'up'; } + if (previous.movingAverage === bollingerBand.movingAverage) { bollingerBand.direction = 'side'; } - previous = bollingerBands; + } + + bollingerBand.previous = previous; + + bollingerBandsMap.set(bollingerBand.begin, bollingerBand); + + previous = bollingerBand; } nextBollingerChannels(); @@ -959,7 +975,7 @@ conditions: [ { name: "%B Moving Average going up", - code: "percentageBandwidth.previous.previous.movingAverage > percentageBandwidth.previous.movingAverage && percentageBandwidth.previous.movingAverage > percentageBandwidth.movingAverage" + code: "percentageBandwidth.previous.direction === 'down' && percentageBandwidth.direction === 'down'" }, { name: "%B Bandwidth going up", @@ -1014,7 +1030,7 @@ }, { name: "Band Moving Average going down", - code: "bollingerBand.previous.movingAverage > bollingerBand.movingAverage" + code: "bollingerBand.direction === 'down'" } ] } @@ -1077,7 +1093,7 @@ conditions: [ { name: "%B Moving Average going up", - code: "percentageBandwidth.previous.movingAverage < percentageBandwidth.movingAverage" + code: "percentageBandwidth.direction === 'up'" }, { name: "%B Moving Average above 0", @@ -1096,7 +1112,7 @@ conditions: [ { name: "%B Moving Average going down", - code: "percentageBandwidth.previous.movingAverage > percentageBandwidth.movingAverage" + code: "percentageBandwidth.direction === 'down'" } ] } @@ -1111,7 +1127,7 @@ conditions: [ { name: "%B Moving Average going up", - code: "percentageBandwidth.previous.movingAverage < percentageBandwidth.movingAverag" + code: "percentageBandwidth.direction === 'up'" }, { name: "%B Moving Average above 30", From 009417144c42004dff962fb456719ffdaf6cea76 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 15 Mar 2019 18:23:06 +0100 Subject: [PATCH 045/244] Simulator moved to Commons --- Commons.js | 937 ++++++++++++++++++++++++++++++- Multi-Period-Market/User.Bot.js | 938 +------------------------------- 2 files changed, 937 insertions(+), 938 deletions(-) diff --git a/Commons.js b/Commons.js index a6da45316..4fe9e107f 100644 --- a/Commons.js +++ b/Commons.js @@ -8,7 +8,8 @@ const GMT_SECONDS = ':00.000 GMT+0000'; let thisObject = { - initializeStorage: initializeStorage + initializeStorage: initializeStorage, + runSimulation: runSimulation }; let utilities = UTILITIES.newCloudUtilities(bot, logger); @@ -98,4 +99,938 @@ } } + function runSimulation( + candles, + bollingerBandsMap, + percentageBandwidthMap, + LRCMap, + bollingerChannelsArray, + bollingerSubChannelsArray, + recordsArray, + conditionsArray, + simulationLogic, + outputPeriod, + callback) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Entering function."); } + + /* Initial Values */ + + let initialDate = new Date("2018-08-01"); + let initialBalanceA = 1; + let minimunBalanceA = 0.5; + + /* Strategy and Phases */ + + let strategyNumber = 0; + let strategyPhase = 0; // So far we will consider 5 possible phases: 0 = Initial state, 1 = Signal to buy, 2 = Buy, 3 = After Buy, 4 = Sell. + + /* Stop Loss Management */ + + let stopLossPercentage = 1.5; + let previousStopLoss = 0; + let stopLoss = 0; + let stopLossDecay = 0; + let stopLossDecayIncrement = 0.06; + let stopLossPhase = 0; + + /* Buy Order Management */ + + let buyOrderPercentage = 1; + let previousBuyOrder = 0; + let buyOrder = 0; + let buyOrderDecay = 0; + let buyOrderPhase = 0; + + /* Building records */ + + let record; + let balanceAssetA = initialBalanceA; + let balanceAssetB = 0; + let profit = 0; + let lastProfit = 0; + let lastProfitPercent = 0; + let sellRate = 0; + + let previousBalanceAssetA = 0; + let roundtrips = 0; + let hits = 0; + let fails = 0; + let hitRatio = 0; + let ROI = 0; + let periods = 0; + let days = 0; + let anualizedRateOfReturn = 0; + let type = '""'; + let rate = 0; + let newStopLoss; + + let initialBuffer = 3; + + simulationLogic.strategies = [ + { + name: "Trend Following", + entryPoint: { + situations: [ + { + name: "Price Collapsing", + conditions: [ + { + name: "%B Moving Average going up", + code: "percentageBandwidth.previous.direction === 'down' && percentageBandwidth.direction === 'down'" + }, + { + name: "%B Bandwidth going up", + code: "percentageBandwidth.previous.previous.bandwidth < percentageBandwidth.previous.bandwidth && percentageBandwidth.previous.bandwidth < percentageBandwidth.bandwidth" + }, + { + name: "Candles Min going down", + code: "candle.previous.previous.min > candle.previous.min && candle.previous.min > candle.min" + } + ] + } + ] + }, + exitPoint: { + situations: [ + { + name: "Market Reversing", + conditions: [ + { + name: "Close above Band Moving Average", + code: "candle.close > bollingerBand.movingAverage" + } + ] + } + ] + }, + sellPoint: { + situations: [ + { + name: "Min below lower bollingerBand.", + conditions: [ + { + name: "3 Candles MIN below Lower Band", + code: "candle.previous.previous.min < bollingerBand.previous.previous.movingAverage - bollingerBand.previous.previous.deviation && candle.previous.min < bollingerBand.previous.movingAverage - bollingerBand.previous.deviation && candle.min < bollingerBand.movingAverage - bollingerBand.deviation" + } + ] + } + ] + }, + stopLoss: { + phases: [ + { + name: "Following Sell Rate", + code: "newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100", + situations: [ + { + name: "Candle below Moving Average", + conditions: [ + { + name: "Candle fully below Band Moving Average", + code: "candle.max < bollingerBand.movingAverage" + }, + { + name: "Band Moving Average going down", + code: "bollingerBand.direction === 'down'" + } + ] + } + ] + }, + { + name: "Above Bands Moving Average", + code: "newStopLoss = bollingerBand.movingAverage + bollingerBand.movingAverage * (stopLossPercentage - stopLossDecay) / 100", + situations: [ + { + name: "Candle below Moving Average", + conditions: [ + { + name: "Candle MAX below lower band", + code: "candle.max < bollingerBand.movingAverage - bollingerBand.deviation" + } + ] + } + ] + }, + { + name: "At Bands Moving Average", + code: "newStopLoss = bollingerBand.movingAverage", + situations: [ + ] + } + ] + }, + buyOrder: { + phases: [ + { + name: "12 times standard deviation", + code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 12", + situations: [ + { + name: "Candle cut by lower band", + conditions: [ + { + name: "Max above lower band", + code: "candle.max > bollingerBand.movingAverage - bollingerBand.deviation" + }, + { + name: "MIN below lower band", + code: "candle.min < bollingerBand.movingAverage - bollingerBand.deviation" + }, + { + name: "Band Moving Average going down", + code: "bollingerBand.previous.movingAverage > bollingerBand.movingAverage" + } + ] + } + ] + }, + { + name: "10 times standard deviation", + code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 10", + situations: [ + { + name: "%B starting to revert", + conditions: [ + { + name: "%B Moving Average going up", + code: "percentageBandwidth.direction === 'up'" + }, + { + name: "%B Moving Average above 0", + code: "percentageBandwidth.movingAverage > 0" + } + ] + } + ] + }, + { + name: "4 times standard deviation", + code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 4", + situations: [ + { + name: "%B going down again", + conditions: [ + { + name: "%B Moving Average going down", + code: "percentageBandwidth.direction === 'down'" + } + ] + } + ] + }, + { + name: "3 times standard deviation", + code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 3", + situations: [ + { + name: "%B going up and above 30", + conditions: [ + { + name: "%B Moving Average going up", + code: "percentageBandwidth.direction === 'up'" + }, + { + name: "%B Moving Average above 30", + code: "percentageBandwidth.movingAverage > 30" + } + ] + } + ] + }, + { + name: "At lower band", + code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 2", + situations: [ + ] + } + ] + } + }, + { + name: "Range Trading", + entryPoint: { + situations: [ + { + name: "Gentle Up Trend", + conditions: [ + { + name: "Sub-Channel going up", + code: "subChannel.direction === 'Up'" + }, + { + name: "Sub-Channel Side|Gentle|Medium", + code: "subChannel.slope === 'Side' || subChannel.slope === 'Gentle' || subChannel.slope === 'Medium'" + }, + { + name: "Candle Close above Lower Band", + code: "candle.close > bollingerBand.movingAverage + bollingerBand.deviation" + }, + { + name: "Impossible", + code: " 1 === 2" + } + ] + } + ] + }, + exitPoint: { + situations: [ + { + name: "Outside Sub-Channel", + conditions: [ + { + name: "Going down or too Steep", + code: "subChannel.direction === 'Down' || subChannel.slope === 'Steep' || subChannel.slope === 'Extreme'" + } + ] + } + ] + }, + sellPoint: { + situations: [ + { + name: "Min below lower bollingerBand.", + conditions: [ + { + name: "%B Moving Average going down", + code: "percentageBandwidth.previous.movingAverage > percentageBandwidth.movingAverage" + }, + { + name: "%B Moving Average above 90", + code: "percentageBandwidth.previous.movingAverage > 90" + } + ] + } + ] + }, + stopLoss: { + phases: [ + { + name: "Following Sell Rate", + code: "newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100", + situations: [ + ] + } + ] + }, + buyOrder: { + phases: [ + { + name: "Between Band Moving Average and Lower Band", + code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation", + situations: [ + ] + } + ] + } + } + , + { + name: "LRC Strategy", + entryPoint: { + situations: [ + { + name: "Lines in the right order", + conditions: [ + { + name: "60 > 30", + code: "LRC._60 > LRC._30" + }, + { + name: "30 > 15", + code: "LRC._30 > LRC._15" + }, + { + name: "Impossible", + code: " 1 === 2" + } + ] + } + ] + }, + exitPoint: { + situations: [ + { + name: "Lines out of order", + conditions: [ + { + name: "60 < 30 or 30 < 15", + code: "LRC._60 < LRC._30 || LRC._30 < LRC._15 " + } + ] + } + ] + }, + sellPoint: { + situations: [ + { + name: "All lines going down", + conditions: [ + { + name: "60 going down", + code: "LRC.direction60 === 'down'" + }, + { + name: "30 going down", + code: "LRC.direction30 === 'down'" + }, + { + name: "15 going down", + code: "LRC.direction15 === 'down'" + } + ] + } + ] + }, + stopLoss: { + phases: [ + { + name: "Following Sell Rate", + code: "newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100", + situations: [ + { + name: "Stop Loss < 60", + conditions: [ + { + name: "Stop Loss < 60", + code: "stopLoss < LRC._60" + } + ] + } + ] + }, + { + name: "Following 60", + code: "newStopLoss = LRC._60", + situations: [ + ] + } + ] + }, + buyOrder: { + phases: [ + { + name: "Between Band Moving Average and Lower Band", + code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 4", + situations: [ + ] + } + ] + } + } + ]; + + /* Main Simulation Loop: We go thourgh all the candles at this time period. */ + + for (let i = 0 + initialBuffer; i < candles.length; i++) { + + /* Update all the data objects available for the simulation. */ + + let candle = candles[i]; + let percentageBandwidth = percentageBandwidthMap.get(candle.begin); + let bollingerBand = bollingerBandsMap.get(candle.begin); + let LRC = LRCMap.get(candle.begin); + + if (LRC === undefined) { continue; } + if (percentageBandwidth === undefined) { continue; } // percentageBandwidth might start after the first few candles. + if (candle.begin < initialDate.valueOf()) { continue; } + + periods++; + + let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); + + let conditions = new Map; // Here we store the conditions values that will be use in the simulator for decision making. + let conditionsArrayRecord = []; // These are the records that will be saved in a file for the plotter to consume. + let conditionsArrayValues = []; // Here we store the conditions values that will be written on file for the plotter. + + /* We define and evaluate all conditions to be used later during the simulation loop. */ + + conditionsArrayRecord.push(candle.begin); + conditionsArrayRecord.push(candle.end); + + for (let j = 0; j < simulationLogic.strategies.length; j++) { + + let strategy = simulationLogic.strategies[j]; + + for (let k = 0; k < strategy.entryPoint.situations.length; k++) { + + let situation = strategy.entryPoint.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + situation.name + '-' + condition.name; + + newCondition(key, condition.code); + } + } + + for (let k = 0; k < strategy.exitPoint.situations.length; k++) { + + let situation = strategy.exitPoint.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + situation.name + '-' + condition.name; + + newCondition(key, condition.code); + } + } + + for (let k = 0; k < strategy.sellPoint.situations.length; k++) { + + let situation = strategy.sellPoint.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + situation.name + '-' + condition.name; + + newCondition(key, condition.code); + } + } + + for (let p = 0; p < strategy.stopLoss.phases.length; p++) { + + let phase = strategy.stopLoss.phases[p]; + + for (let k = 0; k < phase.situations.length; k++) { + + let situation = phase.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name; + + newCondition(key, condition.code); + } + } + } + + for (let p = 0; p < strategy.buyOrder.phases.length; p++) { + + let phase = strategy.buyOrder.phases[p]; + + for (let k = 0; k < phase.situations.length; k++) { + + let situation = phase.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name; + + newCondition(key, condition.code); + } + } + } + } + + function newCondition(key, code) { + + let condition; + + condition = { + key: key, + value: eval(code) + }; + + conditions.set(condition.key, condition); + + if (condition.value) { + conditionsArrayValues.push(1); + } else { + conditionsArrayValues.push(0); + } + } + + /* While we are outside all strategies, we evaluate whether it is time to enter one or not. */ + + if (strategyNumber === 0 && + balanceAssetA > minimunBalanceA) { + + /* + 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 an entering condition. Once we enter + into one strategy, we will ignore market conditions for others. However there is also + a strategy exit condition which can be hit before entering into a trade. If hit, we would + be outside a strategy again and looking for the condition to enter all over again. + + */ + + checkEntryPoints(); + + function checkEntryPoints() { + + for (let j = 0; j < simulationLogic.strategies.length; j++) { + + let strategy = simulationLogic.strategies[j]; + + for (let k = 0; k < strategy.entryPoint.situations.length; k++) { + + let situation = strategy.entryPoint.situations[k]; + let passed = true; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + situation.name + '-' + condition.name + + let value = conditions.get(key).value; + + if (value === false) { passed = false; } + } + + if (passed) { + + strategyPhase = 1; + strategyNumber = j + 1; + + return; + } + } + } + } + } + + /* Strategy Exit Condition */ + + if (strategyPhase === 1) { + + checkExitPoints(); + + function checkExitPoints() { + + let strategy = simulationLogic.strategies[strategyNumber - 1]; + + for (let k = 0; k < strategy.exitPoint.situations.length; k++) { + + let situation = strategy.exitPoint.situations[k]; + let passed = true; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + situation.name + '-' + condition.name + + let value = conditions.get(key).value; + + if (value === false) { passed = false; } + } + + if (passed) { + + strategyPhase = 0; + strategyNumber = 0; + + return; + } + } + } + } + + if (strategyPhase === 3) { + + /* Checking what happened since the last execution. We need to know if the Stop Loss + or our Buy Order were hit. */ + + /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ + + if (candle.max >= stopLoss) { + + balanceAssetA = balanceAssetB / stopLoss; + + balanceAssetB = 0; + rate = stopLoss; + type = '"Buy@StopLoss"'; + strategyPhase = 4; + } + + /* Buy Order condition: Here we verify if the Buy Order was filled or not. */ + + if (candle.min <= buyOrder) { + + balanceAssetA = balanceAssetB / buyOrder; + + balanceAssetB = 0; + rate = buyOrder; + type = '"Buy@BuyOrder"'; + strategyPhase = 4; + } + } + + /* Strategy Sell Condition */ + + if (strategyPhase === 1) { + + checkSellPoints(); + + function checkSellPoints() { + + let strategy = simulationLogic.strategies[strategyNumber - 1]; + + for (let k = 0; k < strategy.sellPoint.situations.length; k++) { + + let situation = strategy.sellPoint.situations[k]; + let passed = true; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + situation.name + '-' + condition.name + + let value = conditions.get(key).value; + + if (value === false) { passed = false; } + } + + if (passed) { + + type = '"Sell"'; + + strategyPhase = 2; + stopLossPhase = 1; + buyOrderPhase = 1; + + return; + } + } + } + } + + /* Stop Loss Management */ + + if (strategyPhase === 3) { + + checkStopLoss(); + + function checkStopLoss() { + + let strategy = simulationLogic.strategies[strategyNumber - 1]; + + let phase = strategy.stopLoss.phases[stopLossPhase - 1]; + + eval(phase.code); // Here is where we apply the formula given for the stop loss for this phase. + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } + + for (let k = 0; k < phase.situations.length; k++) { + + let situation = phase.situations[k]; + let passed = true; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name + + let value = conditions.get(key).value; + + if (value === false) { passed = false; } + } + + if (passed) { + + stopLossPhase++; + + return; + } + } + } + } + + /* Buy Order Management */ + + if (strategyPhase === 3) { + + checkBuyOrder(); + + function checkBuyOrder() { + + let strategy = simulationLogic.strategies[strategyNumber - 1]; + + let phase = strategy.buyOrder.phases[buyOrderPhase - 1]; + + eval(phase.code); // Here is where we apply the formula given for the buy order at this phase. + + for (let k = 0; k < phase.situations.length; k++) { + + let situation = phase.situations[k]; + let passed = true; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name + + let value = conditions.get(key).value; + + if (value === false) { passed = false; } + } + + if (passed) { + + buyOrderPhase++; + + return; + } + } + } + } + + /* Check if we need to sell. */ + + if (strategyPhase === 2) { + + previousBalanceAssetA = balanceAssetA; + lastProfit = 0; + lastProfitPercent = 0; + + balanceAssetB = balanceAssetA * candle.close; + balanceAssetA = 0; + + rate = candle.close; + sellRate = rate; + + stopLoss = sellRate + sellRate * stopLossPercentage / 100; + + stopLossDecay = 0; + + addRecord(); + + strategyPhase = 3; + continue; + } + + /* Check if we need to buy. */ + + if (strategyPhase === 4) { + + roundtrips++; + lastProfit = balanceAssetA - previousBalanceAssetA; + + lastProfitPercent = lastProfit / previousBalanceAssetA * 100; + if (isNaN(lastProfitPercent)) { lastProfitPercent = 0; } + + profit = profit + lastProfit; + + ROI = (initialBalanceA + profit) / initialBalanceA - 1; + //if (isNaN(ROI)) { ROI = 0; } + + if (lastProfit > 0) { + hits++; + } else { + fails++; + } + hitRatio = hits / roundtrips; + + let miliSecondsPerDay = 24 * 60 * 60 * 1000; + days = periods * outputPeriod / miliSecondsPerDay; + anualizedRateOfReturn = ROI / days * 365; + + addRecord(); + + strategyNumber = 0; + stopLoss = 0; + sellRate = 0; + buyOrder = 0; + strategyPhase = 0; + stopLossPhase = 0; + buyOrderPhase = 0; + + continue; + + } + + /* Not a buy or sell condition */ + + rate = candle.close; + addRecord(); + + function addRecord() { + + record = { + begin: candle.begin, + end: candle.end, + type: type, + rate: rate, + amount: 1, + balanceA: balanceAssetA, + balanceB: balanceAssetB, + profit: profit, + lastProfit: lastProfit, + stopLoss: stopLoss, + roundtrips: roundtrips, + hits: hits, + fails: fails, + hitRatio: hitRatio, + ROI: ROI, + periods: periods, + days: days, + anualizedRateOfReturn: anualizedRateOfReturn, + sellRate: sellRate, + lastProfitPercent: lastProfitPercent, + strategy: strategyNumber, + strategyPhase: strategyPhase, + buyOrder: buyOrder, + stopLossPhase: stopLossPhase, + buyOrderPhase: buyOrderPhase + } + + recordsArray.push(record); + + previousStopLoss = stopLoss; + + type = '""'; + + conditionsArrayRecord.push(strategyNumber); + conditionsArrayRecord.push(strategyPhase); + conditionsArrayRecord.push(stopLossPhase); + conditionsArrayRecord.push(buyOrderPhase); + conditionsArrayRecord.push(conditionsArrayValues); + + conditionsArray.push(conditionsArrayRecord); + + } + } + + callback(); + + function getElement(pArray, begin, end) { + + let element; + + for (let i = 0; i < pArray.length; i++) { + + element = pArray[i]; + + if (begin >= element.begin && end <= element.end) { + return element + } + } + + element = { + direction: 'unknown', + slope: 'unknown' + }; + return element; + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] runSimulation -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } }; \ No newline at end of file diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 1797fa834..102cd4145 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -653,7 +653,7 @@ previous = candle; } - runSimulation( + commons.runSimulation( candles, bollingerBandsMap, percentageBandwidthMap, @@ -894,942 +894,6 @@ callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - - function runSimulation( - candles, - bollingerBandsMap, - percentageBandwidthMap, - LRCMap, - bollingerChannelsArray, - bollingerSubChannelsArray, - recordsArray, - conditionsArray, - simulationLogic, - outputPeriod, - callback) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> runSimulation -> Entering function."); } - - /* Initial Values */ - - let initialDate = new Date("2018-08-01"); - let initialBalanceA = 1; - let minimunBalanceA = 0.5; - - /* Strategy and Phases */ - - let strategyNumber = 0; - let strategyPhase = 0; // So far we will consider 5 possible phases: 0 = Initial state, 1 = Signal to buy, 2 = Buy, 3 = After Buy, 4 = Sell. - - /* Stop Loss Management */ - - let stopLossPercentage = 1.5; - let previousStopLoss = 0; - let stopLoss = 0; - let stopLossDecay = 0; - let stopLossDecayIncrement = 0.06; - let stopLossPhase = 0; - - /* Buy Order Management */ - - let buyOrderPercentage = 1; - let previousBuyOrder = 0; - let buyOrder = 0; - let buyOrderDecay = 0; - let buyOrderPhase = 0; - - /* Building records */ - - let record; - let balanceAssetA = initialBalanceA; - let balanceAssetB = 0; - let profit = 0; - let lastProfit = 0; - let lastProfitPercent = 0; - let sellRate = 0; - - let previousBalanceAssetA = 0; - let roundtrips = 0; - let hits = 0; - let fails = 0; - let hitRatio = 0; - let ROI = 0; - let periods = 0; - let days = 0; - let anualizedRateOfReturn = 0; - let type = '""'; - let rate = 0; - let newStopLoss; - - let initialBuffer = 3; - - simulationLogic.strategies = [ - { - name: "Trend Following", - entryPoint: { - situations: [ - { - name: "Price Collapsing", - conditions: [ - { - name: "%B Moving Average going up", - code: "percentageBandwidth.previous.direction === 'down' && percentageBandwidth.direction === 'down'" - }, - { - name: "%B Bandwidth going up", - code: "percentageBandwidth.previous.previous.bandwidth < percentageBandwidth.previous.bandwidth && percentageBandwidth.previous.bandwidth < percentageBandwidth.bandwidth" - }, - { - name: "Candles Min going down", - code: "candle.previous.previous.min > candle.previous.min && candle.previous.min > candle.min" - } - ] - } - ] - }, - exitPoint: { - situations: [ - { - name: "Market Reversing", - conditions: [ - { - name: "Close above Band Moving Average", - code: "candle.close > bollingerBand.movingAverage" - } - ] - } - ] - }, - sellPoint: { - situations: [ - { - name: "Min below lower bollingerBand.", - conditions: [ - { - name: "3 Candles MIN below Lower Band", - code: "candle.previous.previous.min < bollingerBand.previous.previous.movingAverage - bollingerBand.previous.previous.deviation && candle.previous.min < bollingerBand.previous.movingAverage - bollingerBand.previous.deviation && candle.min < bollingerBand.movingAverage - bollingerBand.deviation" - } - ] - } - ] - }, - stopLoss: { - phases: [ - { - name: "Following Sell Rate", - code: "newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100", - situations: [ - { - name: "Candle below Moving Average", - conditions: [ - { - name: "Candle fully below Band Moving Average", - code: "candle.max < bollingerBand.movingAverage" - }, - { - name: "Band Moving Average going down", - code: "bollingerBand.direction === 'down'" - } - ] - } - ] - }, - { - name: "Above Bands Moving Average", - code: "newStopLoss = bollingerBand.movingAverage + bollingerBand.movingAverage * (stopLossPercentage - stopLossDecay) / 100", - situations: [ - { - name: "Candle below Moving Average", - conditions: [ - { - name: "Candle MAX below lower band", - code: "candle.max < bollingerBand.movingAverage - bollingerBand.deviation" - } - ] - } - ] - }, - { - name: "At Bands Moving Average", - code: "newStopLoss = bollingerBand.movingAverage", - situations: [ - ] - } - ] - }, - buyOrder: { - phases: [ - { - name: "12 times standard deviation", - code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 12", - situations: [ - { - name: "Candle cut by lower band", - conditions: [ - { - name: "Max above lower band", - code: "candle.max > bollingerBand.movingAverage - bollingerBand.deviation" - }, - { - name: "MIN below lower band", - code: "candle.min < bollingerBand.movingAverage - bollingerBand.deviation" - }, - { - name: "Band Moving Average going down", - code: "bollingerBand.previous.movingAverage > bollingerBand.movingAverage" - } - ] - } - ] - }, - { - name: "10 times standard deviation", - code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 10", - situations: [ - { - name: "%B starting to revert", - conditions: [ - { - name: "%B Moving Average going up", - code: "percentageBandwidth.direction === 'up'" - }, - { - name: "%B Moving Average above 0", - code: "percentageBandwidth.movingAverage > 0" - } - ] - } - ] - }, - { - name: "4 times standard deviation", - code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 4", - situations: [ - { - name: "%B going down again", - conditions: [ - { - name: "%B Moving Average going down", - code: "percentageBandwidth.direction === 'down'" - } - ] - } - ] - }, - { - name: "3 times standard deviation", - code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 3", - situations: [ - { - name: "%B going up and above 30", - conditions: [ - { - name: "%B Moving Average going up", - code: "percentageBandwidth.direction === 'up'" - }, - { - name: "%B Moving Average above 30", - code: "percentageBandwidth.movingAverage > 30" - } - ] - } - ] - }, - { - name: "At lower band", - code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 2", - situations: [ - ] - } - ] - } - }, - { - name: "Range Trading", - entryPoint: { - situations: [ - { - name: "Gentle Up Trend", - conditions: [ - { - name: "Sub-Channel going up", - code: "subChannel.direction === 'Up'" - }, - { - name: "Sub-Channel Side|Gentle|Medium", - code: "subChannel.slope === 'Side' || subChannel.slope === 'Gentle' || subChannel.slope === 'Medium'" - }, - { - name: "Candle Close above Lower Band", - code: "candle.close > bollingerBand.movingAverage + bollingerBand.deviation" - }, - { - name: "Impossible", - code: " 1 === 2" - } - ] - } - ] - }, - exitPoint: { - situations: [ - { - name: "Outside Sub-Channel", - conditions: [ - { - name: "Going down or too Steep", - code: "subChannel.direction === 'Down' || subChannel.slope === 'Steep' || subChannel.slope === 'Extreme'" - } - ] - } - ] - }, - sellPoint: { - situations: [ - { - name: "Min below lower bollingerBand.", - conditions: [ - { - name: "%B Moving Average going down", - code: "percentageBandwidth.previous.movingAverage > percentageBandwidth.movingAverage" - }, - { - name: "%B Moving Average above 90", - code: "percentageBandwidth.previous.movingAverage > 90" - } - ] - } - ] - }, - stopLoss: { - phases: [ - { - name: "Following Sell Rate", - code: "newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100", - situations: [ - ] - } - ] - }, - buyOrder: { - phases: [ - { - name: "Between Band Moving Average and Lower Band", - code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation", - situations: [ - ] - } - ] - } - } - , - { - name: "LRC Strategy", - entryPoint: { - situations: [ - { - name: "Lines in the right order", - conditions: [ - { - name: "60 > 30", - code: "LRC._60 > LRC._30" - }, - { - name: "30 > 15", - code: "LRC._30 > LRC._15" - }, - { - name: "Impossible", - code: " 1 === 2" - } - ] - } - ] - }, - exitPoint: { - situations: [ - { - name: "Lines out of order", - conditions: [ - { - name: "60 < 30 or 30 < 15", - code: "LRC._60 < LRC._30 || LRC._30 < LRC._15 " - } - ] - } - ] - }, - sellPoint: { - situations: [ - { - name: "All lines going down", - conditions: [ - { - name: "60 going down", - code: "LRC.direction60 === 'down'" - }, - { - name: "30 going down", - code: "LRC.direction30 === 'down'" - }, - { - name: "15 going down", - code: "LRC.direction15 === 'down'" - } - ] - } - ] - }, - stopLoss: { - phases: [ - { - name: "Following Sell Rate", - code: "newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100", - situations: [ - { - name: "Stop Loss < 60", - conditions: [ - { - name: "Stop Loss < 60", - code: "stopLoss < LRC._60" - } - ] - } - ] - }, - { - name: "Following 60", - code: "newStopLoss = LRC._60", - situations: [ - ] - } - ] - }, - buyOrder: { - phases: [ - { - name: "Between Band Moving Average and Lower Band", - code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 4", - situations: [ - ] - } - ] - } - } - ]; - - /* Main Simulation Loop: We go thourgh all the candles at this time period. */ - - for (let i = 0 + initialBuffer; i < candles.length; i++) { - - /* Update all the data objects available for the simulation. */ - - let candle = candles[i]; - let percentageBandwidth = percentageBandwidthMap.get(candle.begin); - let bollingerBand = bollingerBandsMap.get(candle.begin); - let LRC = LRCMap.get(candle.begin); - - if (LRC === undefined) { continue; } - if (percentageBandwidth === undefined) { continue; } // percentageBandwidth might start after the first few candles. - if (candle.begin < initialDate.valueOf()) { continue; } - - periods++; - - let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); - - let conditions = new Map; // Here we store the conditions values that will be use in the simulator for decision making. - let conditionsArrayRecord = []; // These are the records that will be saved in a file for the plotter to consume. - let conditionsArrayValues = []; // Here we store the conditions values that will be written on file for the plotter. - - /* We define and evaluate all conditions to be used later during the simulation loop. */ - - conditionsArrayRecord.push(candle.begin); - conditionsArrayRecord.push(candle.end); - - for (let j = 0; j < simulationLogic.strategies.length; j++) { - - let strategy = simulationLogic.strategies[j]; - - for (let k = 0; k < strategy.entryPoint.situations.length; k++) { - - let situation = strategy.entryPoint.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + situation.name + '-' + condition.name; - - newCondition(key, condition.code); - } - } - - for (let k = 0; k < strategy.exitPoint.situations.length; k++) { - - let situation = strategy.exitPoint.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + situation.name + '-' + condition.name; - - newCondition(key, condition.code); - } - } - - for (let k = 0; k < strategy.sellPoint.situations.length; k++) { - - let situation = strategy.sellPoint.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + situation.name + '-' + condition.name; - - newCondition(key, condition.code); - } - } - - for (let p = 0; p < strategy.stopLoss.phases.length; p++) { - - let phase = strategy.stopLoss.phases[p]; - - for (let k = 0; k < phase.situations.length; k++) { - - let situation = phase.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name; - - newCondition(key, condition.code); - } - } - } - - for (let p = 0; p < strategy.buyOrder.phases.length; p++) { - - let phase = strategy.buyOrder.phases[p]; - - for (let k = 0; k < phase.situations.length; k++) { - - let situation = phase.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name; - - newCondition(key, condition.code); - } - } - } - } - - function newCondition(key, code) { - - let condition; - - condition = { - key: key, - value: eval(code) - }; - - conditions.set(condition.key, condition); - - if (condition.value) { - conditionsArrayValues.push(1); - } else { - conditionsArrayValues.push(0); - } - } - - /* While we are outside all strategies, we evaluate whether it is time to enter one or not. */ - - if (strategyNumber === 0 && - balanceAssetA > minimunBalanceA) { - - /* - 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 an entering condition. Once we enter - into one strategy, we will ignore market conditions for others. However there is also - a strategy exit condition which can be hit before entering into a trade. If hit, we would - be outside a strategy again and looking for the condition to enter all over again. - - */ - - checkEntryPoints(); - - function checkEntryPoints() { - - for (let j = 0; j < simulationLogic.strategies.length; j++) { - - let strategy = simulationLogic.strategies[j]; - - for (let k = 0; k < strategy.entryPoint.situations.length; k++) { - - let situation = strategy.entryPoint.situations[k]; - let passed = true; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + situation.name + '-' + condition.name - - let value = conditions.get(key).value; - - if (value === false) { passed = false; } - } - - if (passed) { - - strategyPhase = 1; - strategyNumber = j + 1; - - return; - } - } - } - } - } - - /* Strategy Exit Condition */ - - if (strategyPhase === 1) { - - checkExitPoints(); - - function checkExitPoints() { - - let strategy = simulationLogic.strategies[strategyNumber - 1]; - - for (let k = 0; k < strategy.exitPoint.situations.length; k++) { - - let situation = strategy.exitPoint.situations[k]; - let passed = true; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + situation.name + '-' + condition.name - - let value = conditions.get(key).value; - - if (value === false) { passed = false; } - } - - if (passed) { - - strategyPhase = 0; - strategyNumber = 0; - - return; - } - } - } - } - - if (strategyPhase === 3) { - - /* Checking what happened since the last execution. We need to know if the Stop Loss - or our Buy Order were hit. */ - - /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - - if (candle.max >= stopLoss) { - - balanceAssetA = balanceAssetB / stopLoss; - - balanceAssetB = 0; - rate = stopLoss; - type = '"Buy@StopLoss"'; - strategyPhase = 4; - } - - /* Buy Order condition: Here we verify if the Buy Order was filled or not. */ - - if (candle.min <= buyOrder) { - - balanceAssetA = balanceAssetB / buyOrder; - - balanceAssetB = 0; - rate = buyOrder; - type = '"Buy@BuyOrder"'; - strategyPhase = 4; - } - } - - /* Strategy Sell Condition */ - - if (strategyPhase === 1) { - - checkSellPoints(); - - function checkSellPoints() { - - let strategy = simulationLogic.strategies[strategyNumber - 1]; - - for (let k = 0; k < strategy.sellPoint.situations.length; k++) { - - let situation = strategy.sellPoint.situations[k]; - let passed = true; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + situation.name + '-' + condition.name - - let value = conditions.get(key).value; - - if (value === false) { passed = false; } - } - - if (passed) { - - type = '"Sell"'; - - strategyPhase = 2; - stopLossPhase = 1; - buyOrderPhase = 1; - - return; - } - } - } - } - - /* Stop Loss Management */ - - if (strategyPhase === 3) { - - checkStopLoss(); - - function checkStopLoss() { - - let strategy = simulationLogic.strategies[strategyNumber - 1]; - - let phase = strategy.stopLoss.phases[stopLossPhase - 1]; - - eval(phase.code); // Here is where we apply the formula given for the stop loss for this phase. - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } - - for (let k = 0; k < phase.situations.length; k++) { - - let situation = phase.situations[k]; - let passed = true; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name - - let value = conditions.get(key).value; - - if (value === false) { passed = false; } - } - - if (passed) { - - stopLossPhase++; - - return; - } - } - } - } - - /* Buy Order Management */ - - if (strategyPhase === 3) { - - checkBuyOrder(); - - function checkBuyOrder() { - - let strategy = simulationLogic.strategies[strategyNumber - 1]; - - let phase = strategy.buyOrder.phases[buyOrderPhase - 1]; - - eval(phase.code); // Here is where we apply the formula given for the buy order at this phase. - - for (let k = 0; k < phase.situations.length; k++) { - - let situation = phase.situations[k]; - let passed = true; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name - - let value = conditions.get(key).value; - - if (value === false) { passed = false; } - } - - if (passed) { - - buyOrderPhase++; - - return; - } - } - } - } - - /* Check if we need to sell. */ - - if (strategyPhase === 2) { - - previousBalanceAssetA = balanceAssetA; - lastProfit = 0; - lastProfitPercent = 0; - - balanceAssetB = balanceAssetA * candle.close; - balanceAssetA = 0; - - rate = candle.close; - sellRate = rate; - - stopLoss = sellRate + sellRate * stopLossPercentage / 100; - - stopLossDecay = 0; - - addRecord(); - - strategyPhase = 3; - continue; - } - - /* Check if we need to buy. */ - - if (strategyPhase === 4) { - - roundtrips++; - lastProfit = balanceAssetA - previousBalanceAssetA; - - lastProfitPercent = lastProfit / previousBalanceAssetA * 100; - if (isNaN(lastProfitPercent)) { lastProfitPercent = 0; } - - profit = profit + lastProfit; - - ROI = (initialBalanceA + profit) / initialBalanceA - 1; - //if (isNaN(ROI)) { ROI = 0; } - - if (lastProfit > 0) { - hits++; - } else { - fails++; - } - hitRatio = hits / roundtrips; - - let miliSecondsPerDay = 24 * 60 * 60 * 1000; - days = periods * outputPeriod / miliSecondsPerDay; - anualizedRateOfReturn = ROI / days * 365; - - addRecord(); - - strategyNumber = 0; - stopLoss = 0; - sellRate = 0; - buyOrder = 0; - strategyPhase = 0; - stopLossPhase = 0; - buyOrderPhase = 0; - - continue; - - } - - /* Not a buy or sell condition */ - - rate = candle.close; - addRecord(); - - function addRecord() { - - record = { - begin: candle.begin, - end: candle.end, - type: type, - rate: rate, - amount: 1, - balanceA: balanceAssetA, - balanceB: balanceAssetB, - profit: profit, - lastProfit: lastProfit, - stopLoss: stopLoss, - roundtrips: roundtrips, - hits: hits, - fails: fails, - hitRatio: hitRatio, - ROI: ROI, - periods: periods, - days: days, - anualizedRateOfReturn: anualizedRateOfReturn, - sellRate: sellRate, - lastProfitPercent: lastProfitPercent, - strategy: strategyNumber, - strategyPhase: strategyPhase, - buyOrder: buyOrder, - stopLossPhase: stopLossPhase, - buyOrderPhase: buyOrderPhase - } - - recordsArray.push(record); - - previousStopLoss = stopLoss; - - type = '""'; - - conditionsArrayRecord.push(strategyNumber); - conditionsArrayRecord.push(strategyPhase); - conditionsArrayRecord.push(stopLossPhase); - conditionsArrayRecord.push(buyOrderPhase); - conditionsArrayRecord.push(conditionsArrayValues); - - conditionsArray.push(conditionsArrayRecord); - - } - } - - callback(); - - function getElement(pArray, begin, end) { - - let element; - - for (let i = 0; i < pArray.length; i++) { - - element = pArray[i]; - - if (begin >= element.begin && end <= element.end) { - return element - } - } - - element = { - direction: 'unknown', - slope: 'unknown' - }; - return element; - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> runSimulation -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } catch (err) { From a5181bc980932c143ccd48a6db5a73854ca120f4 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 15 Mar 2019 18:38:49 +0100 Subject: [PATCH 046/244] Add previous at all missing places. --- Multi-Period-Market/User.Bot.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 102cd4145..02193f6d0 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -220,6 +220,8 @@ } + LRC.previous = previous; + LRCMap.set(LRC.begin, LRC); previous = LRC; @@ -462,6 +464,8 @@ try { + let previous; + for (let i = 0; i < marketFile.length; i++) { let bollingerChannel = { @@ -475,8 +479,11 @@ lastDeviation: marketFile[i][7] }; + bollingerChannel.previous = previous; + bollingerChannelsArray.push(bollingerChannel); + previous = bollingerChannel; } nextBollingerSubChannels(); @@ -540,6 +547,8 @@ try { + let previous; + for (let i = 0; i < marketFile.length; i++) { let bollingerSubChannel = { @@ -554,8 +563,11 @@ lastDeviation: marketFile[i][8] }; + bollingerSubChannel.previous = previous; + bollingerSubChannelsArray.push(bollingerSubChannel); + previous = bollingerSubChannel; } nextCandlesFile(); From aa04a2b0e044be78bff3386bc5016f257e30293c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 Mar 2019 10:33:02 +0100 Subject: [PATCH 047/244] Data Dependencies Added to Config --- Commons.js | 2 +- Multi-Period-Daily/User.Bot.js | 845 +++++++++++++++++++++++++-------- this.bot.config.json | 48 ++ 3 files changed, 698 insertions(+), 197 deletions(-) diff --git a/Commons.js b/Commons.js index 4fe9e107f..53bfce367 100644 --- a/Commons.js +++ b/Commons.js @@ -359,7 +359,7 @@ conditions: [ { name: "Sub-Channel going up", - code: "subChannel.direction === 'Up'" + code: "subChannel.direction === 'up'" }, { name: "Sub-Channel Side|Gentle|Medium", diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index abcd97979..5e94c9d31 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -64,14 +64,6 @@ } } - /* - - This process is going to do the following: - - Read the bands from Chris and produce daily files with bollinger trades. - - */ - function start(callBackFunction) { try { @@ -317,229 +309,615 @@ const timePeriod = global.dailyFilePeriods[n][1]; - let bands = []; // Here we will put all the bands of the 2 files read. + let marketFile; - let previousDayFile; - let processDayFile; + let LRCMap = new Map(); + let percentageBandwidthMap = new Map(); + let bollingerBandsMap = new Map(); + let bollingerChannelsArray = []; + let bollingerSubChannelsArray = []; - getPreviousDayFile(); + let candles = []; + let recordsArray = []; + let conditionsArray = []; + let simulationLogic = {}; - function getPreviousDayFile() { + nextLRC(); + + function nextLRC() { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> getPreviousDayFile -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> Entering function."); } - let dateForPath = previousDay.getUTCFullYear() + '/' + utilities.pad(previousDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(previousDay.getUTCDate(), 2); + let dateForPath = fileDate.getUTCFullYear() + '/' + utilities.pad(fileDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(fileDate.getUTCDate(), 2); let fileName = market.assetA + '_' + market.assetB + ".json" - let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + "Multi-Period-Daily" + "/" + timePeriod + "/" + dateForPath; + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + CANDLE_STAIRS_FOLDER_NAME + '/' + "Multi-Period-Daily" + "/" + timePeriod + "/" + dateForPath; - chrisStorage.getTextFile(filePath, fileName, onCurrentDayFileReceived, true); - function onCurrentDayFileReceived(err, text) { + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = "AAVikings" + "/" + "AAGauss" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + LRC_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + gaussStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> text = " + text); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> text = " + text); } - previousDayFile = JSON.parse(text); - getProcessDayFile() + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> market = " + market.assetA + '_' + market.assetB); - - callBackFunction(global.DEFAULT_RETRY_RESPONSE); - } - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> getPreviousDayFile -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function getProcessDayFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> getProcessDayFile -> Entering function."); } - - let dateForPath = processDate.getUTCFullYear() + '/' + utilities.pad(processDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(processDate.getUTCDate(), 2); - let fileName = market.assetA + '_' + market.assetB + ".json" - - let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + "Multi-Period-Daily" + "/" + timePeriod + "/" + dateForPath; - - chrisStorage.getTextFile(filePath, fileName, onCurrentDayFileReceived, true); - - function onCurrentDayFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> text = " + text); } - - processDayFile = JSON.parse(text); - buildTrades(); - - } catch (err) { - - if (processDate.valueOf() > contextVariables.maxTradeFile.valueOf()) { - - processDayFile = []; // we are past the head of the market, then no worries if this file is non existent. - buildTrades(); - - } else { - - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> market = " + market.assetA + '_' + market.assetB); - - callBackFunction(global.DEFAULT_RETRY_RESPONSE); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> err = " + err.message); + callBackFunction(err); return; + } + + marketFile = JSON.parse(text); + + buildLRC(); + + } - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> getProcessDayFile -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildTrades() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> buildTrades -> Entering function."); } - - addBandsToSingleArray(previousDayFile); - addBandsToSingleArray(processDayFile); - calculateTrades(); - - function addBandsToSingleArray(bandsFile) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> buildTrades -> addBandsToSingleArray -> Entering function."); } - - for (let i = 0; i < bandsFile.length; i++) { - - let band = { - open: undefined, - close: undefined, - min: 10000000000000, - max: 0, - begin: undefined, - end: undefined, - direction: undefined - }; - - band.min = bandsFile[i][0]; - band.max = bandsFile[i][1]; - - band.open = bandsFile[i][2]; - band.close = bandsFile[i][3]; - - band.begin = bandsFile[i][4]; - band.end = bandsFile[i][5]; - - if (band.open > band.close) { band.direction = 'down'; } - if (band.open < band.close) { band.direction = 'up'; } - if (band.open === band.close) { band.direction = 'side'; } - - bands.push(band); - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> buildTrades -> addBandsToSingleArray -> err = " + err.message); + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); - return; } } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> buildTrades -> err = " + err.message); + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); - return; } } - function calculateTrades() { + function buildLRC() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildLRC -> Entering function."); } try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> calculateTrades -> Entering function."); } + let previous; - let tradesArray = []; - let numberOfPeriods = 20; + for (let i = 0; i < marketFile.length; i++) { - /* Building trades */ - - let trade; - - for (let i = numberOfPeriods - 1; i < bands.length; i++) { // Go through all the bands to generate a trade segment for each of them. - - let movingAverage = 0; - for (let j = i - numberOfPeriods + 1; j < i + 1; j++) { // go through the last n bands to calculate the moving average. - movingAverage = movingAverage + bands[j].close; - } - movingAverage = movingAverage / numberOfPeriods; - - let standardDeviation = 0; - for (let j = i - numberOfPeriods + 1; j < i + 1; j++) { // go through the last n bands to calculate the standard deviation. - standardDeviation = standardDeviation + Math.pow(bands[j].close - movingAverage, 2); - } - standardDeviation = standardDeviation / numberOfPeriods; - standardDeviation = Math.sqrt(standardDeviation); - - trade = { - begin: bands[i].begin, - end: bands[i].end, - movingAverage: movingAverage, - standardDeviation: standardDeviation + let LRC = { + begin: marketFile[i][0], + end: marketFile[i][1], + _15: marketFile[i][2], + _30: marketFile[i][3], + _60: marketFile[i][4] }; - /* Will only add to the array the trades of the current day */ + if (previous !== undefined) { - if (trade.begin >= processDate.valueOf()) { tradesArray.push(trade); } - + if (previous._15 > LRC._15) { LRC.direction15 = 'down'; } + if (previous._15 < LRC._15) { LRC.direction15 = 'up'; } + if (previous._15 === LRC._15) { LRC.direction15 = 'side'; } + + if (previous._30 > LRC._30) { LRC.direction30 = 'down'; } + if (previous._30 < LRC._30) { LRC.direction30 = 'up'; } + if (previous._30 === LRC._30) { LRC.direction30 = 'side'; } + + if (previous._60 > LRC._60) { LRC.direction60 = 'down'; } + if (previous._60 < LRC._60) { LRC.direction60 = 'up'; } + if (previous._60 === LRC._60) { LRC.direction60 = 'side'; } + + } + + LRC.previous = previous; + + LRCMap.set(LRC.begin, LRC); + + previous = LRC; } - writeFile(tradesArray); + nextPercentageBandwidth(); - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> calculateTrades -> err = " + err.message); + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildLRC -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); - return; } } - function writeFile(pTrades, callback) { + function nextPercentageBandwidth() { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> writeTradeTradesFile -> writeFile -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + PERCENTAGE_BANDWIDTH_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildPercentageBandwidthMap(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildPercentageBandwidthMap() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildPercentageBandwidthMap -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < marketFile.length; i++) { + + let percentageBandwidth = { + begin: marketFile[i][0], + end: marketFile[i][1], + value: marketFile[i][2], + movingAverage: marketFile[i][3], + bandwidth: marketFile[i][4] + }; + + if (previous !== undefined) { + + if (previous.movingAverage > percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'down'; } + if (previous.movingAverage < percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'up'; } + if (previous.movingAverage === percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'side'; } + + } + + percentageBandwidth.previous = previous; + + percentageBandwidthMap.set(percentageBandwidth.begin, percentageBandwidth); + + previous = percentageBandwidth; + } + + nextBollingerBands(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildPercentageBandwidthMap -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function nextBollingerBands() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + BOLLINGER_BANDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildBollingerBandsMap(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildBollingerBandsMap() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerBandsMap -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < marketFile.length; i++) { + + let bollingerBand = { + begin: marketFile[i][0], + end: marketFile[i][1], + movingAverage: marketFile[i][2], + standardDeviation: marketFile[i][3], + deviation: marketFile[i][4] + }; + + if (previous !== undefined) { + + if (previous.movingAverage > bollingerBand.movingAverage) { bollingerBand.direction = 'down'; } + if (previous.movingAverage < bollingerBand.movingAverage) { bollingerBand.direction = 'up'; } + if (previous.movingAverage === bollingerBand.movingAverage) { bollingerBand.direction = 'side'; } + + } + + bollingerBand.previous = previous; + + bollingerBandsMap.set(bollingerBand.begin, bollingerBand); + + previous = bollingerBand; + } + + nextBollingerChannels(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerBandsMap -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function nextBollingerChannels() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = bot.devTeam + "/" + "AAPaula" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + BOLLINGER_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildBollingerChannelsArray(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildBollingerChannelsArray() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerChannelsArray -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < marketFile.length; i++) { + + let bollingerChannel = { + begin: marketFile[i][0], + end: marketFile[i][1], + direction: marketFile[i][2], + period: marketFile[i][3], + firstMovingAverage: marketFile[i][4], + lastMovingAverage: marketFile[i][5], + firstDeviation: marketFile[i][6], + lastDeviation: marketFile[i][7] + }; + + bollingerChannel.previous = previous; + + bollingerChannelsArray.push(bollingerChannel); + + previous = bollingerChannel; + } + + nextBollingerSubChannels(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerChannelsArray -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function nextBollingerSubChannels() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = bot.devTeam + "/" + "AAPaula" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + BOLLINGER_SUB_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildBollingerSubChannelsArray(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildBollingerSubChannelsArray() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerSubChannelsArray -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < marketFile.length; i++) { + + let bollingerSubChannel = { + begin: marketFile[i][0], + end: marketFile[i][1], + direction: marketFile[i][2], + slope: marketFile[i][3], + period: marketFile[i][4], + firstMovingAverage: marketFile[i][5], + lastMovingAverage: marketFile[i][6], + firstDeviation: marketFile[i][7], + lastDeviation: marketFile[i][8] + }; + + bollingerSubChannel.previous = previous; + + bollingerSubChannelsArray.push(bollingerSubChannel); + + previous = bollingerSubChannel; + } + + nextCandlesFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerSubChannelsArray -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function nextCandlesFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> Entering function."); } + + let fileName = market.assetA + '_' + market.assetB + ".json"; + + let filePathRoot = bot.devTeam + "/" + "AAOlivia" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + oliviaStorage.getTextFile(filePath, fileName, onFileReceived, true); + + function onFileReceived(err, text) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> text = " + text); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> err = " + err.message); + callBackFunction(err); + return; + + } + + marketFile = JSON.parse(text); + + buildCandles(); + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildCandles() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildCandles -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < marketFile.length; i++) { + + let candle = { + open: undefined, + close: undefined, + min: 10000000000000, + max: 0, + begin: undefined, + end: undefined, + direction: undefined + }; + + candle.min = marketFile[i][0]; + candle.max = marketFile[i][1]; + + candle.open = marketFile[i][2]; + candle.close = marketFile[i][3]; + + candle.begin = marketFile[i][4]; + candle.end = marketFile[i][5]; + + if (candle.open > candle.close) { candle.direction = 'down'; } + if (candle.open < candle.close) { candle.direction = 'up'; } + if (candle.open === candle.close) { candle.direction = 'side'; } + + candle.previous = previous; + + candles.push(candle); + + previous = candle; + } + + commons.runSimulation( + candles, + bollingerBandsMap, + percentageBandwidthMap, + LRCMap, + bollingerChannelsArray, + bollingerSubChannelsArray, + recordsArray, + conditionsArray, + simulationLogic, + outputPeriod, + writeRecordsFile) + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildCandles -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeRecordsFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> Entering function."); } let separator = ""; let fileRecordCounter = 0; let fileContent = ""; - for (i = 0; i < pTrades.length; i++) { + for (let i = 0; i < recordsArray.length; i++) { - let trade = pTrades[i]; + let record = recordsArray[i]; fileContent = fileContent + separator + '[' + - trade.begin + "," + - trade.end + "," + - trade.movingAverage + "," + - trade.standardDeviation + "]"; + record.begin + "," + + record.end + "," + + record.type + "," + + record.rate + "," + + record.amount + "," + + record.balanceA + "," + + record.balanceB + "," + + record.profit + "," + + record.lastProfit + "," + + record.stopLoss + "," + + record.roundtrips + "," + + record.hits + "," + + record.fails + "," + + record.hitRatio + "," + + record.ROI + "," + + record.periods + "," + + record.days + "," + + record.anualizedRateOfReturn + "," + + record.sellRate + "," + + record.lastProfitPercent + "," + + record.strategy + "," + + record.strategyPhase + "," + + record.buyOrder + "," + + record.stopLossPhase + "," + + record.buyOrderPhase + "]"; if (separator === "") { separator = ","; } @@ -549,11 +927,10 @@ fileContent = "[" + fileContent + "]"; - let dateForPath = processDate.getUTCFullYear() + '/' + utilities.pad(processDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(processDate.getUTCDate(), 2); let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_TRADES_FOLDER_NAME + "/" + bot.process + "/" + timePeriod + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); @@ -561,35 +938,111 @@ try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> writeTradeTradesFile -> writeFile -> onFileCreated -> Entering function."); } - - if (LOG_FILE_CONTENT === true) { - logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> writeTradeTradesFile -> writeFile -> onFileCreated -> Content written = " + fileContent); - } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> fileContent = " + fileContent); } if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> loopBody -> writeTradeTradesFile -> writeFile -> onFileCreated -> err = " + err.message); + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + callBackFunction(err); return; + } - const logText = "[WARN] Finished with File @ " + market.assetA + "_" + market.assetB + ", " + fileRecordCounter + " records inserted into " + filePath + "/" + fileName + ""; - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> writeTradeTradesFile -> writeFile -> onFileCreated -> " + logText); } + writeConditionsFile(); - controlLoop(); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> writeTradeTradesFile -> writeFile -> onFileCreated -> err = " + err.message); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> writeTradeTradesFile -> writeFile -> err = " + err.message); + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } + function writeConditionsFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < conditionsArray.length; i++) { + + let record = conditionsArray[i]; + + let conditions = ""; + let conditionsSeparator = ""; + + for (let j = 0; j < record.length - 1; j++) { + conditions = conditions + conditionsSeparator + record[j]; + if (conditionsSeparator === "") { conditionsSeparator = ","; } + } + + conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of condition values. + + fileContent = fileContent + separator + '[' + conditions + ']'; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + fileContent = "[" + JSON.stringify(simulationLogic) + "," + fileContent + "]"; + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + controlLoop(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + diff --git a/this.bot.config.json b/this.bot.config.json index 47e91399d..25d2198a3 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -48,6 +48,30 @@ "process": "Multi-Period-Market", "dataSetVersion": "dataSet.V1" } + ], + "dataDependencies": [ + { + "devTeam": "AAVikings", + "bot": "AAGauss", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "LRC-Points", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Market" + }, + { + "devTeam": "AAMasters", + "bot": "AAOlivia", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Candles", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Market" + } ] }, { @@ -107,6 +131,30 @@ "process": "Multi-Period-Daily", "dataSetVersion": "dataSet.V1" } + ], + "dataDependencies": [ + { + "devTeam": "AAVikings", + "bot": "AAGauss", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "LRC-Points", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Daily" + }, + { + "devTeam": "AAMasters", + "bot": "AAOlivia", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Candles", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Daily" + } ] } ], From 2d4485e9792ffa36872a39c7d334cfd1a19f70f3 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 Mar 2019 11:19:40 +0100 Subject: [PATCH 048/244] Implementation Ready to test --- Multi-Period-Market/User.Bot.js | 1251 +++++++++++-------------------- 1 file changed, 434 insertions(+), 817 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 02193f6d0..a039abe7e 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -7,12 +7,6 @@ const EXCHANGE_NAME = "Poloniex"; - const LRC_FOLDER_NAME = "LRC-Points"; - const PERCENTAGE_BANDWIDTH_FOLDER_NAME = "Percentage-Bandwidth"; - const BOLLINGER_BANDS_FOLDER_NAME = "Bollinger-Bands"; - const BOLLINGER_CHANNELS_FOLDER_NAME = "Bollinger-Channels"; - const BOLLINGER_SUB_CHANNELS_FOLDER_NAME = "Bollinger-Sub-Channels"; - const CANDLES_FOLDER_NAME = "Candles"; const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; @@ -23,18 +17,13 @@ start: start }; - let gaussStorage = BLOB_STORAGE.newBlobStorage(bot, logger); - let chrisStorage = BLOB_STORAGE.newBlobStorage(bot, logger); - let oliviaStorage = BLOB_STORAGE.newBlobStorage(bot, logger); - let jasonStorage = BLOB_STORAGE.newBlobStorage(bot, logger); - let utilities = UTILITIES.newCloudUtilities(bot, logger); - let statusDependencies; + let dataDependencies; return thisObject; - function initialize(pStatusDependencies, pMonth, pYear, callBackFunction) { + function initialize(pDataDependencies, pMonth, pYear, callBackFunction) { try { @@ -43,22 +32,9 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } - statusDependencies = pStatusDependencies; + dataDependencies = pDataDependencies; - commons.initializeStorage(chrisStorage, jasonStorage, oliviaStorage, gaussStorage, onInizialized); - - function onInizialized(err) { - - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> onInizialized -> Initialization Succeed."); } - callBackFunction(global.DEFAULT_OK_RESPONSE); - - } else { - logger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> err = " + err.message); - callBackFunction(err); - } - } + callBackFunction(global.DEFAULT_OK_RESPONSE); } catch (err) { logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message); @@ -66,848 +42,489 @@ } } - - - function start(callBackFunction) { + function start(marketFiles, callBackFunction) { try { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); } - let market = global.MARKET; + const outputPeriod = global.marketFilesPeriods[n][0]; + const timePeriod = global.marketFilesPeriods[n][1]; - buildRecords(); + let marketFile; - function buildRecords() { + let LRCMap = new Map(); + let percentageBandwidthMap = new Map(); + let bollingerBandsMap = new Map(); + let bollingerChannelsArray = []; + let bollingerSubChannelsArray = []; - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> Entering function."); } + let candles = []; + let recordsArray = []; + let conditionsArray = []; + let simulationLogic = {}; + + let fileCounter = 0; + + for (let i = 0; i < dataDependencies.length; i++) { + + let dependency = dataDependencies[i]; + marketFile = marketFiles[i]; + + switch (i) { + + case 0: { + buildLRC(); + fileCounter++; + break; + } + case 1: { + buildPercentageBandwidthMap(); + fileCounter++; + break; + } + case 2: { + buildBollingerBandsMap(); + fileCounter++; + break; + } + case 3: { + buildBollingerChannelsArray(); + fileCounter++; + break; + } + case 4: { + buildBollingerSubChannelsArray(); + fileCounter++; + break; + } + case 5: { + buildCandles(); + fileCounter++; + break; + } + } + } + + commons.runSimulation( + candles, + bollingerBandsMap, + percentageBandwidthMap, + LRCMap, + bollingerChannelsArray, + bollingerSubChannelsArray, + recordsArray, + conditionsArray, + simulationLogic, + outputPeriod, + writeRecordsFile) + + function buildLRC() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildLRC -> Entering function."); } try { - let n; + let previous; - periodsLoop(); + for (let i = 0; i < marketFile.length; i++) { - function periodsLoop() { + let LRC = { + begin: marketFile[i][0], + end: marketFile[i][1], + _15: marketFile[i][2], + _30: marketFile[i][3], + _60: marketFile[i][4] + }; - try { + if (previous !== undefined) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> periodsLoop -> Entering function."); } + if (previous._15 > LRC._15) { LRC.direction15 = 'down'; } + if (previous._15 < LRC._15) { LRC.direction15 = 'up'; } + if (previous._15 === LRC._15) { LRC.direction15 = 'side'; } - /* - - We will iterate through all posible periods. - - */ + if (previous._30 > LRC._30) { LRC.direction30 = 'down'; } + if (previous._30 < LRC._30) { LRC.direction30 = 'up'; } + if (previous._30 === LRC._30) { LRC.direction30 = 'side'; } - n = 0 // loop Variable representing each possible period as defined at the periods array. - - loopBody(); + if (previous._60 > LRC._60) { LRC.direction60 = 'down'; } + if (previous._60 < LRC._60) { LRC.direction60 = 'up'; } + if (previous._60 === LRC._60) { LRC.direction60 = 'side'; } } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> periodsLoop -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); + + LRC.previous = previous; + + LRCMap.set(LRC.begin, LRC); + + previous = LRC; + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildLRC -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildPercentageBandwidthMap() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildPercentageBandwidthMap -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < marketFile.length; i++) { + + let percentageBandwidth = { + begin: marketFile[i][0], + end: marketFile[i][1], + value: marketFile[i][2], + movingAverage: marketFile[i][3], + bandwidth: marketFile[i][4] + }; + + if (previous !== undefined) { + + if (previous.movingAverage > percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'down'; } + if (previous.movingAverage < percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'up'; } + if (previous.movingAverage === percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'side'; } + } + + percentageBandwidth.previous = previous; + + percentageBandwidthMap.set(percentageBandwidth.begin, percentageBandwidth); + + previous = percentageBandwidth; + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildPercentageBandwidthMap -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildBollingerBandsMap() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBollingerBandsMap -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < marketFile.length; i++) { + + let bollingerBand = { + begin: marketFile[i][0], + end: marketFile[i][1], + movingAverage: marketFile[i][2], + standardDeviation: marketFile[i][3], + deviation: marketFile[i][4] + }; + + if (previous !== undefined) { + + if (previous.movingAverage > bollingerBand.movingAverage) { bollingerBand.direction = 'down'; } + if (previous.movingAverage < bollingerBand.movingAverage) { bollingerBand.direction = 'up'; } + if (previous.movingAverage === bollingerBand.movingAverage) { bollingerBand.direction = 'side'; } + + } + + bollingerBand.previous = previous; + + bollingerBandsMap.set(bollingerBand.begin, bollingerBand); + + previous = bollingerBand; + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildBollingerBandsMap -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildBollingerChannelsArray() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBollingerChannelsArray -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < marketFile.length; i++) { + + let bollingerChannel = { + begin: marketFile[i][0], + end: marketFile[i][1], + direction: marketFile[i][2], + period: marketFile[i][3], + firstMovingAverage: marketFile[i][4], + lastMovingAverage: marketFile[i][5], + firstDeviation: marketFile[i][6], + lastDeviation: marketFile[i][7] + }; + + bollingerChannel.previous = previous; + + bollingerChannelsArray.push(bollingerChannel); + + previous = bollingerChannel; + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildBollingerChannelsArray -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildBollingerSubChannelsArray() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBollingerSubChannelsArray -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < marketFile.length; i++) { + + let bollingerSubChannel = { + begin: marketFile[i][0], + end: marketFile[i][1], + direction: marketFile[i][2], + slope: marketFile[i][3], + period: marketFile[i][4], + firstMovingAverage: marketFile[i][5], + lastMovingAverage: marketFile[i][6], + firstDeviation: marketFile[i][7], + lastDeviation: marketFile[i][8] + }; + + bollingerSubChannel.previous = previous; + + bollingerSubChannelsArray.push(bollingerSubChannel); + + previous = bollingerSubChannel; + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildBollingerSubChannelsArray -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildCandles() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < marketFile.length; i++) { + + let candle = { + open: undefined, + close: undefined, + min: 10000000000000, + max: 0, + begin: undefined, + end: undefined, + direction: undefined + }; + + candle.min = marketFile[i][0]; + candle.max = marketFile[i][1]; + + candle.open = marketFile[i][2]; + candle.close = marketFile[i][3]; + + candle.begin = marketFile[i][4]; + candle.end = marketFile[i][5]; + + if (candle.open > candle.close) { candle.direction = 'down'; } + if (candle.open < candle.close) { candle.direction = 'up'; } + if (candle.open === candle.close) { candle.direction = 'side'; } + + candle.previous = previous; + + candles.push(candle); + + previous = candle; + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeRecordsFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < recordsArray.length; i++) { + + let record = recordsArray[i]; + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.type + "," + + record.rate + "," + + record.amount + "," + + record.balanceA + "," + + record.balanceB + "," + + record.profit + "," + + record.lastProfit + "," + + record.stopLoss + "," + + record.roundtrips + "," + + record.hits + "," + + record.fails + "," + + record.hitRatio + "," + + record.ROI + "," + + record.periods + "," + + record.days + "," + + record.anualizedRateOfReturn + "," + + record.sellRate + "," + + record.lastProfitPercent + "," + + record.strategy + "," + + record.strategyPhase + "," + + record.buyOrder + "," + + record.stopLossPhase + "," + + record.buyOrderPhase + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + } - function loopBody() { + fileContent = "[" + fileContent + "]"; + + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> onFileCreated -> fileContent = " + fileContent); } - const outputPeriod = global.marketFilesPeriods[n][0]; - const timePeriod = global.marketFilesPeriods[n][1]; - /* - if (timePeriod !== '01-hs') { - controlLoop(); + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); return; - } - */ - let marketFile; - let LRCMap = new Map(); - let percentageBandwidthMap = new Map(); - let bollingerBandsMap = new Map(); - let bollingerChannelsArray = []; - let bollingerSubChannelsArray = []; - - let candles = []; - let recordsArray = []; - let conditionsArray = []; - let simulationLogic = {}; - - nextLRC(); - - function nextLRC() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = "AAVikings" + "/" + "AAGauss" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + LRC_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - gaussStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildLRC(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } } - function buildLRC() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildLRC -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let LRC = { - begin: marketFile[i][0], - end: marketFile[i][1], - _15: marketFile[i][2], - _30: marketFile[i][3], - _60: marketFile[i][4] - }; - - if (previous !== undefined) { - - if (previous._15 > LRC._15) { LRC.direction15 = 'down'; } - if (previous._15 < LRC._15) { LRC.direction15 = 'up'; } - if (previous._15 === LRC._15) { LRC.direction15 = 'side'; } - - if (previous._30 > LRC._30) { LRC.direction30 = 'down'; } - if (previous._30 < LRC._30) { LRC.direction30 = 'up'; } - if (previous._30 === LRC._30) { LRC.direction30 = 'side'; } - - if (previous._60 > LRC._60) { LRC.direction60 = 'down'; } - if (previous._60 < LRC._60) { LRC.direction60 = 'up'; } - if (previous._60 === LRC._60) { LRC.direction60 = 'side'; } - - } - - LRC.previous = previous; - - LRCMap.set(LRC.begin, LRC); - - previous = LRC; - } - - nextPercentageBandwidth(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildLRC -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function nextPercentageBandwidth() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + PERCENTAGE_BANDWIDTH_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildPercentageBandwidthMap(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildPercentageBandwidthMap() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildPercentageBandwidthMap -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let percentageBandwidth = { - begin: marketFile[i][0], - end: marketFile[i][1], - value: marketFile[i][2], - movingAverage: marketFile[i][3], - bandwidth: marketFile[i][4] - }; - - if (previous !== undefined) { - - if (previous.movingAverage > percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'down'; } - if (previous.movingAverage < percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'up'; } - if (previous.movingAverage === percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'side'; } - - } - - percentageBandwidth.previous = previous; - - percentageBandwidthMap.set(percentageBandwidth.begin, percentageBandwidth); - - previous = percentageBandwidth; - } - - nextBollingerBands(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildPercentageBandwidthMap -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function nextBollingerBands() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + BOLLINGER_BANDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildBollingerBandsMap(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildBollingerBandsMap() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerBandsMap -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let bollingerBand = { - begin: marketFile[i][0], - end: marketFile[i][1], - movingAverage: marketFile[i][2], - standardDeviation: marketFile[i][3], - deviation: marketFile[i][4] - }; - - if (previous !== undefined) { - - if (previous.movingAverage > bollingerBand.movingAverage) { bollingerBand.direction = 'down'; } - if (previous.movingAverage < bollingerBand.movingAverage) { bollingerBand.direction = 'up'; } - if (previous.movingAverage === bollingerBand.movingAverage) { bollingerBand.direction = 'side'; } - - } - - bollingerBand.previous = previous; - - bollingerBandsMap.set(bollingerBand.begin, bollingerBand); - - previous = bollingerBand; - } - - nextBollingerChannels(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerBandsMap -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function nextBollingerChannels() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = bot.devTeam + "/" + "AAPaula" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + BOLLINGER_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildBollingerChannelsArray(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildBollingerChannelsArray() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerChannelsArray -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let bollingerChannel = { - begin: marketFile[i][0], - end: marketFile[i][1], - direction: marketFile[i][2], - period: marketFile[i][3], - firstMovingAverage: marketFile[i][4], - lastMovingAverage: marketFile[i][5], - firstDeviation: marketFile[i][6], - lastDeviation: marketFile[i][7] - }; - - bollingerChannel.previous = previous; - - bollingerChannelsArray.push(bollingerChannel); - - previous = bollingerChannel; - } - - nextBollingerSubChannels(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerChannelsArray -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function nextBollingerSubChannels() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = bot.devTeam + "/" + "AAPaula" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + BOLLINGER_SUB_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildBollingerSubChannelsArray(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildBollingerSubChannelsArray() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerSubChannelsArray -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let bollingerSubChannel = { - begin: marketFile[i][0], - end: marketFile[i][1], - direction: marketFile[i][2], - slope: marketFile[i][3], - period: marketFile[i][4], - firstMovingAverage: marketFile[i][5], - lastMovingAverage: marketFile[i][6], - firstDeviation: marketFile[i][7], - lastDeviation: marketFile[i][8] - }; - - bollingerSubChannel.previous = previous; - - bollingerSubChannelsArray.push(bollingerSubChannel); - - previous = bollingerSubChannel; - } - - nextCandlesFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerSubChannelsArray -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function nextCandlesFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = bot.devTeam + "/" + "AAOlivia" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - oliviaStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildCandles(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildCandles() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildCandles -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let candle = { - open: undefined, - close: undefined, - min: 10000000000000, - max: 0, - begin: undefined, - end: undefined, - direction: undefined - }; - - candle.min = marketFile[i][0]; - candle.max = marketFile[i][1]; - - candle.open = marketFile[i][2]; - candle.close = marketFile[i][3]; - - candle.begin = marketFile[i][4]; - candle.end = marketFile[i][5]; - - if (candle.open > candle.close) { candle.direction = 'down'; } - if (candle.open < candle.close) { candle.direction = 'up'; } - if (candle.open === candle.close) { candle.direction = 'side'; } - - candle.previous = previous; - - candles.push(candle); - - previous = candle; - } - - commons.runSimulation( - candles, - bollingerBandsMap, - percentageBandwidthMap, - LRCMap, - bollingerChannelsArray, - bollingerSubChannelsArray, - recordsArray, - conditionsArray, - simulationLogic, - outputPeriod, - writeRecordsFile) - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildCandles -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeRecordsFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < recordsArray.length; i++) { - - let record = recordsArray[i]; - - fileContent = fileContent + separator + '[' + - record.begin + "," + - record.end + "," + - record.type + "," + - record.rate + "," + - record.amount + "," + - record.balanceA + "," + - record.balanceB + "," + - record.profit + "," + - record.lastProfit + "," + - record.stopLoss + "," + - record.roundtrips + "," + - record.hits + "," + - record.fails + "," + - record.hitRatio + "," + - record.ROI + "," + - record.periods + "," + - record.days + "," + - record.anualizedRateOfReturn + "," + - record.sellRate + "," + - record.lastProfitPercent + "," + - record.strategy + "," + - record.strategyPhase + "," + - record.buyOrder + "," + - record.stopLossPhase + "," + - record.buyOrderPhase + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - writeConditionsFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeConditionsFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < conditionsArray.length; i++) { - - let record = conditionsArray[i]; - - let conditions = ""; - let conditionsSeparator = ""; - - for (let j = 0; j < record.length - 1; j++) { - conditions = conditions + conditionsSeparator + record[j]; - if (conditionsSeparator === "") { conditionsSeparator = ","; } - } - - conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of condition values. - - fileContent = fileContent + separator + '[' + conditions + ']'; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - fileContent = "[" + JSON.stringify(simulationLogic) + "," + fileContent + "]"; - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - controlLoop(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } + writeConditionsFile(); } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - - function controlLoop() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> controlLoop -> Entering function."); } - - n++; - - if (n < global.marketFilesPeriods.length) { - - loopBody(); - - } else { - - writeStatusReport(callBackFunction); - - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> controlLoop -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - function writeStatusReport(callBack) { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> Entering function."); } + function writeConditionsFile() { try { - let reportKey = "AAMasters" + "-" + "AAJason" + "-" + "Multi-Period-Market" + "-" + "dataSet.V1"; - let thisReport = statusDependencies.statusReports.get(reportKey); + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> Entering function."); } - thisReport.file.lastExecution = bot.processDatetime; - thisReport.save(callBack); + let separator = ""; + let fileRecordCounter = 0; + let fileContent = ""; + + for (let i = 0; i < conditionsArray.length; i++) { + + let record = conditionsArray[i]; + + let conditions = ""; + let conditionsSeparator = ""; + + for (let j = 0; j < record.length - 1; j++) { + conditions = conditions + conditionsSeparator + record[j]; + if (conditionsSeparator === "") { conditionsSeparator = ","; } + } + + conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of condition values. + + fileContent = fileContent + separator + '[' + conditions + ']'; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + fileContent = "[" + JSON.stringify(simulationLogic) + "," + fileContent + "]"; + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + callBackFunction(global.DEFAULT_OK_RESPONSE); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - } + } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); From 8cb325160b92435dfab849763c35608e1fe42e0b Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 Mar 2019 11:40:02 +0100 Subject: [PATCH 049/244] Missing Variables --- Multi-Period-Market/User.Bot.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index a039abe7e..be4af9bf3 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -42,15 +42,12 @@ } } - function start(marketFiles, callBackFunction) { + function start(marketFiles, outputPeriod, timePeriod, callBackFunction) { try { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); } - const outputPeriod = global.marketFilesPeriods[n][0]; - const timePeriod = global.marketFilesPeriods[n][1]; - let marketFile; let LRCMap = new Map(); From 55d1dfba7871fbc5a1c7890680add1c3a1b65c3d Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 Mar 2019 14:03:17 +0100 Subject: [PATCH 050/244] Bot working under Multi Period Market Framework --- Commons.js | 83 --------------------------------- Multi-Period-Market/User.Bot.js | 27 ++++++----- this.bot.config.json | 47 ++++++++++++++++++- 3 files changed, 62 insertions(+), 95 deletions(-) diff --git a/Commons.js b/Commons.js index 53bfce367..ca4dccd82 100644 --- a/Commons.js +++ b/Commons.js @@ -8,7 +8,6 @@ const GMT_SECONDS = ':00.000 GMT+0000'; let thisObject = { - initializeStorage: initializeStorage, runSimulation: runSimulation }; @@ -16,88 +15,6 @@ return thisObject; - function initializeStorage(chrisStorage, jasonStorage, oliviaStorage, gaussStorage, callBackFunction) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initializeStorage -> Entering function."); } - - initializetomStorage(); - - function initializetomStorage() { - - jasonStorage.initialize(bot.devTeam, onBruceInizialized); - - function onBruceInizialized(err) { - - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - - initializeChrisStorage(); - - } else { - logger.write(MODULE_NAME, "[ERROR] initializeStorage -> initializetomStorage -> onBruceInizialized -> err = " + err.message); - callBackFunction(err); - } - } - } - - function initializeChrisStorage() { - - chrisStorage.initialize(bot.devTeam, onChrisInizialized); - - function onChrisInizialized(err) { - - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - - initializeGaussStorage(); - - } else { - logger.write(MODULE_NAME, "[ERROR] initializeStorage -> initializeChrisStorage -> onChrisInizialized -> err = " + err.message); - callBackFunction(err); - } - } - } - - function initializeGaussStorage() { - - gaussStorage.initialize("AAVikings", onGaussInizialized); - - function onGaussInizialized(err) { - - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - - initializeOliviaStorage(); - - } else { - logger.write(MODULE_NAME, "[ERROR] initializeStorage -> initializeGaussStorage -> onChrisInizialized -> err = " + err.message); - callBackFunction(err); - } - } - } - - function initializeOliviaStorage() { - - oliviaStorage.initialize(bot.devTeam, onOliviaInizialized); - - function onOliviaInizialized(err) { - - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - - callBackFunction(global.DEFAULT_OK_RESPONSE); - - } else { - logger.write(MODULE_NAME, "[ERROR] initializeStorage -> initializeChrisStorage -> onChrisInizialized -> err = " + err.message); - callBackFunction(err); - } - } - } - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] initializeStorage -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } function runSimulation( candles, diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index be4af9bf3..2195b7445 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -18,6 +18,7 @@ }; let utilities = UTILITIES.newCloudUtilities(bot, logger); + let jasonStorage = BLOB_STORAGE.newBlobStorage(bot, logger); let dataDependencies; @@ -34,8 +35,19 @@ dataDependencies = pDataDependencies; - callBackFunction(global.DEFAULT_OK_RESPONSE); + jasonStorage.initialize(bot.devTeam, onStorageInizialized); + function onStorageInizialized(err) { + + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + + callBackFunction(global.DEFAULT_OK_RESPONSE); + + } else { + logger.write(MODULE_NAME, "[ERROR] initializeStorage -> onStorageInizialized -> err = " + err.message); + callBackFunction(err); + } + } } catch (err) { logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); @@ -48,6 +60,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); } + let market = global.MARKET; let marketFile; let LRCMap = new Map(); @@ -61,43 +74,35 @@ let conditionsArray = []; let simulationLogic = {}; - let fileCounter = 0; + for (let i = 0; i < dataDependencies.config.length; i++) { - for (let i = 0; i < dataDependencies.length; i++) { - - let dependency = dataDependencies[i]; + let dependency = dataDependencies.config[i]; marketFile = marketFiles[i]; switch (i) { case 0: { buildLRC(); - fileCounter++; break; } case 1: { buildPercentageBandwidthMap(); - fileCounter++; break; } case 2: { buildBollingerBandsMap(); - fileCounter++; break; } case 3: { buildBollingerChannelsArray(); - fileCounter++; break; } case 4: { buildBollingerSubChannelsArray(); - fileCounter++; break; } case 5: { buildCandles(); - fileCounter++; break; } } diff --git a/this.bot.config.json b/this.bot.config.json index 25d2198a3..2d09eeb9f 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -61,6 +61,50 @@ "dataSetVersion": "dataSet.V1", "dataSet": "Multi-Period-Market" }, + { + "devTeam": "AAMasters", + "bot": "AAChris", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Percentage-Bandwidth", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Market" + }, + { + "devTeam": "AAMasters", + "bot": "AAChris", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Bollinger-Bands", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Market" + }, + { + "devTeam": "AAMasters", + "bot": "AAPaula", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Bollinger-Channels", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Market" + }, + { + "devTeam": "AAMasters", + "bot": "AAPaula", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Bollinger-Sub-Channels", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Market" + }, { "devTeam": "AAMasters", "bot": "AAOlivia", @@ -72,7 +116,8 @@ "dataSetVersion": "dataSet.V1", "dataSet": "Multi-Period-Market" } - ] + ], + "framework": "Multi-Period-Market" }, { "name": "Multi-Period-Daily", From 2cc407c6fecfb3dfa5f58639df1fbe80aefd9611 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 Mar 2019 15:30:53 +0100 Subject: [PATCH 051/244] Move to Commons, everything that will be reused by Daily Files --- Commons.js | 273 +++++++++++++++++++++++++++++++- Multi-Period-Market/User.Bot.js | 267 +------------------------------ 2 files changed, 274 insertions(+), 266 deletions(-) diff --git a/Commons.js b/Commons.js index ca4dccd82..15f5190d0 100644 --- a/Commons.js +++ b/Commons.js @@ -8,21 +8,40 @@ const GMT_SECONDS = ':00.000 GMT+0000'; let thisObject = { - runSimulation: runSimulation + initializeData: initializeData, + runSimulation: runSimulation, + buildLRC: buildLRC, + buildPercentageBandwidthMap: buildPercentageBandwidthMap, + buildBollingerBandsMap: buildBollingerBandsMap, + buildBollingerChannelsArray: buildBollingerChannelsArray, + buildBollingerSubChannelsArray: buildBollingerSubChannelsArray, + buildCandles: buildCandles }; let utilities = UTILITIES.newCloudUtilities(bot, logger); + let LRCMap = new Map(); + let percentageBandwidthMap = new Map(); + let bollingerBandsMap = new Map(); + let bollingerChannelsArray = []; + let bollingerSubChannelsArray = []; + + let candles = []; + return thisObject; + function initializeData() { + + LRCMap = new Map(); + percentageBandwidthMap = new Map(); + bollingerBandsMap = new Map(); + bollingerChannelsArray = []; + bollingerSubChannelsArray = []; + + candles = []; + } function runSimulation( - candles, - bollingerBandsMap, - percentageBandwidthMap, - LRCMap, - bollingerChannelsArray, - bollingerSubChannelsArray, recordsArray, conditionsArray, simulationLogic, @@ -950,4 +969,244 @@ callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } + + function buildLRC(dataFile) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildLRC -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < dataFile.length; i++) { + + let LRC = { + begin: dataFile[i][0], + end: dataFile[i][1], + _15: dataFile[i][2], + _30: dataFile[i][3], + _60: dataFile[i][4] + }; + + if (previous !== undefined) { + + if (previous._15 > LRC._15) { LRC.direction15 = 'down'; } + if (previous._15 < LRC._15) { LRC.direction15 = 'up'; } + if (previous._15 === LRC._15) { LRC.direction15 = 'side'; } + + if (previous._30 > LRC._30) { LRC.direction30 = 'down'; } + if (previous._30 < LRC._30) { LRC.direction30 = 'up'; } + if (previous._30 === LRC._30) { LRC.direction30 = 'side'; } + + if (previous._60 > LRC._60) { LRC.direction60 = 'down'; } + if (previous._60 < LRC._60) { LRC.direction60 = 'up'; } + if (previous._60 === LRC._60) { LRC.direction60 = 'side'; } + + } + + LRC.previous = previous; + + LRCMap.set(LRC.begin, LRC); + + previous = LRC; + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] buildLRC -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildPercentageBandwidthMap(dataFile) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildPercentageBandwidthMap -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < dataFile.length; i++) { + + let percentageBandwidth = { + begin: dataFile[i][0], + end: dataFile[i][1], + value: dataFile[i][2], + movingAverage: dataFile[i][3], + bandwidth: dataFile[i][4] + }; + + if (previous !== undefined) { + + if (previous.movingAverage > percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'down'; } + if (previous.movingAverage < percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'up'; } + if (previous.movingAverage === percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'side'; } + + } + + percentageBandwidth.previous = previous; + + percentageBandwidthMap.set(percentageBandwidth.begin, percentageBandwidth); + + previous = percentageBandwidth; + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] buildPercentageBandwidthMap -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildBollingerBandsMap(dataFile) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildBollingerBandsMap -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < dataFile.length; i++) { + + let bollingerBand = { + begin: dataFile[i][0], + end: dataFile[i][1], + movingAverage: dataFile[i][2], + standardDeviation: dataFile[i][3], + deviation: dataFile[i][4] + }; + + if (previous !== undefined) { + + if (previous.movingAverage > bollingerBand.movingAverage) { bollingerBand.direction = 'down'; } + if (previous.movingAverage < bollingerBand.movingAverage) { bollingerBand.direction = 'up'; } + if (previous.movingAverage === bollingerBand.movingAverage) { bollingerBand.direction = 'side'; } + + } + + bollingerBand.previous = previous; + + bollingerBandsMap.set(bollingerBand.begin, bollingerBand); + + previous = bollingerBand; + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] buildBollingerBandsMap -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildBollingerChannelsArray(dataFile) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildBollingerChannelsArray -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < dataFile.length; i++) { + + let bollingerChannel = { + begin: dataFile[i][0], + end: dataFile[i][1], + direction: dataFile[i][2], + period: dataFile[i][3], + firstMovingAverage: dataFile[i][4], + lastMovingAverage: dataFile[i][5], + firstDeviation: dataFile[i][6], + lastDeviation: dataFile[i][7] + }; + + bollingerChannel.previous = previous; + + bollingerChannelsArray.push(bollingerChannel); + + previous = bollingerChannel; + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] buildBollingerChannelsArray -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildBollingerSubChannelsArray(dataFile) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildBollingerSubChannelsArray -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < dataFile.length; i++) { + + let bollingerSubChannel = { + begin: dataFile[i][0], + end: dataFile[i][1], + direction: dataFile[i][2], + slope: dataFile[i][3], + period: dataFile[i][4], + firstMovingAverage: dataFile[i][5], + lastMovingAverage: dataFile[i][6], + firstDeviation: dataFile[i][7], + lastDeviation: dataFile[i][8] + }; + + bollingerSubChannel.previous = previous; + + bollingerSubChannelsArray.push(bollingerSubChannel); + + previous = bollingerSubChannel; + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] buildBollingerSubChannelsArray -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function buildCandles(dataFile) { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildCandles -> Entering function."); } + + try { + + let previous; + + for (let i = 0; i < dataFile.length; i++) { + + let candle = { + open: undefined, + close: undefined, + min: 10000000000000, + max: 0, + begin: undefined, + end: undefined, + direction: undefined + }; + + candle.min = dataFile[i][0]; + candle.max = dataFile[i][1]; + + candle.open = dataFile[i][2]; + candle.close = dataFile[i][3]; + + candle.begin = dataFile[i][4]; + candle.end = dataFile[i][5]; + + if (candle.open > candle.close) { candle.direction = 'down'; } + if (candle.open < candle.close) { candle.direction = 'up'; } + if (candle.open === candle.close) { candle.direction = 'side'; } + + candle.previous = previous; + + candles.push(candle); + + previous = candle; + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] buildCandles -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } }; \ No newline at end of file diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 2195b7445..6ec4fe2a6 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -63,16 +63,11 @@ let market = global.MARKET; let marketFile; - let LRCMap = new Map(); - let percentageBandwidthMap = new Map(); - let bollingerBandsMap = new Map(); - let bollingerChannelsArray = []; - let bollingerSubChannelsArray = []; - - let candles = []; let recordsArray = []; let conditionsArray = []; + let simulationLogic = {}; + commons.initializeData(); for (let i = 0; i < dataDependencies.config.length; i++) { @@ -82,285 +77,39 @@ switch (i) { case 0: { - buildLRC(); + commons.buildLRC(marketFile); break; } case 1: { - buildPercentageBandwidthMap(); + commons.buildPercentageBandwidthMap(marketFile); break; } case 2: { - buildBollingerBandsMap(); + commons.buildBollingerBandsMap(marketFile); break; } case 3: { - buildBollingerChannelsArray(); + commons.buildBollingerChannelsArray(marketFile); break; } case 4: { - buildBollingerSubChannelsArray(); + commons.buildBollingerSubChannelsArray(marketFile); break; } case 5: { - buildCandles(); + commons.buildCandles(marketFile); break; } } } commons.runSimulation( - candles, - bollingerBandsMap, - percentageBandwidthMap, - LRCMap, - bollingerChannelsArray, - bollingerSubChannelsArray, recordsArray, conditionsArray, simulationLogic, outputPeriod, writeRecordsFile) - function buildLRC() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildLRC -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let LRC = { - begin: marketFile[i][0], - end: marketFile[i][1], - _15: marketFile[i][2], - _30: marketFile[i][3], - _60: marketFile[i][4] - }; - - if (previous !== undefined) { - - if (previous._15 > LRC._15) { LRC.direction15 = 'down'; } - if (previous._15 < LRC._15) { LRC.direction15 = 'up'; } - if (previous._15 === LRC._15) { LRC.direction15 = 'side'; } - - if (previous._30 > LRC._30) { LRC.direction30 = 'down'; } - if (previous._30 < LRC._30) { LRC.direction30 = 'up'; } - if (previous._30 === LRC._30) { LRC.direction30 = 'side'; } - - if (previous._60 > LRC._60) { LRC.direction60 = 'down'; } - if (previous._60 < LRC._60) { LRC.direction60 = 'up'; } - if (previous._60 === LRC._60) { LRC.direction60 = 'side'; } - - } - - LRC.previous = previous; - - LRCMap.set(LRC.begin, LRC); - - previous = LRC; - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildLRC -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildPercentageBandwidthMap() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildPercentageBandwidthMap -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let percentageBandwidth = { - begin: marketFile[i][0], - end: marketFile[i][1], - value: marketFile[i][2], - movingAverage: marketFile[i][3], - bandwidth: marketFile[i][4] - }; - - if (previous !== undefined) { - - if (previous.movingAverage > percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'down'; } - if (previous.movingAverage < percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'up'; } - if (previous.movingAverage === percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'side'; } - - } - - percentageBandwidth.previous = previous; - - percentageBandwidthMap.set(percentageBandwidth.begin, percentageBandwidth); - - previous = percentageBandwidth; - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildPercentageBandwidthMap -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildBollingerBandsMap() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBollingerBandsMap -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let bollingerBand = { - begin: marketFile[i][0], - end: marketFile[i][1], - movingAverage: marketFile[i][2], - standardDeviation: marketFile[i][3], - deviation: marketFile[i][4] - }; - - if (previous !== undefined) { - - if (previous.movingAverage > bollingerBand.movingAverage) { bollingerBand.direction = 'down'; } - if (previous.movingAverage < bollingerBand.movingAverage) { bollingerBand.direction = 'up'; } - if (previous.movingAverage === bollingerBand.movingAverage) { bollingerBand.direction = 'side'; } - - } - - bollingerBand.previous = previous; - - bollingerBandsMap.set(bollingerBand.begin, bollingerBand); - - previous = bollingerBand; - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildBollingerBandsMap -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildBollingerChannelsArray() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBollingerChannelsArray -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let bollingerChannel = { - begin: marketFile[i][0], - end: marketFile[i][1], - direction: marketFile[i][2], - period: marketFile[i][3], - firstMovingAverage: marketFile[i][4], - lastMovingAverage: marketFile[i][5], - firstDeviation: marketFile[i][6], - lastDeviation: marketFile[i][7] - }; - - bollingerChannel.previous = previous; - - bollingerChannelsArray.push(bollingerChannel); - - previous = bollingerChannel; - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildBollingerChannelsArray -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildBollingerSubChannelsArray() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBollingerSubChannelsArray -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let bollingerSubChannel = { - begin: marketFile[i][0], - end: marketFile[i][1], - direction: marketFile[i][2], - slope: marketFile[i][3], - period: marketFile[i][4], - firstMovingAverage: marketFile[i][5], - lastMovingAverage: marketFile[i][6], - firstDeviation: marketFile[i][7], - lastDeviation: marketFile[i][8] - }; - - bollingerSubChannel.previous = previous; - - bollingerSubChannelsArray.push(bollingerSubChannel); - - previous = bollingerSubChannel; - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildBollingerSubChannelsArray -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildCandles() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let candle = { - open: undefined, - close: undefined, - min: 10000000000000, - max: 0, - begin: undefined, - end: undefined, - direction: undefined - }; - - candle.min = marketFile[i][0]; - candle.max = marketFile[i][1]; - - candle.open = marketFile[i][2]; - candle.close = marketFile[i][3]; - - candle.begin = marketFile[i][4]; - candle.end = marketFile[i][5]; - - if (candle.open > candle.close) { candle.direction = 'down'; } - if (candle.open < candle.close) { candle.direction = 'up'; } - if (candle.open === candle.close) { candle.direction = 'side'; } - - candle.previous = previous; - - candles.push(candle); - - previous = candle; - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - function writeRecordsFile() { try { From 3593ef150e30ab04edd49a9071fd6aadf45169ee Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 16 Mar 2019 15:37:16 +0100 Subject: [PATCH 052/244] dataFiles --- Multi-Period-Market/User.Bot.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 6ec4fe2a6..b8e8f8b02 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -54,14 +54,14 @@ } } - function start(marketFiles, outputPeriod, timePeriod, callBackFunction) { + function start(dataFiles, outputPeriod, timePeriod, callBackFunction) { try { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); } let market = global.MARKET; - let marketFile; + let dataFile; let recordsArray = []; let conditionsArray = []; @@ -72,32 +72,32 @@ for (let i = 0; i < dataDependencies.config.length; i++) { let dependency = dataDependencies.config[i]; - marketFile = marketFiles[i]; + dataFile = dataFiles[i]; switch (i) { case 0: { - commons.buildLRC(marketFile); + commons.buildLRC(dataFile); break; } case 1: { - commons.buildPercentageBandwidthMap(marketFile); + commons.buildPercentageBandwidthMap(dataFile); break; } case 2: { - commons.buildBollingerBandsMap(marketFile); + commons.buildBollingerBandsMap(dataFile); break; } case 3: { - commons.buildBollingerChannelsArray(marketFile); + commons.buildBollingerChannelsArray(dataFile); break; } case 4: { - commons.buildBollingerSubChannelsArray(marketFile); + commons.buildBollingerSubChannelsArray(dataFile); break; } case 5: { - commons.buildCandles(marketFile); + commons.buildCandles(dataFile); break; } } From 1db7fdefea2dda37cc3a94167cdbb8a48ff876c6 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 17 Mar 2019 09:16:20 +0100 Subject: [PATCH 053/244] Multi Period Daily Implemented --- Multi-Period-Daily/User.Bot.js | 1288 +++++-------------------------- Multi-Period-Market/User.Bot.js | 2 +- 2 files changed, 188 insertions(+), 1102 deletions(-) diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 5e94c9d31..f1ca93728 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -1,20 +1,14 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, FILE_STORAGE) { const FULL_LOG = true; - const INTENSIVE_LOG = false; const LOG_FILE_CONTENT = false; - const GMT_SECONDS = ':00.000 GMT+0000'; - const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; - const MODULE_NAME = "User Bot"; const EXCHANGE_NAME = "Poloniex"; - const TRADES_FOLDER_NAME = "Trades"; - - const CANDLES_FOLDER_NAME = "Bands"; - const SIMULATED_TRADES_FOLDER_NAME = "Trading-Simulation"; + const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; + const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; const commons = COMMONS.newCommons(bot, logger, UTILITIES); @@ -23,16 +17,14 @@ start: start }; - let chrisStorage = BLOB_STORAGE.newBlobStorage(bot, logger); + let utilities = UTILITIES.newCloudUtilities(bot, logger); let jasonStorage = BLOB_STORAGE.newBlobStorage(bot, logger); - let utilities = UTILITIES.newCloudUtilities(bot, logger); - - let statusDependencies; + let dataDependencies; return thisObject; - function initialize(pStatusDependencies, pMonth, pYear, callBackFunction) { + function initialize(pDataDependencies, callBackFunction) { try { @@ -41,1165 +33,259 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } - statusDependencies = pStatusDependencies; + dataDependencies = pDataDependencies; - commons.initializeStorage(chrisStorage, jasonStorage, onInizialized); + jasonStorage.initialize(bot.devTeam, onStorageInizialized); - function onInizialized(err) { + function onStorageInizialized(err) { if (err.result === global.DEFAULT_OK_RESPONSE.result) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> onInizialized -> Initialization Succeed."); } callBackFunction(global.DEFAULT_OK_RESPONSE); } else { - logger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] initializeStorage -> onStorageInizialized -> err = " + err.message); callBackFunction(err); } } - } catch (err) { logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - function start(callBackFunction) { + function start(dataFiles, outputPeriod, timePeriod, currentDate, callBackFunction) { try { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); } let market = global.MARKET; + let dataFile; - /* Context Variables */ + let recordsArray = []; + let conditionsArray = []; - let contextVariables = { - lastTradeFile: undefined, // Datetime of the last file files sucessfully produced by this process. - firstTradeFile: undefined, // Datetime of the first trade file in the whole market history. - maxTradeFile: undefined // Datetime of the last file available to be used as an input of this process. - }; + let simulationLogic = {}; + commons.initializeData(); - let previousDay; // Holds the date of the previous day relative to the processing date. - let processDate; // Holds the processing date. + for (let i = 0; i < dataDependencies.config.length; i++) { - getContextVariables(); + let dependency = dataDependencies.config[i]; + dataFile = dataFiles[i]; - function getContextVariables() { + switch (i) { - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Entering function."); } - - let thisReport; - let reportKey; - let statusReport; - - /* We look first for Charly in order to get when the market starts. */ - - reportKey = "AAMasters" + "-" + "AACharly" + "-" + "Poloniex-Historic-Trades" + "-" + "dataSet.V1"; - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); } - - statusReport = statusDependencies.statusReports.get(reportKey); - - if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. - logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. "); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); - return; + case 0: { + commons.buildLRC(dataFile); + break; } - - if (statusReport.status === "Status Report is corrupt.") { - logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. "); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); - return; + case 1: { + commons.buildPercentageBandwidthMap(dataFile); + break; } - - thisReport = statusDependencies.statusReports.get(reportKey).file; - - if (thisReport.lastFile === undefined) { - logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey); - logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> It is too early too run this process since the trade history of the market is not there yet."); - - let customOK = { - result: global.CUSTOM_OK_RESPONSE.result, - message: "Dependency does not exist." - } - logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message); - callBackFunction(customOK); - return; + case 2: { + commons.buildBollingerBandsMap(dataFile); + break; } - - contextVariables.firstTradeFile = new Date(thisReport.lastFile.year + "-" + thisReport.lastFile.month + "-" + thisReport.lastFile.days + " " + thisReport.lastFile.hours + ":" + thisReport.lastFile.minutes + GMT_SECONDS); - - /* Second, we get the report from Chris, to know when the marted ends. */ - - reportKey = "AAMasters" + "-" + "AAChris" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1"; - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); } - - statusReport = statusDependencies.statusReports.get(reportKey); - - if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. - logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. "); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); - return; + case 3: { + commons.buildBollingerChannelsArray(dataFile); + break; } - - if (statusReport.status === "Status Report is corrupt.") { - logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. "); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); - return; + case 4: { + commons.buildBollingerSubChannelsArray(dataFile); + break; } - - thisReport = statusDependencies.statusReports.get(reportKey).file; - - if (thisReport.lastFile === undefined) { - logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey); - - let customOK = { - result: global.CUSTOM_OK_RESPONSE.result, - message: "Dependency not ready." - } - logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message); - callBackFunction(customOK); - return; + case 5: { + commons.buildCandles(dataFile); + break; } - - contextVariables.maxTradeFile = new Date(thisReport.lastFile.valueOf()); - - /* Finally we get our own Status Report. */ - - reportKey = "AAMasters" + "-" + "AAJason" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1"; - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); } - - statusReport = statusDependencies.statusReports.get(reportKey); - - if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. - logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. "); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); - return; - } - - if (statusReport.status === "Status Report is corrupt.") { - logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process."); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - return; - } - - thisReport = statusDependencies.statusReports.get(reportKey).file; - - if (thisReport.lastFile !== undefined) { - - contextVariables.lastTradeFile = new Date(thisReport.lastFile); - - /* - The trades objects needs to be calculated over more than one day in some situations. In order to simplify the calculations we will - always load the last 2 days of bands, and run the calculations on that array. - - 1. So first we will load the bands file of processDay -1. - 2. Secondly we will load the bands file of processDay. - - After reading these two files we will add all bands to a unique array. - */ - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> thisReport.lastFile !== undefined"); } - - buildTrades(); - return; - - } else { - - /* - In the case when there is no status report, we take the date of the file with the first trades as the begining of the market. Then we will - go one day further in time, so that the previous day does fine a file at the begining of the market. - */ - - contextVariables.lastTradeFile = new Date(contextVariables.firstTradeFile.getUTCFullYear() + "-" + (contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" + contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" + GMT_SECONDS); - contextVariables.lastTradeFile = new Date(contextVariables.lastTradeFile.valueOf() + ONE_DAY_IN_MILISECONDS); - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> thisReport.lastFile === undefined"); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> contextVariables.lastTradeFile = " + contextVariables.lastTradeFile); } - - buildTrades(); - return; - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> err = " + err.message); - if (err.message === "Cannot read property 'file' of undefined") { - logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. "); - logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys)); - } - callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - function buildTrades() { + commons.runSimulation( + recordsArray, + conditionsArray, + simulationLogic, + outputPeriod, + writeRecordsFile) + + function writeRecordsFile() { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> Entering function."); } - let n; - processDate = new Date(contextVariables.lastTradeFile.valueOf() - ONE_DAY_IN_MILISECONDS); // Go back one day to start well when we advance time at the begining of the loop. - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> processDate = " + processDate); } + let separator = ""; + let fileRecordCounter = 0; - advanceTime(); + let fileContent = ""; - function advanceTime() { + for (let i = 0; i < recordsArray.length; i++) { - try { + let record = recordsArray[i]; - logger.newInternalLoop(bot.codeName, bot.process); + /* Will only add to the file the records of the current day */ - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> advanceTime -> Entering function."); } + if (record.begin < currentDate.valueOf()) { continue; } - processDate = new Date(processDate.valueOf() + ONE_DAY_IN_MILISECONDS); - previousDay = new Date(processDate.valueOf() - ONE_DAY_IN_MILISECONDS); + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.type + "," + + record.rate + "," + + record.amount + "," + + record.balanceA + "," + + record.balanceB + "," + + record.profit + "," + + record.lastProfit + "," + + record.stopLoss + "," + + record.roundtrips + "," + + record.hits + "," + + record.fails + "," + + record.hitRatio + "," + + record.ROI + "," + + record.periods + "," + + record.days + "," + + record.anualizedRateOfReturn + "," + + record.sellRate + "," + + record.lastProfitPercent + "," + + record.strategy + "," + + record.strategyPhase + "," + + record.buyOrder + "," + + record.stopLossPhase + "," + + record.buyOrderPhase + "]"; - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> advanceTime -> processDate = " + processDate); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> advanceTime -> previousDay = " + previousDay); } + if (separator === "") { separator = ","; } - /* Validation that we are not going past the head of the market. */ + fileRecordCounter++; - if (processDate.valueOf() > contextVariables.maxTradeFile.valueOf()) { - - const logText = "Head of the market found @ " + previousDay.getUTCFullYear() + "/" + (previousDay.getUTCMonth() + 1) + "/" + previousDay.getUTCDate() + "."; - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> advanceTime -> " + logText); } - - callBackFunction(global.DEFAULT_OK_RESPONSE); - return; - - } - - periodsLoop(); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> advanceTime -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } } - function periodsLoop() { + fileContent = "[" + fileContent + "]"; - try { + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> periodsLoop -> Entering function."); } - - /* - - We will iterate through all posible timePeriods. - - */ - - n = 0 // loop Variable representing each possible period as defined at the periods array. - - loopBody(); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function loopBody() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> Entering function."); } - - const timePeriod = global.dailyFilePeriods[n][1]; - - let marketFile; - - let LRCMap = new Map(); - let percentageBandwidthMap = new Map(); - let bollingerBandsMap = new Map(); - let bollingerChannelsArray = []; - let bollingerSubChannelsArray = []; - - let candles = []; - let recordsArray = []; - let conditionsArray = []; - let simulationLogic = {}; - - nextLRC(); - - function nextLRC() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> Entering function."); } - - let dateForPath = fileDate.getUTCFullYear() + '/' + utilities.pad(fileDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(fileDate.getUTCDate(), 2); - let fileName = market.assetA + '_' + market.assetB + ".json" - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CANDLE_STAIRS_FOLDER_NAME + '/' + "Multi-Period-Daily" + "/" + timePeriod + "/" + dateForPath; - - - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = "AAVikings" + "/" + "AAGauss" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + LRC_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - gaussStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildLRC(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildLRC() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildLRC -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let LRC = { - begin: marketFile[i][0], - end: marketFile[i][1], - _15: marketFile[i][2], - _30: marketFile[i][3], - _60: marketFile[i][4] - }; - - if (previous !== undefined) { - - if (previous._15 > LRC._15) { LRC.direction15 = 'down'; } - if (previous._15 < LRC._15) { LRC.direction15 = 'up'; } - if (previous._15 === LRC._15) { LRC.direction15 = 'side'; } - - if (previous._30 > LRC._30) { LRC.direction30 = 'down'; } - if (previous._30 < LRC._30) { LRC.direction30 = 'up'; } - if (previous._30 === LRC._30) { LRC.direction30 = 'side'; } - - if (previous._60 > LRC._60) { LRC.direction60 = 'down'; } - if (previous._60 < LRC._60) { LRC.direction60 = 'up'; } - if (previous._60 === LRC._60) { LRC.direction60 = 'side'; } - - } - - LRC.previous = previous; - - LRCMap.set(LRC.begin, LRC); - - previous = LRC; - } - - nextPercentageBandwidth(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildLRC -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function nextPercentageBandwidth() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + PERCENTAGE_BANDWIDTH_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildPercentageBandwidthMap(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildPercentageBandwidthMap() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildPercentageBandwidthMap -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let percentageBandwidth = { - begin: marketFile[i][0], - end: marketFile[i][1], - value: marketFile[i][2], - movingAverage: marketFile[i][3], - bandwidth: marketFile[i][4] - }; - - if (previous !== undefined) { - - if (previous.movingAverage > percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'down'; } - if (previous.movingAverage < percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'up'; } - if (previous.movingAverage === percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'side'; } - - } - - percentageBandwidth.previous = previous; - - percentageBandwidthMap.set(percentageBandwidth.begin, percentageBandwidth); - - previous = percentageBandwidth; - } - - nextBollingerBands(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildPercentageBandwidthMap -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function nextBollingerBands() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + BOLLINGER_BANDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildBollingerBandsMap(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildBollingerBandsMap() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerBandsMap -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let bollingerBand = { - begin: marketFile[i][0], - end: marketFile[i][1], - movingAverage: marketFile[i][2], - standardDeviation: marketFile[i][3], - deviation: marketFile[i][4] - }; - - if (previous !== undefined) { - - if (previous.movingAverage > bollingerBand.movingAverage) { bollingerBand.direction = 'down'; } - if (previous.movingAverage < bollingerBand.movingAverage) { bollingerBand.direction = 'up'; } - if (previous.movingAverage === bollingerBand.movingAverage) { bollingerBand.direction = 'side'; } - - } - - bollingerBand.previous = previous; - - bollingerBandsMap.set(bollingerBand.begin, bollingerBand); - - previous = bollingerBand; - } - - nextBollingerChannels(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerBandsMap -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function nextBollingerChannels() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = bot.devTeam + "/" + "AAPaula" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + BOLLINGER_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildBollingerChannelsArray(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildBollingerChannelsArray() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerChannelsArray -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let bollingerChannel = { - begin: marketFile[i][0], - end: marketFile[i][1], - direction: marketFile[i][2], - period: marketFile[i][3], - firstMovingAverage: marketFile[i][4], - lastMovingAverage: marketFile[i][5], - firstDeviation: marketFile[i][6], - lastDeviation: marketFile[i][7] - }; - - bollingerChannel.previous = previous; - - bollingerChannelsArray.push(bollingerChannel); - - previous = bollingerChannel; - } - - nextBollingerSubChannels(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerChannelsArray -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function nextBollingerSubChannels() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = bot.devTeam + "/" + "AAPaula" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + BOLLINGER_SUB_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - chrisStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildBollingerSubChannelsArray(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildBollingerSubChannelsArray() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerSubChannelsArray -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let bollingerSubChannel = { - begin: marketFile[i][0], - end: marketFile[i][1], - direction: marketFile[i][2], - slope: marketFile[i][3], - period: marketFile[i][4], - firstMovingAverage: marketFile[i][5], - lastMovingAverage: marketFile[i][6], - firstDeviation: marketFile[i][7], - lastDeviation: marketFile[i][8] - }; - - bollingerSubChannel.previous = previous; - - bollingerSubChannelsArray.push(bollingerSubChannel); - - previous = bollingerSubChannel; - } - - nextCandlesFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerSubChannelsArray -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function nextCandlesFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> Entering function."); } - - let fileName = market.assetA + '_' + market.assetB + ".json"; - - let filePathRoot = bot.devTeam + "/" + "AAOlivia" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - oliviaStorage.getTextFile(filePath, fileName, onFileReceived, true); - - function onFileReceived(err, text) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> text = " + text); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> err = " + err.message); - callBackFunction(err); - return; - - } - - marketFile = JSON.parse(text); - - buildCandles(); - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildCandles() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildCandles -> Entering function."); } - - try { - - let previous; - - for (let i = 0; i < marketFile.length; i++) { - - let candle = { - open: undefined, - close: undefined, - min: 10000000000000, - max: 0, - begin: undefined, - end: undefined, - direction: undefined - }; - - candle.min = marketFile[i][0]; - candle.max = marketFile[i][1]; - - candle.open = marketFile[i][2]; - candle.close = marketFile[i][3]; - - candle.begin = marketFile[i][4]; - candle.end = marketFile[i][5]; - - if (candle.open > candle.close) { candle.direction = 'down'; } - if (candle.open < candle.close) { candle.direction = 'up'; } - if (candle.open === candle.close) { candle.direction = 'side'; } - - candle.previous = previous; - - candles.push(candle); - - previous = candle; - } - - commons.runSimulation( - candles, - bollingerBandsMap, - percentageBandwidthMap, - LRCMap, - bollingerChannelsArray, - bollingerSubChannelsArray, - recordsArray, - conditionsArray, - simulationLogic, - outputPeriod, - writeRecordsFile) - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildCandles -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeRecordsFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < recordsArray.length; i++) { - - let record = recordsArray[i]; - - fileContent = fileContent + separator + '[' + - record.begin + "," + - record.end + "," + - record.type + "," + - record.rate + "," + - record.amount + "," + - record.balanceA + "," + - record.balanceB + "," + - record.profit + "," + - record.lastProfit + "," + - record.stopLoss + "," + - record.roundtrips + "," + - record.hits + "," + - record.fails + "," + - record.hitRatio + "," + - record.ROI + "," + - record.periods + "," + - record.days + "," + - record.anualizedRateOfReturn + "," + - record.sellRate + "," + - record.lastProfitPercent + "," + - record.strategy + "," + - record.strategyPhase + "," + - record.buyOrder + "," + - record.stopLossPhase + "," + - record.buyOrderPhase + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - writeConditionsFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeConditionsFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < conditionsArray.length; i++) { - - let record = conditionsArray[i]; - - let conditions = ""; - let conditionsSeparator = ""; - - for (let j = 0; j < record.length - 1; j++) { - conditions = conditions + conditionsSeparator + record[j]; - if (conditionsSeparator === "") { conditionsSeparator = ","; } - } - - conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of condition values. - - fileContent = fileContent + separator + '[' + conditions + ']'; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - fileContent = "[" + JSON.stringify(simulationLogic) + "," + fileContent + "]"; - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; - - jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - controlLoop(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - - - - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function controlLoop() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> controlLoop -> Entering function."); } - - n++; - - if (n < global.dailyFilePeriods.length) { - - loopBody(); - - } else { - - n = 0; - - writeDataRanges(onWritten); - - function onWritten(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> controlLoop -> onWritten -> Entering function."); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> controlLoop -> onWritten -> err = " + err.message); - callBackFunction(err); - return; - } - - writeStatusReport(processDate, advanceTime); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> controlLoop -> onWritten -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> controlLoop -> err = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> err.message = " + err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeDataRanges(callBack) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRanges -> Entering function."); } - - writeDataRange(contextVariables.firstTradeFile, processDate, SIMULATED_TRADES_FOLDER_NAME, onTradesTradesDataRangeWritten); - - function onTradesTradesDataRangeWritten(err) { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRanges -> Entering function."); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] writeDataRanges -> writeDataRanges -> onTradesTradesDataRangeWritten -> err = " + err.message); - callBack(err); - return; - } - - callBack(global.DEFAULT_OK_RESPONSE); - - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeDataRanges -> err = " + err.message); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - - } - - function writeDataRange(pBegin, pEnd, pProductFolder, callBack) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> Entering function."); } - - let dataRange = { - begin: pBegin.valueOf(), - end: pEnd.valueOf() - }; - - let fileContent = JSON.stringify(dataRange); - - let fileName = 'Data.Range.' + market.assetA + '_' + market.assetB + '.json'; - let filePath = bot.filePathRoot + "/Output/" + pProductFolder + "/" + bot.process; - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> fileName = " + fileName); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> filePath = " + filePath); } + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); function onFileCreated(err) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Entering function."); } + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + writeConditionsFile(); - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> onFileCreated -> err = " + err.message); - callBack(err); - return; } - - if (LOG_FILE_CONTENT === true) { - logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Content written = " + fileContent); + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); } - - callBack(global.DEFAULT_OK_RESPONSE); } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> err = " + err.message); - callBack(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeStatusReport(lastFileDate, callBack) { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> Entering function."); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> lastFileDate = " + lastFileDate); } - - try { - - let reportKey = "AAMasters" + "-" + "AAJason" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1"; - let thisReport = statusDependencies.statusReports.get(reportKey); - - thisReport.file.lastExecution = bot.processDatetime; - thisReport.file.lastFile = lastFileDate; - thisReport.save(callBack); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } + + function writeConditionsFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < conditionsArray.length; i++) { + + let record = conditionsArray[i]; + + let conditions = ""; + let conditionsSeparator = ""; + + /* Will only add to the file the records of the current day */ + + if (record.begin < currentDate.valueOf()) { continue; } + + for (let j = 0; j < record.length - 1; j++) { + conditions = conditions + conditionsSeparator + record[j]; + if (conditionsSeparator === "") { conditionsSeparator = ","; } + } + + conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of condition values. + + fileContent = fileContent + separator + '[' + conditions + ']'; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + fileContent = "[" + JSON.stringify(simulationLogic) + "," + fileContent + "]"; + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + + jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + callBackFunction(global.DEFAULT_OK_RESPONSE); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> err.message = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index b8e8f8b02..0b7c78a56 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -24,7 +24,7 @@ return thisObject; - function initialize(pDataDependencies, pMonth, pYear, callBackFunction) { + function initialize(pDataDependencies, callBackFunction) { try { From 340365e0d56fddb9c9273941b6ca9d1827cfa5ab Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 17 Mar 2019 09:27:57 +0100 Subject: [PATCH 054/244] Framework Added --- this.bot.config.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/this.bot.config.json b/this.bot.config.json index 2d09eeb9f..dfa2f6ce8 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -200,7 +200,8 @@ "dataSetVersion": "dataSet.V1", "dataSet": "Multi-Period-Daily" } - ] + ], + "framework": "Multi-Period-Daily" } ], "products": [ From 55ed967bd5c8a327275cdd78496392c9cf0c55f3 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 17 Mar 2019 15:48:51 +0100 Subject: [PATCH 055/244] Time Period refactored --- Commons.js | 16 +++++----- Multi-Period-Daily/User.Bot.js | 28 ++++++++--------- Multi-Period-Market/User.Bot.js | 28 ++++++++--------- this.bot.config.json | 54 ++++++++++++++++++++++++++++++--- 4 files changed, 86 insertions(+), 40 deletions(-) diff --git a/Commons.js b/Commons.js index 15f5190d0..58597556f 100644 --- a/Commons.js +++ b/Commons.js @@ -45,7 +45,7 @@ recordsArray, conditionsArray, simulationLogic, - outputPeriod, + timePeriod, callback) { try { @@ -873,7 +873,7 @@ hitRatio = hits / roundtrips; let miliSecondsPerDay = 24 * 60 * 60 * 1000; - days = periods * outputPeriod / miliSecondsPerDay; + days = periods * timePeriod / miliSecondsPerDay; anualizedRateOfReturn = ROI / days * 365; addRecord(); @@ -970,7 +970,7 @@ } } - function buildLRC(dataFile) { + function buildLRC(dataFile, callBackFunction) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildLRC -> Entering function."); } @@ -1017,7 +1017,7 @@ } } - function buildPercentageBandwidthMap(dataFile) { + function buildPercentageBandwidthMap(dataFile, callBackFunction) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildPercentageBandwidthMap -> Entering function."); } @@ -1056,7 +1056,7 @@ } } - function buildBollingerBandsMap(dataFile) { + function buildBollingerBandsMap(dataFile, callBackFunction) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildBollingerBandsMap -> Entering function."); } @@ -1095,7 +1095,7 @@ } } - function buildBollingerChannelsArray(dataFile) { + function buildBollingerChannelsArray(dataFile, callBackFunction) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildBollingerChannelsArray -> Entering function."); } @@ -1129,7 +1129,7 @@ } } - function buildBollingerSubChannelsArray(dataFile) { + function buildBollingerSubChannelsArray(dataFile, callBackFunction) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildBollingerSubChannelsArray -> Entering function."); } @@ -1164,7 +1164,7 @@ } } - function buildCandles(dataFile) { + function buildCandles(dataFile, callBackFunction) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildCandles -> Entering function."); } diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index f1ca93728..dce80df1e 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -18,7 +18,7 @@ }; let utilities = UTILITIES.newCloudUtilities(bot, logger); - let jasonStorage = BLOB_STORAGE.newBlobStorage(bot, logger); + let thisBotStorage = BLOB_STORAGE.newBlobStorage(bot, logger); let dataDependencies; @@ -35,7 +35,7 @@ dataDependencies = pDataDependencies; - jasonStorage.initialize(bot.devTeam, onStorageInizialized); + thisBotStorage.initialize(bot.devTeam, onStorageInizialized); function onStorageInizialized(err) { @@ -54,7 +54,7 @@ } } - function start(dataFiles, outputPeriod, timePeriod, currentDate, callBackFunction) { + function start(dataFiles, timePeriod, outputPeriodLabel, currentDate, callBackFunction) { try { @@ -77,27 +77,27 @@ switch (i) { case 0: { - commons.buildLRC(dataFile); + commons.buildLRC(dataFile, callBackFunction); break; } case 1: { - commons.buildPercentageBandwidthMap(dataFile); + commons.buildPercentageBandwidthMap(dataFile, callBackFunction); break; } case 2: { - commons.buildBollingerBandsMap(dataFile); + commons.buildBollingerBandsMap(dataFile, callBackFunction); break; } case 3: { - commons.buildBollingerChannelsArray(dataFile); + commons.buildBollingerChannelsArray(dataFile, callBackFunction); break; } case 4: { - commons.buildBollingerSubChannelsArray(dataFile); + commons.buildBollingerSubChannelsArray(dataFile, callBackFunction); break; } case 5: { - commons.buildCandles(dataFile); + commons.buildCandles(dataFile, callBackFunction); break; } } @@ -107,7 +107,7 @@ recordsArray, conditionsArray, simulationLogic, - outputPeriod, + timePeriod, writeRecordsFile) function writeRecordsFile() { @@ -167,9 +167,9 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel; - jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); function onFileCreated(err) { @@ -246,9 +246,9 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel; - jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); function onFileCreated(err) { diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 0b7c78a56..63bb2135b 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -18,7 +18,7 @@ }; let utilities = UTILITIES.newCloudUtilities(bot, logger); - let jasonStorage = BLOB_STORAGE.newBlobStorage(bot, logger); + let thisBotStorage = BLOB_STORAGE.newBlobStorage(bot, logger); let dataDependencies; @@ -35,7 +35,7 @@ dataDependencies = pDataDependencies; - jasonStorage.initialize(bot.devTeam, onStorageInizialized); + thisBotStorage.initialize(bot.devTeam, onStorageInizialized); function onStorageInizialized(err) { @@ -54,7 +54,7 @@ } } - function start(dataFiles, outputPeriod, timePeriod, callBackFunction) { + function start(dataFiles, timePeriod, outputPeriodLabel, callBackFunction) { try { @@ -77,27 +77,27 @@ switch (i) { case 0: { - commons.buildLRC(dataFile); + commons.buildLRC(dataFile, callBackFunction); break; } case 1: { - commons.buildPercentageBandwidthMap(dataFile); + commons.buildPercentageBandwidthMap(dataFile, callBackFunction); break; } case 2: { - commons.buildBollingerBandsMap(dataFile); + commons.buildBollingerBandsMap(dataFile, callBackFunction); break; } case 3: { - commons.buildBollingerChannelsArray(dataFile); + commons.buildBollingerChannelsArray(dataFile, callBackFunction); break; } case 4: { - commons.buildBollingerSubChannelsArray(dataFile); + commons.buildBollingerSubChannelsArray(dataFile, callBackFunction); break; } case 5: { - commons.buildCandles(dataFile); + commons.buildCandles(dataFile, callBackFunction); break; } } @@ -107,7 +107,7 @@ recordsArray, conditionsArray, simulationLogic, - outputPeriod, + timePeriod, writeRecordsFile) function writeRecordsFile() { @@ -163,9 +163,9 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; - jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); function onFileCreated(err) { @@ -238,9 +238,9 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod; + let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; - jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); function onFileCreated(err) { diff --git a/this.bot.config.json b/this.bot.config.json index dfa2f6ce8..cf3733691 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -153,12 +153,12 @@ "major": 1, "minor": 0 }, - "process": "Poloniex-Historic-Records", + "process": "Poloniex-Historic-Trades", "dataSetVersion": "dataSet.V1" }, { "devTeam": "AAMasters", - "bot": "AAChris", + "bot": "AAOlivia", "botVersion": { "major": 1, "minor": 0 @@ -177,6 +177,8 @@ "dataSetVersion": "dataSet.V1" } ], + "statusDependenciesIndexBegingOfMarket": 0, + "statusDependenciesIndexEndOfMarket": 1, "dataDependencies": [ { "devTeam": "AAVikings", @@ -187,7 +189,51 @@ }, "product": "LRC-Points", "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Daily" + "dataSet": "Multi-Period-Market" + }, + { + "devTeam": "AAMasters", + "bot": "AAChris", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Percentage-Bandwidth", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Market" + }, + { + "devTeam": "AAMasters", + "bot": "AAChris", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Bollinger-Bands", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Market" + }, + { + "devTeam": "AAMasters", + "bot": "AAPaula", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Bollinger-Channels", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Market" + }, + { + "devTeam": "AAMasters", + "bot": "AAPaula", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Bollinger-Sub-Channels", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Market" }, { "devTeam": "AAMasters", @@ -198,7 +244,7 @@ }, "product": "Candles", "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Daily" + "dataSet": "Multi-Period-Market" } ], "framework": "Multi-Period-Daily" From 9b3214c69969e380cba8d419d24299a5a2b51be6 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 17 Mar 2019 18:29:27 +0100 Subject: [PATCH 056/244] 5 Last Objects written on file --- Commons.js | 24 ++++++++++++++++++++++++ Multi-Period-Daily/User.Bot.js | 5 ++++- Multi-Period-Market/User.Bot.js | 5 ++++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Commons.js b/Commons.js index 58597556f..4ceb812a8 100644 --- a/Commons.js +++ b/Commons.js @@ -44,6 +44,7 @@ function runSimulation( recordsArray, conditionsArray, + lastObjectsArray, simulationLogic, timePeriod, callback) { @@ -477,8 +478,31 @@ periods++; + let channel = getElement(bollingerChannelsArray, candle.begin, candle.end); let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); + let lastObjects = { + candle: JSON.parse(JSON.stringify(candle)), + LRC: JSON.parse(JSON.stringify(LRC)), + bollingerBand: JSON.parse(JSON.stringify(bollingerBand)), + percentageBandwidth: JSON.parse(JSON.stringify(percentageBandwidth)), + channel: JSON.parse(JSON.stringify(channel)), + subChannel: JSON.parse(JSON.stringify(subChannel)), + } + + lastObjects.candle.previous = undefined; + lastObjects.LRC.previous = undefined; + lastObjects.bollingerBand.previous = undefined; + lastObjects.percentageBandwidth.previous = undefined; + lastObjects.channel.previous = undefined; + lastObjects.subChannel.previous = undefined; + + lastObjectsArray.push(lastObjects); + + if (lastObjectsArray.length > 5) { + lastObjectsArray.splice(0,1); + } + let conditions = new Map; // Here we store the conditions values that will be use in the simulator for decision making. let conditionsArrayRecord = []; // These are the records that will be saved in a file for the plotter to consume. let conditionsArrayValues = []; // Here we store the conditions values that will be written on file for the plotter. diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index dce80df1e..144182310 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -67,6 +67,8 @@ let conditionsArray = []; let simulationLogic = {}; + let lastObjectsArray = []; + commons.initializeData(); for (let i = 0; i < dataDependencies.config.length; i++) { @@ -106,6 +108,7 @@ commons.runSimulation( recordsArray, conditionsArray, + lastObjectsArray, simulationLogic, timePeriod, writeRecordsFile) @@ -242,7 +245,7 @@ } fileContent = "[" + fileContent + "]"; - fileContent = "[" + JSON.stringify(simulationLogic) + "," + fileContent + "]"; + fileContent = "[" + JSON.stringify(simulationLogic) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]"; let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 63bb2135b..71a3e83ed 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -65,8 +65,10 @@ let recordsArray = []; let conditionsArray = []; + let lastObjectsArray = []; let simulationLogic = {}; + commons.initializeData(); for (let i = 0; i < dataDependencies.config.length; i++) { @@ -106,6 +108,7 @@ commons.runSimulation( recordsArray, conditionsArray, + lastObjectsArray, simulationLogic, timePeriod, writeRecordsFile) @@ -234,7 +237,7 @@ } fileContent = "[" + fileContent + "]"; - fileContent = "[" + JSON.stringify(simulationLogic) + "," + fileContent + "]"; + fileContent = "[" + JSON.stringify(simulationLogic) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]"; let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; From ecaf0ceb31a27002f4b7ba839123e597d3f88971 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 17 Mar 2019 20:32:45 +0100 Subject: [PATCH 057/244] Cloning Objects for Nikola --- Commons.js | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/Commons.js b/Commons.js index 4ceb812a8..54a3ea5fd 100644 --- a/Commons.js +++ b/Commons.js @@ -482,12 +482,21 @@ let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); let lastObjects = { - candle: JSON.parse(JSON.stringify(candle)), - LRC: JSON.parse(JSON.stringify(LRC)), - bollingerBand: JSON.parse(JSON.stringify(bollingerBand)), - percentageBandwidth: JSON.parse(JSON.stringify(percentageBandwidth)), - channel: JSON.parse(JSON.stringify(channel)), - subChannel: JSON.parse(JSON.stringify(subChannel)), + candle: clone(candle), + LRC: clone(LRC), + bollingerBand: clone(bollingerBand), + percentageBandwidth: clone(percentageBandwidth), + channel: clone(channel), + subChannel: clone(subChannel) + } + + function clone(obj) { + if (null == obj || "object" != typeof obj) return obj; + var copy = obj.constructor(); + for (var attr in obj) { + if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr]; + } + return copy; } lastObjects.candle.previous = undefined; From 3c733dace8c179652cea2194ecf8461191056aa6 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 17 Mar 2019 21:14:17 +0100 Subject: [PATCH 058/244] Dates were missing in path --- Commons.js | 2 +- Multi-Period-Daily/User.Bot.js | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Commons.js b/Commons.js index 54a3ea5fd..7c1ca109a 100644 --- a/Commons.js +++ b/Commons.js @@ -55,7 +55,7 @@ /* Initial Values */ - let initialDate = new Date("2018-08-01"); + let initialDate = new Date("2015-07-01"); let initialBalanceA = 1; let minimunBalanceA = 0.5; diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 144182310..43a221a07 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -54,7 +54,7 @@ } } - function start(dataFiles, timePeriod, outputPeriodLabel, currentDate, callBackFunction) { + function start(dataFiles, timePeriod, outputPeriodLabel, currentDay, callBackFunction) { try { @@ -130,7 +130,7 @@ /* Will only add to the file the records of the current day */ - if (record.begin < currentDate.valueOf()) { continue; } + if (record.begin < currentDay.valueOf()) { continue; } fileContent = fileContent + separator + '[' + record.begin + "," + @@ -167,10 +167,11 @@ fileContent = "[" + fileContent + "]"; + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); @@ -227,7 +228,7 @@ /* Will only add to the file the records of the current day */ - if (record.begin < currentDate.valueOf()) { continue; } + if (record.begin < currentDay.valueOf()) { continue; } for (let j = 0; j < record.length - 1; j++) { conditions = conditions + conditionsSeparator + record[j]; @@ -246,10 +247,12 @@ fileContent = "[" + fileContent + "]"; fileContent = "[" + JSON.stringify(simulationLogic) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]"; + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel; + let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); From 9b6a8073bd6a9f8f1cac02f11fa657f414a1de1c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 18 Mar 2019 15:44:03 +0100 Subject: [PATCH 059/244] dynamic start date and end date --- Commons.js | 136 ++++++++++++++++++++++++++++++-- Multi-Period-Daily/User.Bot.js | 4 +- Multi-Period-Market/User.Bot.js | 4 +- this.bot.config.json | 27 +++++-- 4 files changed, 157 insertions(+), 14 deletions(-) diff --git a/Commons.js b/Commons.js index 7c1ca109a..c7908576e 100644 --- a/Commons.js +++ b/Commons.js @@ -1,4 +1,7 @@ -exports.newCommons = function newCommons(bot, logger, UTILITIES) { +const axios = require('axios') +const auth = require('./utils/auth') + +exports.newCommons = function newCommons(bot, logger, UTILITIES) { const FULL_LOG = true; const LOG_FILE_CONTENT = false; @@ -41,12 +44,14 @@ candles = []; } - function runSimulation( + async function runSimulation( recordsArray, conditionsArray, lastObjectsArray, simulationLogic, timePeriod, + startDate, + endDate, callback) { try { @@ -55,7 +60,7 @@ /* Initial Values */ - let initialDate = new Date("2015-07-01"); + let initialDate = startDate; let initialBalanceA = 1; let minimunBalanceA = 0.5; @@ -106,6 +111,9 @@ let initialBuffer = 3; + simulationLogic.strategies = await getStrategy(); + + /* simulationLogic.strategies = [ { name: "Trend Following", @@ -460,7 +468,7 @@ } } ]; - + */ /* Main Simulation Loop: We go thourgh all the candles at this time period. */ for (let i = 0 + initialBuffer; i < candles.length; i++) { @@ -1242,4 +1250,122 @@ callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } -}; \ No newline at end of file + + async function getStrategy() { + + try { + + const accessToken = await auth.authenticate() + + const strategizerResponse = await axios({ + url: process.env.GATEWAY_ENDPOINT, + method: 'post', + data: { + query: ` + query($fbSlug: String!){ + + strategizer_StrategyByFb(fbSlug: $fbSlug){ + subStrategies{ + name + entryPoint{ + situations{ + name + conditions{ + name + code + } + } + } + exitPoint{ + situations{ + name + conditions{ + name + code + } + } + } + sellPoint{ + situations{ + name + conditions{ + name + code + } + } + } + buyPoint{ + situations{ + name + conditions{ + name + code + } + } + } + stopLoss{ + phases{ + name + code + situations{ + name + conditions{ + name + code + } + } + } + } + buyOrder{ + phases{ + name + code + situations{ + name + conditions{ + name + code + } + } + } + } + sellOrder{ + phases{ + name + code + situations{ + name + conditions{ + name + code + } + } + } + } + } + } + } + + `, + variables: { + fbSlug: bot.codeName + }, + }, + headers: { + authorization: 'Bearer ' + accessToken + } + }) + + if (strategizerResponse.data.errors) + throw new Error(strategizerResponse.data.errors[0].message) + + return strategizerResponse.data.data.strategizer_StrategyByFb.subStrategies; + + } catch (error) { + throw new Error('There has been an error getting the strategy to run on the simulator. Error: ' + error) + } + } +}; + + + diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 43a221a07..362a2f6eb 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -54,7 +54,7 @@ } } - function start(dataFiles, timePeriod, outputPeriodLabel, currentDay, callBackFunction) { + function start(dataFiles, timePeriod, outputPeriodLabel, currentDay, startDate, endDate, callBackFunction) { try { @@ -111,6 +111,8 @@ lastObjectsArray, simulationLogic, timePeriod, + startDate, + endDate, writeRecordsFile) function writeRecordsFile() { diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 71a3e83ed..00897693e 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -54,7 +54,7 @@ } } - function start(dataFiles, timePeriod, outputPeriodLabel, callBackFunction) { + function start(dataFiles, timePeriod, outputPeriodLabel, startDate, endDate, callBackFunction) { try { @@ -111,6 +111,8 @@ lastObjectsArray, simulationLogic, timePeriod, + startDate, + endDate, writeRecordsFile) function writeRecordsFile() { diff --git a/this.bot.config.json b/this.bot.config.json index cf3733691..637886720 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -37,6 +37,14 @@ "retryWaitTime": 10000, "sleepWaitTime": 3600000, "comaWaitTime": 86400000, + "framework": { + "name": "Multi-Period-Market", + "startDate": { + "fixedDate": "2018-07-01" + }, + "endDate": { + } + }, "statusDependencies": [ { "devTeam": "AAMasters", @@ -116,8 +124,7 @@ "dataSetVersion": "dataSet.V1", "dataSet": "Multi-Period-Market" } - ], - "framework": "Multi-Period-Market" + ] }, { "name": "Multi-Period-Daily", @@ -145,6 +152,15 @@ "retryWaitTime": 10000, "sleepWaitTime": 3600000, "comaWaitTime": 86400000, + "framework": { + "name": "Multi-Period-Daily", + "startDate": { + "fixedDate": "2018-07-01" + }, + "endDate": { + "takeItFromStatusDependency": 1 + } + }, "statusDependencies": [ { "devTeam": "AAMasters", @@ -177,8 +193,6 @@ "dataSetVersion": "dataSet.V1" } ], - "statusDependenciesIndexBegingOfMarket": 0, - "statusDependenciesIndexEndOfMarket": 1, "dataDependencies": [ { "devTeam": "AAVikings", @@ -246,8 +260,7 @@ "dataSetVersion": "dataSet.V1", "dataSet": "Multi-Period-Market" } - ], - "framework": "Multi-Period-Daily" + ] } ], "products": [ @@ -288,7 +301,7 @@ } }, { - "codeName": "SimulationConditions", + "codeName": "Simulation-Conditions", "displayName": "Simulation Conditions", "description": "Simulation Conditions", "storageAccount": "aajason", From 0361aff7816997ef8ad71a678ae71eaba54925bd Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 18 Mar 2019 21:41:08 +0100 Subject: [PATCH 060/244] Inter Process Memory Implemented --- Commons.js | 399 +++----------------------------- Multi-Period-Daily/User.Bot.js | 3 +- Multi-Period-Market/User.Bot.js | 4 +- 3 files changed, 33 insertions(+), 373 deletions(-) diff --git a/Commons.js b/Commons.js index c7908576e..10ac42fdd 100644 --- a/Commons.js +++ b/Commons.js @@ -52,6 +52,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { timePeriod, startDate, endDate, + interExecutionMemory, callback) { try { @@ -97,12 +98,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let sellRate = 0; let previousBalanceAssetA = 0; - let roundtrips = 0; - let hits = 0; - let fails = 0; let hitRatio = 0; let ROI = 0; - let periods = 0; let days = 0; let anualizedRateOfReturn = 0; let type = '""'; @@ -111,364 +108,24 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let initialBuffer = 3; - simulationLogic.strategies = await getStrategy(); + if (interExecutionMemory.roundtrips === undefined) { + interExecutionMemory.roundtrips = 0; + } - /* - simulationLogic.strategies = [ - { - name: "Trend Following", - entryPoint: { - situations: [ - { - name: "Price Collapsing", - conditions: [ - { - name: "%B Moving Average going up", - code: "percentageBandwidth.previous.direction === 'down' && percentageBandwidth.direction === 'down'" - }, - { - name: "%B Bandwidth going up", - code: "percentageBandwidth.previous.previous.bandwidth < percentageBandwidth.previous.bandwidth && percentageBandwidth.previous.bandwidth < percentageBandwidth.bandwidth" - }, - { - name: "Candles Min going down", - code: "candle.previous.previous.min > candle.previous.min && candle.previous.min > candle.min" - } - ] - } - ] - }, - exitPoint: { - situations: [ - { - name: "Market Reversing", - conditions: [ - { - name: "Close above Band Moving Average", - code: "candle.close > bollingerBand.movingAverage" - } - ] - } - ] - }, - sellPoint: { - situations: [ - { - name: "Min below lower bollingerBand.", - conditions: [ - { - name: "3 Candles MIN below Lower Band", - code: "candle.previous.previous.min < bollingerBand.previous.previous.movingAverage - bollingerBand.previous.previous.deviation && candle.previous.min < bollingerBand.previous.movingAverage - bollingerBand.previous.deviation && candle.min < bollingerBand.movingAverage - bollingerBand.deviation" - } - ] - } - ] - }, - stopLoss: { - phases: [ - { - name: "Following Sell Rate", - code: "newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100", - situations: [ - { - name: "Candle below Moving Average", - conditions: [ - { - name: "Candle fully below Band Moving Average", - code: "candle.max < bollingerBand.movingAverage" - }, - { - name: "Band Moving Average going down", - code: "bollingerBand.direction === 'down'" - } - ] - } - ] - }, - { - name: "Above Bands Moving Average", - code: "newStopLoss = bollingerBand.movingAverage + bollingerBand.movingAverage * (stopLossPercentage - stopLossDecay) / 100", - situations: [ - { - name: "Candle below Moving Average", - conditions: [ - { - name: "Candle MAX below lower band", - code: "candle.max < bollingerBand.movingAverage - bollingerBand.deviation" - } - ] - } - ] - }, - { - name: "At Bands Moving Average", - code: "newStopLoss = bollingerBand.movingAverage", - situations: [ - ] - } - ] - }, - buyOrder: { - phases: [ - { - name: "12 times standard deviation", - code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 12", - situations: [ - { - name: "Candle cut by lower band", - conditions: [ - { - name: "Max above lower band", - code: "candle.max > bollingerBand.movingAverage - bollingerBand.deviation" - }, - { - name: "MIN below lower band", - code: "candle.min < bollingerBand.movingAverage - bollingerBand.deviation" - }, - { - name: "Band Moving Average going down", - code: "bollingerBand.previous.movingAverage > bollingerBand.movingAverage" - } - ] - } - ] - }, - { - name: "10 times standard deviation", - code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 10", - situations: [ - { - name: "%B starting to revert", - conditions: [ - { - name: "%B Moving Average going up", - code: "percentageBandwidth.direction === 'up'" - }, - { - name: "%B Moving Average above 0", - code: "percentageBandwidth.movingAverage > 0" - } - ] - } - ] - }, - { - name: "4 times standard deviation", - code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 4", - situations: [ - { - name: "%B going down again", - conditions: [ - { - name: "%B Moving Average going down", - code: "percentageBandwidth.direction === 'down'" - } - ] - } - ] - }, - { - name: "3 times standard deviation", - code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 3", - situations: [ - { - name: "%B going up and above 30", - conditions: [ - { - name: "%B Moving Average going up", - code: "percentageBandwidth.direction === 'up'" - }, - { - name: "%B Moving Average above 30", - code: "percentageBandwidth.movingAverage > 30" - } - ] - } - ] - }, - { - name: "At lower band", - code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 2", - situations: [ - ] - } - ] - } - }, - { - name: "Range Trading", - entryPoint: { - situations: [ - { - name: "Gentle Up Trend", - conditions: [ - { - name: "Sub-Channel going up", - code: "subChannel.direction === 'up'" - }, - { - name: "Sub-Channel Side|Gentle|Medium", - code: "subChannel.slope === 'Side' || subChannel.slope === 'Gentle' || subChannel.slope === 'Medium'" - }, - { - name: "Candle Close above Lower Band", - code: "candle.close > bollingerBand.movingAverage + bollingerBand.deviation" - }, - { - name: "Impossible", - code: " 1 === 2" - } - ] - } - ] - }, - exitPoint: { - situations: [ - { - name: "Outside Sub-Channel", - conditions: [ - { - name: "Going down or too Steep", - code: "subChannel.direction === 'Down' || subChannel.slope === 'Steep' || subChannel.slope === 'Extreme'" - } - ] - } - ] - }, - sellPoint: { - situations: [ - { - name: "Min below lower bollingerBand.", - conditions: [ - { - name: "%B Moving Average going down", - code: "percentageBandwidth.previous.movingAverage > percentageBandwidth.movingAverage" - }, - { - name: "%B Moving Average above 90", - code: "percentageBandwidth.previous.movingAverage > 90" - } - ] - } - ] - }, - stopLoss: { - phases: [ - { - name: "Following Sell Rate", - code: "newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100", - situations: [ - ] - } - ] - }, - buyOrder: { - phases: [ - { - name: "Between Band Moving Average and Lower Band", - code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation", - situations: [ - ] - } - ] - } - } - , - { - name: "LRC Strategy", - entryPoint: { - situations: [ - { - name: "Lines in the right order", - conditions: [ - { - name: "60 > 30", - code: "LRC._60 > LRC._30" - }, - { - name: "30 > 15", - code: "LRC._30 > LRC._15" - }, - { - name: "Impossible", - code: " 1 === 2" - } - ] - } - ] - }, - exitPoint: { - situations: [ - { - name: "Lines out of order", - conditions: [ - { - name: "60 < 30 or 30 < 15", - code: "LRC._60 < LRC._30 || LRC._30 < LRC._15 " - } - ] - } - ] - }, - sellPoint: { - situations: [ - { - name: "All lines going down", - conditions: [ - { - name: "60 going down", - code: "LRC.direction60 === 'down'" - }, - { - name: "30 going down", - code: "LRC.direction30 === 'down'" - }, - { - name: "15 going down", - code: "LRC.direction15 === 'down'" - } - ] - } - ] - }, - stopLoss: { - phases: [ - { - name: "Following Sell Rate", - code: "newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100", - situations: [ - { - name: "Stop Loss < 60", - conditions: [ - { - name: "Stop Loss < 60", - code: "stopLoss < LRC._60" - } - ] - } - ] - }, - { - name: "Following 60", - code: "newStopLoss = LRC._60", - situations: [ - ] - } - ] - }, - buyOrder: { - phases: [ - { - name: "Between Band Moving Average and Lower Band", - code: "buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 4", - situations: [ - ] - } - ] - } - } - ]; - */ + if (interExecutionMemory.fails === undefined) { + interExecutionMemory.fails = 0; + } + + if (interExecutionMemory.hits === undefined) { + interExecutionMemory.hits = 0; + } + + if (interExecutionMemory.periods === undefined) { + interExecutionMemory.periods = 0; + } + + simulationLogic.strategies = await getStrategy(); + /* Main Simulation Loop: We go thourgh all the candles at this time period. */ for (let i = 0 + initialBuffer; i < candles.length; i++) { @@ -484,7 +141,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (percentageBandwidth === undefined) { continue; } // percentageBandwidth might start after the first few candles. if (candle.begin < initialDate.valueOf()) { continue; } - periods++; + interExecutionMemory.periods++; let channel = getElement(bollingerChannelsArray, candle.begin, candle.end); let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); @@ -895,7 +552,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (strategyPhase === 4) { - roundtrips++; + interExecutionMemory.roundtrips++; lastProfit = balanceAssetA - previousBalanceAssetA; lastProfitPercent = lastProfit / previousBalanceAssetA * 100; @@ -907,14 +564,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { //if (isNaN(ROI)) { ROI = 0; } if (lastProfit > 0) { - hits++; + interExecutionMemory.hits++; } else { - fails++; + interExecutionMemory.fails++; } - hitRatio = hits / roundtrips; + hitRatio = interExecutionMemory.hits / interExecutionMemory.roundtrips; let miliSecondsPerDay = 24 * 60 * 60 * 1000; - days = periods * timePeriod / miliSecondsPerDay; + days = interExecutionMemory.periods * timePeriod / miliSecondsPerDay; anualizedRateOfReturn = ROI / days * 365; addRecord(); @@ -949,12 +606,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { profit: profit, lastProfit: lastProfit, stopLoss: stopLoss, - roundtrips: roundtrips, - hits: hits, - fails: fails, + roundtrips: interExecutionMemory.roundtrips, + hits: interExecutionMemory.hits, + fails: interExecutionMemory.fails, hitRatio: hitRatio, ROI: ROI, - periods: periods, + periods: interExecutionMemory.periods, days: days, anualizedRateOfReturn: anualizedRateOfReturn, sellRate: sellRate, diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 362a2f6eb..bf520195d 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -54,7 +54,7 @@ } } - function start(dataFiles, timePeriod, outputPeriodLabel, currentDay, startDate, endDate, callBackFunction) { + function start(dataFiles, timePeriod, outputPeriodLabel, currentDay, startDate, endDate, interExecutionMemory, callBackFunction) { try { @@ -113,6 +113,7 @@ timePeriod, startDate, endDate, + interExecutionMemory, writeRecordsFile) function writeRecordsFile() { diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 00897693e..1484c20c1 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -54,7 +54,7 @@ } } - function start(dataFiles, timePeriod, outputPeriodLabel, startDate, endDate, callBackFunction) { + function start(dataFiles, timePeriod, outputPeriodLabel, startDate, endDate, callBackFunction) { try { @@ -68,6 +68,7 @@ let lastObjectsArray = []; let simulationLogic = {}; + let interExecutionMemory = {}; commons.initializeData(); @@ -113,6 +114,7 @@ timePeriod, startDate, endDate, + interExecutionMemory, writeRecordsFile) function writeRecordsFile() { From 4f54adf23535d005529d8f8b5c4d6281b916490e Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 19 Mar 2019 10:30:41 +0100 Subject: [PATCH 061/244] Problems to manage inter execution conters solved --- Commons.js | 151 ++++++++++++++++++++++++++------ Multi-Period-Daily/User.Bot.js | 1 + Multi-Period-Market/User.Bot.js | 4 +- 3 files changed, 130 insertions(+), 26 deletions(-) diff --git a/Commons.js b/Commons.js index 10ac42fdd..97f0697c7 100644 --- a/Commons.js +++ b/Commons.js @@ -7,7 +7,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { const LOG_FILE_CONTENT = false; const MODULE_NAME = "Commons"; - + const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; const GMT_SECONDS = ':00.000 GMT+0000'; let thisObject = { @@ -50,6 +50,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { lastObjectsArray, simulationLogic, timePeriod, + currentDay, startDate, endDate, interExecutionMemory, @@ -106,29 +107,59 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let rate = 0; let newStopLoss; - let initialBuffer = 3; + /* + The following counters need to survive multiple executions of the similator and keep themselves reliable. + This is challenging when the simulation is executed using Daily Files, since each execution means a new + day and these counters are meant to be kept along the whole market. + + To overcome this problem, we use the interExecutionMemory to record the values of the current execution + when finish. But there are a few details: + + 1. When the process is at the head of the market, it executes multple times at the same day. + 2. The same code serves execution from Market Files. + 3. In Daily Files we are receiving candles from the current day and previous day, so we need to take care of + not adding to the counters duplicate info when processing the day before candles. + + To overcome these challenges we record the values of the counters on the interExecutionMemory only when + the day is complete and if we have a currentDay. That menas that for Market Files we will never use + interExecutionMemory. + */ + + let roundtrips = 0; + let fails = 0; + let hits = 0; + let periods = 0; + + let yesterdayRoundtrips = 0; + let yesterdayFails = 0; + let yesterdayHits = 0; + let yesterdayPeriods = 0; if (interExecutionMemory.roundtrips === undefined) { + + /* Initialize the data structure we will use inter execution. */ + interExecutionMemory.roundtrips = 0; - } - - if (interExecutionMemory.fails === undefined) { interExecutionMemory.fails = 0; - } - - if (interExecutionMemory.hits === undefined) { interExecutionMemory.hits = 0; - } - - if (interExecutionMemory.periods === undefined) { interExecutionMemory.periods = 0; + + } else { + + /* We get the initial values from the day previous to the candles we receive at the current execution */ + + roundtrips = interExecutionMemory.roundtrips; + fails = interExecutionMemory.fails; + hits = interExecutionMemory.hits; + periods = interExecutionMemory.periods; + } simulationLogic.strategies = await getStrategy(); /* Main Simulation Loop: We go thourgh all the candles at this time period. */ - for (let i = 0 + initialBuffer; i < candles.length; i++) { + for (let i = 0; i < candles.length; i++) { /* Update all the data objects available for the simulation. */ @@ -141,7 +172,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (percentageBandwidth === undefined) { continue; } // percentageBandwidth might start after the first few candles. if (candle.begin < initialDate.valueOf()) { continue; } - interExecutionMemory.periods++; + periods++; + + if (currentDay !== undefined) { + if (candle.end < currentDay.valueOf()) { + yesterdayPeriods++; + } + } let channel = getElement(bollingerChannelsArray, candle.begin, candle.end); let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); @@ -269,10 +306,21 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function newCondition(key, code) { let condition; + let value = false; + + try { + value = eval(code); + } catch (err) { + /* + One possible error is that the conditions references a .previous that is undefined. For this + reason and others, we will simply set the value to false. + */ + value = false + } condition = { key: key, - value: eval(code) + value: value }; conditions.set(condition.key, condition); @@ -452,7 +500,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let phase = strategy.stopLoss.phases[stopLossPhase - 1]; - eval(phase.code); // Here is where we apply the formula given for the stop loss for this phase. + try { + eval(phase.code); // Here is where we apply the formula given for the stop loss for this phase. + } catch (err) { + /* + If the code produces an exception, we are covered. + */ + } if (newStopLoss < previousStopLoss) { stopLoss = newStopLoss; @@ -497,7 +551,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let phase = strategy.buyOrder.phases[buyOrderPhase - 1]; - eval(phase.code); // Here is where we apply the formula given for the buy order at this phase. + try { + eval(phase.code); // Here is where we apply the formula given for the buy order at this phase. + } catch (err) { + /* + If the code produces an exception, we are covered. + */ + } for (let k = 0; k < phase.situations.length; k++) { @@ -552,7 +612,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (strategyPhase === 4) { - interExecutionMemory.roundtrips++; + roundtrips++; + + if (currentDay !== undefined) { + if (candle.end < currentDay.valueOf()) { + yesterdayRoundtrips++; + } + } + lastProfit = balanceAssetA - previousBalanceAssetA; lastProfitPercent = lastProfit / previousBalanceAssetA * 100; @@ -564,14 +631,27 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { //if (isNaN(ROI)) { ROI = 0; } if (lastProfit > 0) { - interExecutionMemory.hits++; + hits++; + + if (currentDay !== undefined) { + if (candle.end < currentDay.valueOf()) { + yesterdayHits++; + } + } + } else { - interExecutionMemory.fails++; + fails++; + + if (currentDay !== undefined) { + if (candle.end < currentDay.valueOf()) { + yesterdayFails++; + } + } } - hitRatio = interExecutionMemory.hits / interExecutionMemory.roundtrips; + hitRatio = hits / roundtrips; let miliSecondsPerDay = 24 * 60 * 60 * 1000; - days = interExecutionMemory.periods * timePeriod / miliSecondsPerDay; + days = periods * timePeriod / miliSecondsPerDay; anualizedRateOfReturn = ROI / days * 365; addRecord(); @@ -606,12 +686,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { profit: profit, lastProfit: lastProfit, stopLoss: stopLoss, - roundtrips: interExecutionMemory.roundtrips, - hits: interExecutionMemory.hits, - fails: interExecutionMemory.fails, + roundtrips: roundtrips, + hits: hits, + fails: fails, hitRatio: hitRatio, ROI: ROI, - periods: interExecutionMemory.periods, + periods: periods, days: days, anualizedRateOfReturn: anualizedRateOfReturn, sellRate: sellRate, @@ -640,6 +720,27 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } + /* + Before returning we need to see if we have to record some of our counters at the interExecutionMemory. + To do that, the condition to be met is that this execution must include all candles of the currentDay. + */ + + if (currentDay !== undefined) { + + let lastInstantOdDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1; + + lastCandle = candles[candles.length - 1]; + + if (lastCandle.end === lastInstantOdDay) { + + interExecutionMemory.roundtrips = interExecutionMemory.roundtrips + yesterdayRoundtrips; + interExecutionMemory.fails = interExecutionMemory.fails + yesterdayFails; + interExecutionMemory.hits = interExecutionMemory.hits + yesterdayHits; + interExecutionMemory.periods = interExecutionMemory.periods + yesterdayPeriods; + + } + } + callback(); function getElement(pArray, begin, end) { diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index bf520195d..0bf942278 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -111,6 +111,7 @@ lastObjectsArray, simulationLogic, timePeriod, + currentDay, startDate, endDate, interExecutionMemory, diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 1484c20c1..a621b87e8 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -69,7 +69,8 @@ let simulationLogic = {}; let interExecutionMemory = {}; - + let currentDay; + commons.initializeData(); for (let i = 0; i < dataDependencies.config.length; i++) { @@ -112,6 +113,7 @@ lastObjectsArray, simulationLogic, timePeriod, + currentDay, startDate, endDate, interExecutionMemory, From 22460d1e1d0fb770b6419d006d73e12abb60414a Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 19 Mar 2019 17:46:20 +0100 Subject: [PATCH 062/244] Balance being correctly stored in inter execution memory --- Commons.js | 103 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 79 insertions(+), 24 deletions(-) diff --git a/Commons.js b/Commons.js index 97f0697c7..d13f610b1 100644 --- a/Commons.js +++ b/Commons.js @@ -62,7 +62,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Initial Values */ - let initialDate = startDate; + let initialDate = startDate; let initialBalanceA = 1; let minimunBalanceA = 0.5; @@ -91,12 +91,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Building records */ let record; - let balanceAssetA = initialBalanceA; - let balanceAssetB = 0; let profit = 0; - let lastProfit = 0; let lastProfitPercent = 0; let sellRate = 0; + let sellInstant; let previousBalanceAssetA = 0; let hitRatio = 0; @@ -120,25 +118,39 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { 3. In Daily Files we are receiving candles from the current day and previous day, so we need to take care of not adding to the counters duplicate info when processing the day before candles. - To overcome these challenges we record the values of the counters on the interExecutionMemory only when + To overcome these challenges we record the values of the counters and variables on the interExecutionMemory only when the day is complete and if we have a currentDay. That menas that for Market Files we will never use interExecutionMemory. */ + let balanceAssetA = initialBalanceA; + let balanceAssetB = 0; + let lastProfit = 0; + let roundtrips = 0; let fails = 0; let hits = 0; let periods = 0; - let yesterdayRoundtrips = 0; - let yesterdayFails = 0; - let yesterdayHits = 0; - let yesterdayPeriods = 0; + let yesterday = {}; + + yesterday.balanceAssetA = 0; + yesterday.balanceAssetB = 0; + yesterday.lastProfit = 0; + + yesterday.Roundtrips = 0; + yesterday.Fails = 0; + yesterday.Hits = 0; + yesterday.Periods = 0; if (interExecutionMemory.roundtrips === undefined) { /* Initialize the data structure we will use inter execution. */ + interExecutionMemory.balanceAssetA = balanceAssetA; + interExecutionMemory.balanceAssetB = balanceAssetB; + interExecutionMemory.lastProfit = lastProfit; + interExecutionMemory.roundtrips = 0; interExecutionMemory.fails = 0; interExecutionMemory.hits = 0; @@ -148,6 +160,15 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* We get the initial values from the day previous to the candles we receive at the current execution */ + if (currentDay.valueOf() > startDate.valueOf() + ONE_DAY_IN_MILISECONDS) { // Only after the first day we start grabbing the balance from this memory. + + balanceAssetA = interExecutionMemory.balanceAssetA; + balanceAssetB = interExecutionMemory.balanceAssetB; + + } + + lastProfit = interExecutionMemory.lastProfit; + roundtrips = interExecutionMemory.roundtrips; fails = interExecutionMemory.fails; hits = interExecutionMemory.hits; @@ -173,10 +194,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (candle.begin < initialDate.valueOf()) { continue; } periods++; + days = periods * timePeriod / ONE_DAY_IN_MILISECONDS; if (currentDay !== undefined) { if (candle.end < currentDay.valueOf()) { - yesterdayPeriods++; + yesterday.Periods++; } } @@ -429,8 +451,15 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (candle.max >= stopLoss) { balanceAssetA = balanceAssetB / stopLoss; - balanceAssetB = 0; + + if (currentDay !== undefined) { + if (sellInstant < currentDay.valueOf()) { + yesterday.balanceAssetA = balanceAssetA; + yesterday.balanceAssetB = balanceAssetB; + } + } + rate = stopLoss; type = '"Buy@StopLoss"'; strategyPhase = 4; @@ -441,8 +470,16 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (candle.min <= buyOrder) { balanceAssetA = balanceAssetB / buyOrder; - balanceAssetB = 0; + + if (currentDay !== undefined) { + if (sellInstant < currentDay.valueOf()) { + yesterday.balanceAssetA = balanceAssetA; + yesterday.balanceAssetB = balanceAssetB; + + } + } + rate = buyOrder; type = '"Buy@BuyOrder"'; strategyPhase = 4; @@ -595,8 +632,17 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { balanceAssetB = balanceAssetA * candle.close; balanceAssetA = 0; + if (currentDay !== undefined) { + if (sellInstant < currentDay.valueOf()) { + yesterday.balanceAssetA = balanceAssetA; + yesterday.balanceAssetB = balanceAssetB; + yesterday.lastProfit = lastProfit; + } + } + rate = candle.close; sellRate = rate; + sellInstant = candle.end; stopLoss = sellRate + sellRate * stopLossPercentage / 100; @@ -615,13 +661,19 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { roundtrips++; if (currentDay !== undefined) { - if (candle.end < currentDay.valueOf()) { - yesterdayRoundtrips++; + if (sellInstant < currentDay.valueOf()) { + yesterday.Roundtrips++; } } lastProfit = balanceAssetA - previousBalanceAssetA; + if (currentDay !== undefined) { + if (sellInstant < currentDay.valueOf()) { + yesterday.lastProfit = lastProfit; + } + } + lastProfitPercent = lastProfit / previousBalanceAssetA * 100; if (isNaN(lastProfitPercent)) { lastProfitPercent = 0; } @@ -634,8 +686,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { hits++; if (currentDay !== undefined) { - if (candle.end < currentDay.valueOf()) { - yesterdayHits++; + if (sellInstant < currentDay.valueOf()) { + yesterday.Hits++; } } @@ -643,15 +695,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { fails++; if (currentDay !== undefined) { - if (candle.end < currentDay.valueOf()) { - yesterdayFails++; + if (sellInstant < currentDay.valueOf()) { + yesterday.Fails++; } } } hitRatio = hits / roundtrips; - let miliSecondsPerDay = 24 * 60 * 60 * 1000; - days = periods * timePeriod / miliSecondsPerDay; anualizedRateOfReturn = ROI / days * 365; addRecord(); @@ -659,6 +709,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategyNumber = 0; stopLoss = 0; sellRate = 0; + sellInstant = undefined; buyOrder = 0; strategyPhase = 0; stopLossPhase = 0; @@ -733,10 +784,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (lastCandle.end === lastInstantOdDay) { - interExecutionMemory.roundtrips = interExecutionMemory.roundtrips + yesterdayRoundtrips; - interExecutionMemory.fails = interExecutionMemory.fails + yesterdayFails; - interExecutionMemory.hits = interExecutionMemory.hits + yesterdayHits; - interExecutionMemory.periods = interExecutionMemory.periods + yesterdayPeriods; + interExecutionMemory.balanceAssetA = yesterday.balanceAssetA; + interExecutionMemory.balanceAssetB = yesterday.balanceAssetB; + interExecutionMemory.lastProfit = yesterday.lastProfit; + + interExecutionMemory.roundtrips = interExecutionMemory.roundtrips + yesterday.Roundtrips; + interExecutionMemory.fails = interExecutionMemory.fails + yesterday.Fails; + interExecutionMemory.hits = interExecutionMemory.hits + yesterday.Hits; + interExecutionMemory.periods = interExecutionMemory.periods + yesterday.Periods; } } From 5ca181265618e4d6e971d5f71ed2de01e372fe42 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 19 Mar 2019 20:38:50 +0100 Subject: [PATCH 063/244] undefined at file BUG resolved --- Commons.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Commons.js b/Commons.js index d13f610b1..c8d826179 100644 --- a/Commons.js +++ b/Commons.js @@ -134,8 +134,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let yesterday = {}; - yesterday.balanceAssetA = 0; - yesterday.balanceAssetB = 0; + yesterday.balanceAssetA = balanceAssetA; + yesterday.balanceAssetB = balanceAssetB; + yesterday.lastProfit = 0; yesterday.Roundtrips = 0; @@ -165,6 +166,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { balanceAssetA = interExecutionMemory.balanceAssetA; balanceAssetB = interExecutionMemory.balanceAssetB; + yesterday.balanceAssetA = balanceAssetA; + yesterday.balanceAssetB = balanceAssetB; + } lastProfit = interExecutionMemory.lastProfit; @@ -632,6 +636,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { balanceAssetB = balanceAssetA * candle.close; balanceAssetA = 0; + sellInstant = candle.end; + if (currentDay !== undefined) { if (sellInstant < currentDay.valueOf()) { yesterday.balanceAssetA = balanceAssetA; @@ -642,8 +648,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { rate = candle.close; sellRate = rate; - sellInstant = candle.end; - + stopLoss = sellRate + sellRate * stopLossPercentage / 100; stopLossDecay = 0; @@ -677,8 +682,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { lastProfitPercent = lastProfit / previousBalanceAssetA * 100; if (isNaN(lastProfitPercent)) { lastProfitPercent = 0; } - profit = profit + lastProfit; - + profit = initialBalanceA - balanceAssetA; + ROI = (initialBalanceA + profit) / initialBalanceA - 1; //if (isNaN(ROI)) { ROI = 0; } From 075d2e9b7005f698f31137d2f1c9ca981480b246 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 26 Mar 2019 10:38:54 +0100 Subject: [PATCH 064/244] Filtering out inactive strategies --- Commons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index c8d826179..0deed4f4a 100644 --- a/Commons.js +++ b/Commons.js @@ -1083,7 +1083,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { query($fbSlug: String!){ strategizer_StrategyByFb(fbSlug: $fbSlug){ - subStrategies{ + subStrategies(activeOnly: true){ name entryPoint{ situations{ From 0e06a53ee155fdb613df02855e3cf25094c50240 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 29 Mar 2019 10:04:05 +0100 Subject: [PATCH 065/244] New Standard of MQService Implemented --- Commons.js | 113 +++++++++++++++++++++++++++++++- Multi-Period-Daily/User.Bot.js | 3 +- Multi-Period-Market/User.Bot.js | 5 +- 3 files changed, 117 insertions(+), 4 deletions(-) diff --git a/Commons.js b/Commons.js index 0deed4f4a..8b8138e7b 100644 --- a/Commons.js +++ b/Commons.js @@ -132,6 +132,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let hits = 0; let periods = 0; + /* Message to Su=Simulation Executor */ + + let orderId = 0; + let messageId = 0; + let yesterday = {}; yesterday.balanceAssetA = balanceAssetA; @@ -144,6 +149,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { yesterday.Hits = 0; yesterday.Periods = 0; + yesterday.orderId = 0; + yesterday.messageId = 0; + if (interExecutionMemory.roundtrips === undefined) { /* Initialize the data structure we will use inter execution. */ @@ -157,6 +165,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { interExecutionMemory.hits = 0; interExecutionMemory.periods = 0; + interExecutionMemory.orderId = 0; + interExecutionMemory.messageId = 0; + } else { /* We get the initial values from the day previous to the candles we receive at the current execution */ @@ -178,6 +189,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { hits = interExecutionMemory.hits; periods = interExecutionMemory.periods; + orderId = interExecutionMemory.orderId; + messageId = interExecutionMemory.messageId; } simulationLogic.strategies = await getStrategy(); @@ -731,6 +744,101 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function addRecord() { + // Since we are going to write the message to a file that the Simulation Executor is going to read, we use the abbreviations. + let messageType; + let message; + + messageId++; + + if (strategyPhase === 2 || strategyPhase === 3) { + + if (strategyPhase === 2) { + messageType = "Order"; + orderId++; + } + if (strategyPhase === 3) { + messageType = "Order Update"; + } + + message = { + id: messageId, // This is a unique Id within the system component that originated the message. + from: "SEN", // "Simulation Executor|Trading Cockpit|Simulation Engine|Trading Assistant", // --> "SEX|COK|SEN|ASS" + to: "SEX", // "Simulation Executor|Trading Cockpit|Simulation Engine|Trading Assistant", // --> "SEX|COK|SEN|ASS" + messageType: messageType, // "Order Authorization Request|Order Authorization Response|Order|Order Update", // --> "ARQ|ARS|ORD|UPT" + dateTime: (new Date()).valueOf(), + order: { + id: orderId, // This is a unique Id within the system component that originated the order. + creator: "SE", // "Simulation Engine|Human Trader", // --> "SE|HT" + dateTime: (new Date()).valueOf(), + owner: "Node/Team/User", + exchange: "Poloniex", + market: "BTC/USDT", + marginEnabled: 0, // true | false --> 1|0 + type: "L", // "Market|Limit|Stop", // --> "M|L|S" + rate: rate, + stop: stopLoss, + takeProfit: buyOrder, + direction: "Sell", //"Sell|Buy", // --> "Sell|Buy" + size: "All", + status: "Signaled", // "Signaled|Manual Authorized|Manual Not Authorized|Auto Authorized|Auto Not Authorized|Executing|Cancelled|Filled|Partially Filled|Discarded|Placed", // --> "SIG|MAU|MNA|AAU|ANA|EXE|CAN|FIL|PRT|DIS|PLA" + sizeFilled: 0, + exitOutcome: "" // "Stop Loss|Take Profit" // --> "SL|TP" + } + } + } else { + + message = { + id: messageId, + from: "SEN", + to: "SEX", + messageType: "HBT", // Heart Beat, no order or updates sent, just informing we are alive. + dateTime: (new Date()).valueOf(), + order: { + id: 0, + creator: "", + dateTime: 0, + owner: "", + exchange: "", + market: "", + marginEnabled: 0, + type: "", + rate: 0, + stop: 0, + takeProfit: 0, + direction: "", + size: "", + status: "", + sizeFilled: 0, + exitOutcome: "" + } + } + } + + let recordToSimulationExecutor = [ + message.id, + message.from, + message.to, + message.messageType, + message.dateTime, + [ + message.order.id, + message.order.creator, + message.order.owner, + message.order.exchange, + message.order.market, + message.order.marginEnabled, + message.order.type, + message.order.rate, + message.order.stop, + message.order.takeProfit, + message.order.direction, + message.order.size, + message.order.status, + message.order.sizeFilled, + message.order.exitOutcome + ] + ] + record = { begin: candle.begin, end: candle.end, @@ -756,7 +864,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategyPhase: strategyPhase, buyOrder: buyOrder, stopLossPhase: stopLossPhase, - buyOrderPhase: buyOrderPhase + buyOrderPhase: buyOrderPhase, + recordToSimulationExecutor: recordToSimulationExecutor } recordsArray.push(record); @@ -798,6 +907,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { interExecutionMemory.hits = interExecutionMemory.hits + yesterday.Hits; interExecutionMemory.periods = interExecutionMemory.periods + yesterday.Periods; + interExecutionMemory.messageId = interExecutionMemory.messageId + yesterday.messageId; + interExecutionMemory.orderId = interExecutionMemory.orderId + yesterday.orderId; } } diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 0bf942278..45205c261 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -161,7 +161,8 @@ record.strategyPhase + "," + record.buyOrder + "," + record.stopLossPhase + "," + - record.buyOrderPhase + "]"; + record.buyOrderPhase + "," + + JSON.stringify(record.recordToSimulationExecutor) + "]"; if (separator === "") { separator = ","; } diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index a621b87e8..9cfe89332 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -159,8 +159,9 @@ record.strategyPhase + "," + record.buyOrder + "," + record.stopLossPhase + "," + - record.buyOrderPhase + "]"; - + record.buyOrderPhase + "," + + JSON.stringify(record.recordToSimulationExecutor) + "]"; + if (separator === "") { separator = ","; } fileRecordCounter++; From f4814ccdeb874d03e9a000a047db9464fe263726 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 29 Mar 2019 21:59:37 +0100 Subject: [PATCH 066/244] Using MQService Library --- Commons.js | 133 +++++++++++++++++++--------------------------- package-lock.json | 13 +++++ package.json | 1 + 3 files changed, 69 insertions(+), 78 deletions(-) create mode 100644 package-lock.json diff --git a/Commons.js b/Commons.js index 8b8138e7b..384a61ba2 100644 --- a/Commons.js +++ b/Commons.js @@ -3,6 +3,12 @@ const auth = require('./utils/auth') exports.newCommons = function newCommons(bot, logger, UTILITIES) { + const { + MESSAGE_ENTITY, MESSAGE_TYPE, ORDER_CREATOR, ORDER_TYPE, + ORDER_OWNER, ORDER_DIRECTION, ORDER_STATUS, ORDER_EXIT_OUTCOME, + createRecord, getRecord, getExpandedRecord + } = require("@superalgos/mqservice") + const FULL_LOG = true; const LOG_FILE_CONTENT = false; @@ -747,98 +753,69 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { // Since we are going to write the message to a file that the Simulation Executor is going to read, we use the abbreviations. let messageType; let message; + let record; messageId++; if (strategyPhase === 2 || strategyPhase === 3) { if (strategyPhase === 2) { - messageType = "Order"; + messageType = MESSAGE_TYPE.Order; orderId++; } if (strategyPhase === 3) { - messageType = "Order Update"; + messageType = MESSAGE_TYPE.OrderUpdate; } - message = { - id: messageId, // This is a unique Id within the system component that originated the message. - from: "SEN", // "Simulation Executor|Trading Cockpit|Simulation Engine|Trading Assistant", // --> "SEX|COK|SEN|ASS" - to: "SEX", // "Simulation Executor|Trading Cockpit|Simulation Engine|Trading Assistant", // --> "SEX|COK|SEN|ASS" - messageType: messageType, // "Order Authorization Request|Order Authorization Response|Order|Order Update", // --> "ARQ|ARS|ORD|UPT" - dateTime: (new Date()).valueOf(), - order: { - id: orderId, // This is a unique Id within the system component that originated the order. - creator: "SE", // "Simulation Engine|Human Trader", // --> "SE|HT" - dateTime: (new Date()).valueOf(), - owner: "Node/Team/User", - exchange: "Poloniex", - market: "BTC/USDT", - marginEnabled: 0, // true | false --> 1|0 - type: "L", // "Market|Limit|Stop", // --> "M|L|S" - rate: rate, - stop: stopLoss, - takeProfit: buyOrder, - direction: "Sell", //"Sell|Buy", // --> "Sell|Buy" - size: "All", - status: "Signaled", // "Signaled|Manual Authorized|Manual Not Authorized|Auto Authorized|Auto Not Authorized|Executing|Cancelled|Filled|Partially Filled|Discarded|Placed", // --> "SIG|MAU|MNA|AAU|ANA|EXE|CAN|FIL|PRT|DIS|PLA" - sizeFilled: 0, - exitOutcome: "" // "Stop Loss|Take Profit" // --> "SL|TP" - } - } + record = createRecord( + messageId, + MESSAGE_ENTITY.SimulationEngine, + MESSAGE_ENTITY.SimulationExecutor, + messageType, + (new Date()).valueOf(), + orderId, + ORDER_CREATOR.SimulationEngine, + (new Date()).valueOf(), + ORDER_OWNER.User, + "Poloniex", + "BTC/USDT", + 0, + ORDER_TYPE.Limit, + rate, + stopLoss, + buyOrder, + ORDER_DIRECTION.Sell, + "All", + ORDER_STATUS.Signaled, + 0, + "") + } else { - message = { - id: messageId, - from: "SEN", - to: "SEX", - messageType: "HBT", // Heart Beat, no order or updates sent, just informing we are alive. - dateTime: (new Date()).valueOf(), - order: { - id: 0, - creator: "", - dateTime: 0, - owner: "", - exchange: "", - market: "", - marginEnabled: 0, - type: "", - rate: 0, - stop: 0, - takeProfit: 0, - direction: "", - size: "", - status: "", - sizeFilled: 0, - exitOutcome: "" - } - } + record = createRecord( + messageId, + MESSAGE_ENTITY.SimulationEngine, + MESSAGE_ENTITY.SimulationExecutor, + MESSAGE_TYPE.HeartBeat, + (new Date()).valueOf(), + 0, + "", + 0, + "", + "", + "", + 0, + "", + 0, + 0, + 0, + "", + "", + "", + 0, + "") } - let recordToSimulationExecutor = [ - message.id, - message.from, - message.to, - message.messageType, - message.dateTime, - [ - message.order.id, - message.order.creator, - message.order.owner, - message.order.exchange, - message.order.market, - message.order.marginEnabled, - message.order.type, - message.order.rate, - message.order.stop, - message.order.takeProfit, - message.order.direction, - message.order.size, - message.order.status, - message.order.sizeFilled, - message.order.exitOutcome - ] - ] - record = { begin: candle.begin, end: candle.end, @@ -865,7 +842,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { buyOrder: buyOrder, stopLossPhase: stopLossPhase, buyOrderPhase: buyOrderPhase, - recordToSimulationExecutor: recordToSimulationExecutor + recordToSimulationExecutor: record } recordsArray.push(record); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..4fc77c7f4 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "AAToma", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@superalgos/mqservice": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@superalgos/mqservice/-/mqservice-0.0.3.tgz", + "integrity": "sha512-7beJRbcylkzND1MnWdEIrmtrqOyFvRsS131JKk6Xap5fFpS8kPpXKHEY50K97qwBnbTJZSJyNvSjafJPRUNjqQ==" + } + } +} diff --git a/package.json b/package.json index 11cc6a7f1..76760c537 100644 --- a/package.json +++ b/package.json @@ -9,5 +9,6 @@ "author": "Luis-Fernando-Molina", "license": "ISC", "dependencies": { + "@superalgos/mqservice": "0.0.3" } } From 52b0cec6b1c05159c848dfe5a985c506b019a909 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 6 Apr 2019 09:47:07 +0200 Subject: [PATCH 067/244] Multi Exchange --- Commons.js | 4 ++-- Multi-Period-Daily/User.Bot.js | 2 -- Multi-Period-Market/User.Bot.js | 2 -- this.bot.config.json | 8 +++++++- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Commons.js b/Commons.js index 384a61ba2..31d776fd1 100644 --- a/Commons.js +++ b/Commons.js @@ -777,8 +777,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { ORDER_CREATOR.SimulationEngine, (new Date()).valueOf(), ORDER_OWNER.User, - "Poloniex", - "BTC/USDT", + global.EXCHANGE_NAME, + "BTC_USDT", 0, ORDER_TYPE.Limit, rate, diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 45205c261..4ce9c3304 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -5,8 +5,6 @@ const MODULE_NAME = "User Bot"; - const EXCHANGE_NAME = "Poloniex"; - const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 9cfe89332..b8760d0fc 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -5,8 +5,6 @@ const MODULE_NAME = "User Bot"; - const EXCHANGE_NAME = "Poloniex"; - const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; diff --git a/this.bot.config.json b/this.bot.config.json index 637886720..6290a1b0b 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -169,7 +169,7 @@ "major": 1, "minor": 0 }, - "process": "Poloniex-Historic-Trades", + "process": "Historic-Trades", "dataSetVersion": "dataSet.V1" }, { @@ -292,6 +292,9 @@ "exchangeList": [ { "name": "Poloniex" + }, + { + "name": "Coss" } ], "plotter": { @@ -328,6 +331,9 @@ "exchangeList": [ { "name": "Poloniex" + }, + { + "name": "Coss" } ], "plotter": { From 38386069fa4ddf7e867d4682c578ea549e1eb241 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 6 Apr 2019 13:07:01 +0200 Subject: [PATCH 068/244] Upgrade to MQService .13 --- Commons.js | 26 +++++++++++++++----------- Multi-Period-Daily/User.Bot.js | 2 +- Multi-Period-Market/User.Bot.js | 2 +- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/Commons.js b/Commons.js index 31d776fd1..f797e9bed 100644 --- a/Commons.js +++ b/Commons.js @@ -3,11 +3,14 @@ const auth = require('./utils/auth') exports.newCommons = function newCommons(bot, logger, UTILITIES) { + const { orderMessage } = require("@superalgos/mqservice") + const { - MESSAGE_ENTITY, MESSAGE_TYPE, ORDER_CREATOR, ORDER_TYPE, - ORDER_OWNER, ORDER_DIRECTION, ORDER_STATUS, ORDER_EXIT_OUTCOME, - createRecord, getRecord, getExpandedRecord - } = require("@superalgos/mqservice") + MESSAGE_ENTITY, MESSAGE_TYPE, ORDER_CREATOR, ORDER_TYPE, + ORDER_OWNER, ORDER_DIRECTION, ORDER_STATUS, ORDER_EXIT_OUTCOME, + createMessage, getMessage, getExpandedMessage + } = orderMessage.newOrderMessage() + const FULL_LOG = true; const LOG_FILE_CONTENT = false; @@ -754,6 +757,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let messageType; let message; let record; + let orderRecord; messageId++; @@ -767,13 +771,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { messageType = MESSAGE_TYPE.OrderUpdate; } - record = createRecord( + orderRecord = createMessage( messageId, MESSAGE_ENTITY.SimulationEngine, MESSAGE_ENTITY.SimulationExecutor, messageType, (new Date()).valueOf(), - orderId, + orderId.toString(), ORDER_CREATOR.SimulationEngine, (new Date()).valueOf(), ORDER_OWNER.User, @@ -785,20 +789,20 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { stopLoss, buyOrder, ORDER_DIRECTION.Sell, - "All", + -1, ORDER_STATUS.Signaled, 0, "") } else { - record = createRecord( + orderRecord = createMessage( messageId, MESSAGE_ENTITY.SimulationEngine, MESSAGE_ENTITY.SimulationExecutor, MESSAGE_TYPE.HeartBeat, (new Date()).valueOf(), - 0, + "", "", 0, "", @@ -810,7 +814,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { 0, 0, "", - "", + 0, "", 0, "") @@ -842,7 +846,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { buyOrder: buyOrder, stopLossPhase: stopLossPhase, buyOrderPhase: buyOrderPhase, - recordToSimulationExecutor: record + orderRecord: orderRecord } recordsArray.push(record); diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 4ce9c3304..b155229ca 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -160,7 +160,7 @@ record.buyOrder + "," + record.stopLossPhase + "," + record.buyOrderPhase + "," + - JSON.stringify(record.recordToSimulationExecutor) + "]"; + JSON.stringify(record.orderRecord) + "]"; if (separator === "") { separator = ","; } diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index b8760d0fc..c9090cc63 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -158,7 +158,7 @@ record.buyOrder + "," + record.stopLossPhase + "," + record.buyOrderPhase + "," + - JSON.stringify(record.recordToSimulationExecutor) + "]"; + JSON.stringify(record.orderRecord) + "]"; if (separator === "") { separator = ","; } From 2feae2c8539a1e681af7c03eaf00591c0645ea70 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 20 Apr 2019 12:00:29 +0200 Subject: [PATCH 069/244] Only Calculates and show some time periods --- this.bot.config.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/this.bot.config.json b/this.bot.config.json index 6290a1b0b..9b033db43 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -154,6 +154,7 @@ "comaWaitTime": 86400000, "framework": { "name": "Multi-Period-Daily", + "validPeriods": [ "15-min", "10-min", "05-min"], "startDate": { "fixedDate": "2018-07-01" }, @@ -280,7 +281,7 @@ { "codeName": "Multi-Period-Daily", "type": "Daily Files", - "validPeriods": [ "45-min", "40-min", "30-min", "20-min", "15-min", "10-min", "05-min", "04-min", "03-min", "02-min", "01-min" ], + "validPeriods": ["15-min", "10-min", "05-min"], "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Trading-Simulation/Multi-Period-Daily/@Period/@Year/@Month/@Day", "fileName": "@AssetA_@AssetB.json", "dataRange": { @@ -319,7 +320,7 @@ { "codeName": "Multi-Period-Daily", "type": "Daily Files", - "validPeriods": [ "45-min", "40-min", "30-min", "20-min", "15-min", "10-min", "05-min", "04-min", "03-min", "02-min", "01-min" ], + "validPeriods": ["15-min", "10-min", "05-min"], "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Conditions/Multi-Period-Daily/@Period/@Year/@Month/@Day", "fileName": "@AssetA_@AssetB.json", "dataRange": { From e53ed7845ac85ac81cd73251f052704d90ef169c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 23 Apr 2019 21:44:36 +0200 Subject: [PATCH 070/244] Bug on ROI calculation --- Commons.js | 57 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/Commons.js b/Commons.js index f797e9bed..779995fe5 100644 --- a/Commons.js +++ b/Commons.js @@ -154,13 +154,17 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { yesterday.lastProfit = 0; yesterday.Roundtrips = 0; - yesterday.Fails = 0; - yesterday.Hits = 0; + yesterday.fails = 0; + yesterday.hits = 0; yesterday.Periods = 0; yesterday.orderId = 0; yesterday.messageId = 0; + yesterday.hitRatio = 0; + yesterday.ROI = 0; + yesterday.anualizedRateOfReturn = 0; + if (interExecutionMemory.roundtrips === undefined) { /* Initialize the data structure we will use inter execution. */ @@ -177,6 +181,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { interExecutionMemory.orderId = 0; interExecutionMemory.messageId = 0; + interExecutionMemory.hitRatio = 0; + interExecutionMemory.ROI = 0; + interExecutionMemory.anualizedRateOfReturn = 0; + } else { /* We get the initial values from the day previous to the candles we receive at the current execution */ @@ -200,6 +208,15 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { orderId = interExecutionMemory.orderId; messageId = interExecutionMemory.messageId; + + hitRatio = interExecutionMemory.hitRatio; + ROI = interExecutionMemory.ROI; + anualizedRateOfReturn = interExecutionMemory.anualizedRateOfReturn; + + yesterday.hitRatio = hitRatio; + yesterday.ROI = ROI; + yesterday.anualizedRateOfReturn = anualizedRateOfReturn; + } simulationLogic.strategies = await getStrategy(); @@ -213,9 +230,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let candle = candles[i]; let percentageBandwidth = percentageBandwidthMap.get(candle.begin); let bollingerBand = bollingerBandsMap.get(candle.begin); - let LRC = LRCMap.get(candle.begin); + //let LRC = LRCMap.get(candle.begin); - if (LRC === undefined) { continue; } + //if (LRC === undefined) { continue; } if (percentageBandwidth === undefined) { continue; } // percentageBandwidth might start after the first few candles. if (candle.begin < initialDate.valueOf()) { continue; } @@ -233,7 +250,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let lastObjects = { candle: clone(candle), - LRC: clone(LRC), + //LRC: clone(LRC), bollingerBand: clone(bollingerBand), percentageBandwidth: clone(percentageBandwidth), channel: clone(channel), @@ -250,7 +267,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } lastObjects.candle.previous = undefined; - lastObjects.LRC.previous = undefined; + //lastObjects.LRC.previous = undefined; lastObjects.bollingerBand.previous = undefined; lastObjects.percentageBandwidth.previous = undefined; lastObjects.channel.previous = undefined; @@ -704,9 +721,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { lastProfitPercent = lastProfit / previousBalanceAssetA * 100; if (isNaN(lastProfitPercent)) { lastProfitPercent = 0; } - profit = initialBalanceA - balanceAssetA; + profit = balanceAssetA - initialBalanceA; + - ROI = (initialBalanceA + profit) / initialBalanceA - 1; //if (isNaN(ROI)) { ROI = 0; } if (lastProfit > 0) { @@ -714,7 +731,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (currentDay !== undefined) { if (sellInstant < currentDay.valueOf()) { - yesterday.Hits++; + yesterday.hits++; } } @@ -723,14 +740,24 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (currentDay !== undefined) { if (sellInstant < currentDay.valueOf()) { - yesterday.Fails++; + yesterday.fails++; } } } - hitRatio = hits / roundtrips; + ROI = (initialBalanceA + profit) / initialBalanceA - 1; + hitRatio = hits / roundtrips; anualizedRateOfReturn = ROI / days * 365; + if (currentDay !== undefined) { + if (sellInstant < currentDay.valueOf()) { + yesterday.ROI = ROI; + yesterday.hitRatio = hitRatio; + yesterday.anualizedRateOfReturn = anualizedRateOfReturn; + } + } + + addRecord(); strategyNumber = 0; @@ -884,12 +911,16 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { interExecutionMemory.lastProfit = yesterday.lastProfit; interExecutionMemory.roundtrips = interExecutionMemory.roundtrips + yesterday.Roundtrips; - interExecutionMemory.fails = interExecutionMemory.fails + yesterday.Fails; - interExecutionMemory.hits = interExecutionMemory.hits + yesterday.Hits; + interExecutionMemory.fails = interExecutionMemory.fails + yesterday.fails; + interExecutionMemory.hits = interExecutionMemory.hits + yesterday.hits; interExecutionMemory.periods = interExecutionMemory.periods + yesterday.Periods; interExecutionMemory.messageId = interExecutionMemory.messageId + yesterday.messageId; interExecutionMemory.orderId = interExecutionMemory.orderId + yesterday.orderId; + + interExecutionMemory.hitRatio = yesterday.hitRatio; + interExecutionMemory.ROI = yesterday.ROI; + interExecutionMemory.anualizedRateOfReturn = yesterday.anualizedRateOfReturn; } } From 9592176ce2b7aec07a2898bf5b88d5232d2f91a9 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 29 Apr 2019 08:52:15 +0200 Subject: [PATCH 071/244] Current Strategy and Trade files generated --- Commons.js | 96 +++++++++++++++++-- Multi-Period-Daily/User.Bot.js | 162 +++++++++++++++++++++++++++++++- Multi-Period-Market/User.Bot.js | 145 +++++++++++++++++++++++++++- this.bot.config.json | 84 ++++++++++++++++- 4 files changed, 473 insertions(+), 14 deletions(-) diff --git a/Commons.js b/Commons.js index 779995fe5..191e0905b 100644 --- a/Commons.js +++ b/Commons.js @@ -56,6 +56,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { async function runSimulation( recordsArray, conditionsArray, + strategiesArray, + tradesArray, lastObjectsArray, simulationLogic, timePeriod, @@ -114,6 +116,20 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let rate = 0; let newStopLoss; + let currentStrategy = { + begin: 0, + end: 0, + status: 0, + number: 0 + } + + let currentTrade = { + begin: 0, + end: 0, + status: 0, + profit: 0 + } + /* The following counters need to survive multiple executions of the similator and keep themselves reliable. This is challenging when the simulation is executed using Daily Files, since each execution means a new @@ -397,7 +413,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - /* While we are outside all strategies, we evaluate whether it is time to enter one or not. */ + + /* Strategy Enter Condition */ if (strategyNumber === 0 && balanceAssetA > minimunBalanceA) { @@ -440,7 +457,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategyPhase = 1; strategyNumber = j + 1; - + currentStrategy.begin = candle.begin; + currentStrategy.beginRate = candle.min; + currentStrategy.endRate = candle.min; // In case the strategy does not get exited return; } } @@ -475,6 +494,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (passed) { + currentStrategy.number = strategyNumber - 1 + currentStrategy.end = candle.end; + currentStrategy.endRate = candle.min; + currentStrategy.status = 1; strategyPhase = 0; strategyNumber = 0; @@ -484,6 +507,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } + /* Checking if Stop or Take Profit were hit */ + if (strategyPhase === 3) { /* Checking what happened since the last execution. We need to know if the Stop Loss @@ -506,6 +531,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { rate = stopLoss; type = '"Buy@StopLoss"'; strategyPhase = 4; + currentTrade.end = candle.end; + currentTrade.status = 1; + + currentStrategy.number = strategyNumber - 1 + currentStrategy.end = candle.end; + currentStrategy.endRate = candle.min; + currentStrategy.status = 1; } /* Buy Order condition: Here we verify if the Buy Order was filled or not. */ @@ -526,10 +558,17 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { rate = buyOrder; type = '"Buy@BuyOrder"'; strategyPhase = 4; + currentTrade.end = candle.end; + currentTrade.status = 1; + + currentStrategy.number = strategyNumber - 1 + currentStrategy.end = candle.end; + currentStrategy.endRate = candle.min; + currentStrategy.status = 1; } } - /* Strategy Sell Condition */ + /* Trade Enter Condition */ if (strategyPhase === 1) { @@ -561,7 +600,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategyPhase = 2; stopLossPhase = 1; buyOrderPhase = 1; - + currentTrade.begin = candle.begin; return; } } @@ -619,7 +658,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - /* Buy Order Management */ + /* Take Profit Management */ if (strategyPhase === 3) { @@ -664,7 +703,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - /* Check if we need to sell. */ + /* Entering into a Trade */ if (strategyPhase === 2) { @@ -698,7 +737,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { continue; } - /* Check if we need to buy. */ + /* Exiting a Trade */ if (strategyPhase === 4) { @@ -768,7 +807,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategyPhase = 0; stopLossPhase = 0; buyOrderPhase = 0; - continue; } @@ -821,7 +859,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { 0, "") - } else { + } + else { orderRecord = createMessage( messageId, @@ -882,6 +921,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { type = '""'; + /* Prepare the information for the Conditions File */ + conditionsArrayRecord.push(strategyNumber); conditionsArrayRecord.push(strategyPhase); conditionsArrayRecord.push(stopLossPhase); @@ -890,6 +931,43 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { conditionsArray.push(conditionsArrayRecord); + /* Prepare the information for the Strategies File*/ + + if ( + (currentStrategy.begin !== 0 && currentStrategy.end !== 0) || + (currentStrategy.begin !== 0 && i === candles.length - 1) + ) { + + strategiesArray.push(currentStrategy); + + currentStrategy = { + begin: 0, + end: 0, + status: 0, + number: 0, + beginRate: 0, + endRate: 0 + } + } + + /* Prepare the information for the Trades File */ + + if ( + (currentTrade.begin !== 0 && currentTrade.end !== 0) || + (currentTrade.begin !== 0 && i === candles.length - 1) + ) { + + currentTrade.profit = lastProfit; + + tradesArray.push(currentTrade); + + currentTrade = { + begin: 0, + end: 0, + status: 0, + profit: 0 + } + } } } diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index b155229ca..29a9c2552 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -7,6 +7,8 @@ const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; + const STRATEGIES_FOLDER_NAME = "Simulation-Strategies"; + const TRADES_FOLDER_NAME = "Simulation-Trades"; const commons = COMMONS.newCommons(bot, logger, UTILITIES); @@ -63,6 +65,8 @@ let recordsArray = []; let conditionsArray = []; + let strategiesArray = []; + let tradesArray = []; let simulationLogic = {}; let lastObjectsArray = []; @@ -106,6 +110,8 @@ commons.runSimulation( recordsArray, conditionsArray, + strategiesArray, + tradesArray, lastObjectsArray, simulationLogic, timePeriod, @@ -226,6 +232,10 @@ let record = conditionsArray[i]; + /* Will only add to the file the records of the current day */ + + if (record.begin < currentDay.valueOf()) { continue; } + let conditions = ""; let conditionsSeparator = ""; @@ -277,7 +287,7 @@ } - callBackFunction(global.DEFAULT_OK_RESPONSE); + writeStrategiesFile(); } catch (err) { @@ -292,6 +302,156 @@ } } + function writeStrategiesFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < strategiesArray.length; i++) { + let record = strategiesArray[i]; + + /* Will only add to the file the records of the current day */ + + if (record.begin < currentDay.valueOf()) { continue; } + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.status + "," + + record.number + "," + + record.beginRate + "," + + record.endRate + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + + thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + writeTradesFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeTradesFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < tradesArray.length; i++) { + + let record = tradesArray[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.status + "," + + record.profit + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + + thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + callBackFunction(global.DEFAULT_OK_RESPONSE); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.message); diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index c9090cc63..acc354cdd 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -7,6 +7,8 @@ const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; + const STRATEGIES_FOLDER_NAME = "Simulation-Strategies"; + const TRADES_FOLDER_NAME = "Simulation-Trades"; const commons = COMMONS.newCommons(bot, logger, UTILITIES); @@ -63,6 +65,8 @@ let recordsArray = []; let conditionsArray = []; + let strategiesArray = []; + let tradesArray = []; let lastObjectsArray = []; let simulationLogic = {}; @@ -108,6 +112,8 @@ commons.runSimulation( recordsArray, conditionsArray, + strategiesArray, + tradesArray, lastObjectsArray, simulationLogic, timePeriod, @@ -268,7 +274,7 @@ } - callBackFunction(global.DEFAULT_OK_RESPONSE); + writeStrategiesFile(); } catch (err) { @@ -283,6 +289,143 @@ } } + function writeStrategiesFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < strategiesArray.length; i++) { + let record = strategiesArray[i]; + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.status + "," + + record.number + "," + + record.beginRate + "," + + record.endRate + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; + + thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + writeTradesFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeTradesFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < tradesArray.length; i++) { + + let record = tradesArray[i]; + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.status + "," + + record.profit + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; + + thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + callBackFunction(global.DEFAULT_OK_RESPONSE); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.message); diff --git a/this.bot.config.json b/this.bot.config.json index 9b033db43..1bf3db7cc 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -281,7 +281,7 @@ { "codeName": "Multi-Period-Daily", "type": "Daily Files", - "validPeriods": ["15-min", "10-min", "05-min"], + "validPeriods": [ "15-min", "10-min", "05-min" ], "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Trading-Simulation/Multi-Period-Daily/@Period/@Year/@Month/@Day", "fileName": "@AssetA_@AssetB.json", "dataRange": { @@ -320,11 +320,11 @@ { "codeName": "Multi-Period-Daily", "type": "Daily Files", - "validPeriods": ["15-min", "10-min", "05-min"], + "validPeriods": [ "15-min", "10-min", "05-min" ], "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Conditions/Multi-Period-Daily/@Period/@Year/@Month/@Day", "fileName": "@AssetA_@AssetB.json", "dataRange": { - "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Trading-Simulation/Multi-Period-Daily", + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Conditions/Multi-Period-Daily", "fileName": "Data.Range.@AssetA_@AssetB.json" } } @@ -342,6 +342,84 @@ "codeName": "PlottersTradingSimulation", "moduleName": "Conditions" } + }, + { + "codeName": "Simulation-Strategies", + "displayName": "Simulation Strategies", + "description": "Simulation Strategies", + "storageAccount": "aajason", + "dataSets": [ + { + "codeName": "Multi-Period-Market", + "type": "Market Files", + "validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs" ], + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Strategies/Multi-Period-Market/@Period", + "fileName": "@AssetA_@AssetB.json" + }, + { + "codeName": "Multi-Period-Daily", + "type": "Daily Files", + "validPeriods": [ "15-min", "10-min", "05-min" ], + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Strategies/Multi-Period-Daily/@Period/@Year/@Month/@Day", + "fileName": "@AssetA_@AssetB.json", + "dataRange": { + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Strategies/Multi-Period-Daily", + "fileName": "Data.Range.@AssetA_@AssetB.json" + } + } + ], + "exchangeList": [ + { + "name": "Poloniex" + }, + { + "name": "Coss" + } + ], + "plotter": { + "devTeam": "AAMasters", + "codeName": "PlottersTradingSimulation", + "moduleName": "Strategies" + } + }, + { + "codeName": "Simulation-Trades", + "displayName": "Simulation Trades", + "description": "Simulation Trades", + "storageAccount": "aajason", + "dataSets": [ + { + "codeName": "Multi-Period-Market", + "type": "Market Files", + "validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs" ], + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Trades/Multi-Period-Market/@Period", + "fileName": "@AssetA_@AssetB.json" + }, + { + "codeName": "Multi-Period-Daily", + "type": "Daily Files", + "validPeriods": [ "15-min", "10-min", "05-min" ], + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Trades/Multi-Period-Daily/@Period/@Year/@Month/@Day", + "fileName": "@AssetA_@AssetB.json", + "dataRange": { + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Trades/Multi-Period-Daily", + "fileName": "Data.Range.@AssetA_@AssetB.json" + } + } + ], + "exchangeList": [ + { + "name": "Poloniex" + }, + { + "name": "Coss" + } + ], + "plotter": { + "devTeam": "AAMasters", + "codeName": "PlottersTradingSimulation", + "moduleName": "Trades" + } } ] } From 2b280530b0022cda3a4a38a894262b263b170dc2 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 29 Apr 2019 10:49:24 +0200 Subject: [PATCH 072/244] Bugs corrected at Daily, when an object is spanning more than one day --- Commons.js | 33 ++++++++++++++------------- Multi-Period-Daily/User.Bot.js | 40 +++++++++++++++++---------------- Multi-Period-Market/User.Bot.js | 30 ++++++++++++------------- 3 files changed, 54 insertions(+), 49 deletions(-) diff --git a/Commons.js b/Commons.js index 191e0905b..761a18652 100644 --- a/Commons.js +++ b/Commons.js @@ -116,6 +116,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let rate = 0; let newStopLoss; + /* In some cases we need to know if we are positioned at the last candle of the calendar day, for that we need thse variables. */ + + let lastInstantOfTheDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1; + let lastCandle = candles[candles.length - 1]; + + /* These 2 objects will allow us to create separate files for each one of them. */ + let currentStrategy = { begin: 0, end: 0, @@ -157,7 +164,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let hits = 0; let periods = 0; - /* Message to Su=Simulation Executor */ + /* Message to the Simulation Executor */ let orderId = 0; let messageId = 0; @@ -935,7 +942,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if ( (currentStrategy.begin !== 0 && currentStrategy.end !== 0) || - (currentStrategy.begin !== 0 && i === candles.length - 1) + (currentStrategy.begin !== 0 && i === candles.length - 1 && lastCandle.end !== lastInstantOfTheDay) ) { strategiesArray.push(currentStrategy); @@ -954,7 +961,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if ( (currentTrade.begin !== 0 && currentTrade.end !== 0) || - (currentTrade.begin !== 0 && i === candles.length - 1) + (currentTrade.begin !== 0 && i === candles.length - 1 && lastCandle.end !== lastInstantOfTheDay) ) { currentTrade.profit = lastProfit; @@ -978,11 +985,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (currentDay !== undefined) { - let lastInstantOdDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1; - - lastCandle = candles[candles.length - 1]; - - if (lastCandle.end === lastInstantOdDay) { + if (lastCandle.end === lastInstantOfTheDay) { interExecutionMemory.balanceAssetA = yesterday.balanceAssetA; interExecutionMemory.balanceAssetB = yesterday.balanceAssetB; @@ -1025,7 +1028,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] runSimulation -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] runSimulation -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -1072,7 +1075,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] buildLRC -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] buildLRC -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -1111,7 +1114,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] buildPercentageBandwidthMap -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] buildPercentageBandwidthMap -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -1150,7 +1153,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] buildBollingerBandsMap -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] buildBollingerBandsMap -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -1184,7 +1187,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] buildBollingerChannelsArray -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] buildBollingerChannelsArray -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -1219,7 +1222,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] buildBollingerSubChannelsArray -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] buildBollingerSubChannelsArray -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -1265,7 +1268,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] buildCandles -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] buildCandles -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 29a9c2552..e700da9de 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -44,12 +44,12 @@ callBackFunction(global.DEFAULT_OK_RESPONSE); } else { - logger.write(MODULE_NAME, "[ERROR] initializeStorage -> onStorageInizialized -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] initializeStorage -> onStorageInizialized -> err = " + err.stack); callBackFunction(err); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -193,7 +193,7 @@ if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.stack); logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> filePath = " + filePath); logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); @@ -206,13 +206,13 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -278,7 +278,7 @@ if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.stack); logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> filePath = " + filePath); logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); @@ -291,13 +291,13 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -316,9 +316,10 @@ for (let i = 0; i < strategiesArray.length; i++) { let record = strategiesArray[i]; - /* Will only add to the file the records of the current day */ + /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends + at the current date. */ - if (record.begin < currentDay.valueOf()) { continue; } + if (record.end < currentDay.valueOf()) { continue; } fileContent = fileContent + separator + '[' + record.begin + "," + @@ -353,7 +354,7 @@ if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.stack); logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> filePath = " + filePath); logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); @@ -366,13 +367,13 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -392,9 +393,10 @@ let record = tradesArray[i]; - /* Will only add to the file the records of the current day */ + /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends + at the current date. */ - if (record.begin < currentDay.valueOf()) { continue; } + if (record.end < currentDay.valueOf()) { continue; } fileContent = fileContent + separator + '[' + record.begin + "," + @@ -427,7 +429,7 @@ if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.stack); logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> filePath = " + filePath); logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); @@ -440,13 +442,13 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -454,7 +456,7 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index acc354cdd..629cb1067 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -44,12 +44,12 @@ callBackFunction(global.DEFAULT_OK_RESPONSE); } else { - logger.write(MODULE_NAME, "[ERROR] initializeStorage -> onStorageInizialized -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] initializeStorage -> onStorageInizialized -> err = " + err.stack); callBackFunction(err); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -190,7 +190,7 @@ if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.stack); logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> filePath = " + filePath); logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); @@ -203,13 +203,13 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -265,7 +265,7 @@ if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.stack); logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> filePath = " + filePath); logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); @@ -278,13 +278,13 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -334,7 +334,7 @@ if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.stack); logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> filePath = " + filePath); logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); @@ -347,13 +347,13 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -402,7 +402,7 @@ if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.stack); logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> filePath = " + filePath); logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); @@ -415,20 +415,20 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } From 053664d2193be027af4c17767b0ec22200c56622 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 29 Apr 2019 16:31:17 +0200 Subject: [PATCH 073/244] All working, with individual files for Trades and Strategies --- Commons.js | 20 ++++++++++++++++---- Multi-Period-Daily/User.Bot.js | 6 +++++- Multi-Period-Market/User.Bot.js | 6 +++++- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/Commons.js b/Commons.js index 761a18652..635d32736 100644 --- a/Commons.js +++ b/Commons.js @@ -134,7 +134,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { begin: 0, end: 0, status: 0, - profit: 0 + profit: 0, + exitType: 0, + beginRate: 0, + endRate: 0 } /* @@ -540,6 +543,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategyPhase = 4; currentTrade.end = candle.end; currentTrade.status = 1; + currentTrade.exitType = 1; + currentTrade.endRate = stopLoss; currentStrategy.number = strategyNumber - 1 currentStrategy.end = candle.end; @@ -566,7 +571,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { type = '"Buy@BuyOrder"'; strategyPhase = 4; currentTrade.end = candle.end; - currentTrade.status = 1; + currentTrade.status = 1; + currentTrade.exitType = 2; + currentTrade.endRate = buyOrder; currentStrategy.number = strategyNumber - 1 currentStrategy.end = candle.end; @@ -608,6 +615,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { stopLossPhase = 1; buyOrderPhase = 1; currentTrade.begin = candle.begin; + currentTrade.beginRate = candle.close; return; } } @@ -768,7 +776,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (isNaN(lastProfitPercent)) { lastProfitPercent = 0; } profit = balanceAssetA - initialBalanceA; - + currentTrade.lastProfitPercent = lastProfitPercent; + currentTrade.stopRate = stopLoss; //if (isNaN(ROI)) { ROI = 0; } @@ -972,7 +981,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { begin: 0, end: 0, status: 0, - profit: 0 + lastProfitPercent: 0, + exitType: 0, + beginRate: 0, + endRate: 0 } } } diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index e700da9de..952e51922 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -402,7 +402,11 @@ record.begin + "," + record.end + "," + record.status + "," + - record.profit + "]"; + record.lastProfitPercent + "," + + record.beginRate + "," + + record.endRate + "," + + record.exitType + "," + + record.stopRate + "]"; if (separator === "") { separator = ","; } diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 629cb1067..1faeca81d 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -377,7 +377,11 @@ record.begin + "," + record.end + "," + record.status + "," + - record.profit + "]"; + record.lastProfitPercent + "," + + record.beginRate + "," + + record.endRate + "," + + record.exitType + "," + + record.stopRate + "]"; if (separator === "") { separator = ","; } From e6505706dcc6d8fd82b0aa1c4632b4843e5bdaf4 Mon Sep 17 00:00:00 2001 From: Matias Date: Fri, 3 May 2019 19:06:20 -0300 Subject: [PATCH 074/244] Fixing current day undefined issue --- Multi-Period-Market/User.Bot.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 1faeca81d..c0a887fe2 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -71,7 +71,7 @@ let simulationLogic = {}; let interExecutionMemory = {}; - let currentDay; + let currentDay = bot.processDatetime; commons.initializeData(); @@ -165,7 +165,7 @@ record.stopLossPhase + "," + record.buyOrderPhase + "," + JSON.stringify(record.orderRecord) + "]"; - + if (separator === "") { separator = ","; } fileRecordCounter++; From 29a448702a65dd57eb85559ad9b4defac5e56d49 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 16 May 2019 19:16:09 +0200 Subject: [PATCH 075/244] Fixing latest bug --- Commons.js | 49 ++++++++++++++++++++++----------- Multi-Period-Daily/User.Bot.js | 3 +- Multi-Period-Market/User.Bot.js | 3 +- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/Commons.js b/Commons.js index 635d32736..5a93ad1c2 100644 --- a/Commons.js +++ b/Commons.js @@ -102,9 +102,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Building records */ let record; - let profit = 0; - let lastProfitPercent = 0; let sellRate = 0; + let sellAmount = 0; let sellInstant; let previousBalanceAssetA = 0; @@ -160,7 +159,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let balanceAssetA = initialBalanceA; let balanceAssetB = 0; + let lastProfit = 0; + let profit = 0; + let lastProfitPercent = 0; let roundtrips = 0; let fails = 0; @@ -178,6 +180,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { yesterday.balanceAssetB = balanceAssetB; yesterday.lastProfit = 0; + yesterday.profit = 0; + yesterday.lastProfitPercent = 0; yesterday.Roundtrips = 0; yesterday.fails = 0; @@ -197,7 +201,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { interExecutionMemory.balanceAssetA = balanceAssetA; interExecutionMemory.balanceAssetB = balanceAssetB; + interExecutionMemory.lastProfit = lastProfit; + interExecutionMemory.profit = profit; + interExecutionMemory.lastProfitPercent = lastProfitPercent; interExecutionMemory.roundtrips = 0; interExecutionMemory.fails = 0; @@ -215,7 +222,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* We get the initial values from the day previous to the candles we receive at the current execution */ - if (currentDay.valueOf() > startDate.valueOf() + ONE_DAY_IN_MILISECONDS) { // Only after the first day we start grabbing the balance from this memory. + if (currentDay.valueOf() >= startDate.valueOf() + ONE_DAY_IN_MILISECONDS) { // Only after the first day we start grabbing the balance from this memory. balanceAssetA = interExecutionMemory.balanceAssetA; balanceAssetB = interExecutionMemory.balanceAssetB; @@ -226,6 +233,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } lastProfit = interExecutionMemory.lastProfit; + profit = interExecutionMemory.profit; + lastProfitPercent = interExecutionMemory.lastProfitPercent; roundtrips = interExecutionMemory.roundtrips; fails = interExecutionMemory.fails; @@ -722,11 +731,19 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (strategyPhase === 2) { + rate = candle.close; + sellRate = rate; + sellAmount = balanceAssetA; + + stopLoss = sellRate + sellRate * stopLossPercentage / 100; + + stopLossDecay = 0; + previousBalanceAssetA = balanceAssetA; lastProfit = 0; lastProfitPercent = 0; - balanceAssetB = balanceAssetA * candle.close; + balanceAssetB = balanceAssetA * rate; balanceAssetA = 0; sellInstant = candle.end; @@ -735,17 +752,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (sellInstant < currentDay.valueOf()) { yesterday.balanceAssetA = balanceAssetA; yesterday.balanceAssetB = balanceAssetB; + yesterday.lastProfit = lastProfit; + yesterday.lastProfitPercent = lastProfitPercent; } } - rate = candle.close; - sellRate = rate; - - stopLoss = sellRate + sellRate * stopLossPercentage / 100; - - stopLossDecay = 0; - addRecord(); strategyPhase = 3; @@ -765,17 +777,18 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } lastProfit = balanceAssetA - previousBalanceAssetA; + lastProfitPercent = lastProfit / previousBalanceAssetA * 100; + if (isNaN(lastProfitPercent)) { lastProfitPercent = 0; } + profit = balanceAssetA - initialBalanceA; if (currentDay !== undefined) { if (sellInstant < currentDay.valueOf()) { yesterday.lastProfit = lastProfit; + yesterday.profit = profit; + yesterday.lastProfitPercent = lastProfitPercent; } } - lastProfitPercent = lastProfit / previousBalanceAssetA * 100; - if (isNaN(lastProfitPercent)) { lastProfitPercent = 0; } - - profit = balanceAssetA - initialBalanceA; currentTrade.lastProfitPercent = lastProfitPercent; currentTrade.stopRate = stopLoss; @@ -818,6 +831,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategyNumber = 0; stopLoss = 0; sellRate = 0; + sellAmount = 0; sellInstant = undefined; buyOrder = 0; strategyPhase = 0; @@ -928,7 +942,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { buyOrder: buyOrder, stopLossPhase: stopLossPhase, buyOrderPhase: buyOrderPhase, - orderRecord: orderRecord + orderRecord: orderRecord, + sellAmount: sellAmount } recordsArray.push(record); @@ -1002,6 +1017,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { interExecutionMemory.balanceAssetA = yesterday.balanceAssetA; interExecutionMemory.balanceAssetB = yesterday.balanceAssetB; interExecutionMemory.lastProfit = yesterday.lastProfit; + interExecutionMemory.profit = yesterday.profit; + interExecutionMemory.lastProfitPercent = yesterday.lastProfitPercent; interExecutionMemory.roundtrips = interExecutionMemory.roundtrips + yesterday.Roundtrips; interExecutionMemory.fails = interExecutionMemory.fails + yesterday.fails; diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 952e51922..eb96ce694 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -166,7 +166,8 @@ record.buyOrder + "," + record.stopLossPhase + "," + record.buyOrderPhase + "," + - JSON.stringify(record.orderRecord) + "]"; + JSON.stringify(record.orderRecord) + "," + + record.sellAmount + "]"; if (separator === "") { separator = ","; } diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 1faeca81d..b1f6abba2 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -164,7 +164,8 @@ record.buyOrder + "," + record.stopLossPhase + "," + record.buyOrderPhase + "," + - JSON.stringify(record.orderRecord) + "]"; + JSON.stringify(record.orderRecord) + "," + + record.sellAmount + "]"; if (separator === "") { separator = ","; } From 976a849f54d6fdb5d16b64a72eaf5ca2f8dc6740 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 19 May 2019 11:50:03 +0200 Subject: [PATCH 076/244] BUG FIXED: Initial STOP and TAKE PROFIT not correctly set --- Commons.js | 131 ++++++++++++++++++++++--------------------- this.bot.config.json | 12 ++-- 2 files changed, 76 insertions(+), 67 deletions(-) diff --git a/Commons.js b/Commons.js index 5a93ad1c2..82a881a0f 100644 --- a/Commons.js +++ b/Commons.js @@ -84,7 +84,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Stop Loss Management */ - let stopLossPercentage = 1.5; + let stopLossPercentage = 50; let previousStopLoss = 0; let stopLoss = 0; let stopLossDecay = 0; @@ -637,47 +637,48 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { checkStopLoss(); - function checkStopLoss() { + } - let strategy = simulationLogic.strategies[strategyNumber - 1]; + function checkStopLoss() { - let phase = strategy.stopLoss.phases[stopLossPhase - 1]; + let strategy = simulationLogic.strategies[strategyNumber - 1]; - try { - eval(phase.code); // Here is where we apply the formula given for the stop loss for this phase. - } catch (err) { - /* - If the code produces an exception, we are covered. - */ + let phase = strategy.stopLoss.phases[stopLossPhase - 1]; + + try { + eval(phase.code); // Here is where we apply the formula given for the stop loss for this phase. + } catch (err) { + /* + If the code produces an exception, we are covered. + */ + } + + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; + } + + for (let k = 0; k < phase.situations.length; k++) { + + let situation = phase.situations[k]; + let passed = true; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name + + let value = conditions.get(key).value; + + if (value === false) { passed = false; } } - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } + if (passed) { - for (let k = 0; k < phase.situations.length; k++) { + stopLossPhase++; - let situation = phase.situations[k]; - let passed = true; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name - - let value = conditions.get(key).value; - - if (value === false) { passed = false; } - } - - if (passed) { - - stopLossPhase++; - - return; - } + return; } } } @@ -688,41 +689,42 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { checkBuyOrder(); - function checkBuyOrder() { + } - let strategy = simulationLogic.strategies[strategyNumber - 1]; + function checkBuyOrder() { - let phase = strategy.buyOrder.phases[buyOrderPhase - 1]; + let strategy = simulationLogic.strategies[strategyNumber - 1]; - try { - eval(phase.code); // Here is where we apply the formula given for the buy order at this phase. - } catch (err) { - /* - If the code produces an exception, we are covered. - */ + let phase = strategy.buyOrder.phases[buyOrderPhase - 1]; + + try { + eval(phase.code); // Here is where we apply the formula given for the buy order at this phase. + } catch (err) { + /* + If the code produces an exception, we are covered. + */ + } + + for (let k = 0; k < phase.situations.length; k++) { + + let situation = phase.situations[k]; + let passed = true; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name + + let value = conditions.get(key).value; + + if (value === false) { passed = false; } } - for (let k = 0; k < phase.situations.length; k++) { + if (passed) { - let situation = phase.situations[k]; - let passed = true; + buyOrderPhase++; - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name - - let value = conditions.get(key).value; - - if (value === false) { passed = false; } - } - - if (passed) { - - buyOrderPhase++; - - return; - } + return; } } } @@ -739,6 +741,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { stopLossDecay = 0; + checkStopLoss(); + checkBuyOrder(); + previousBalanceAssetA = balanceAssetA; lastProfit = 0; lastProfitPercent = 0; diff --git a/this.bot.config.json b/this.bot.config.json index 1bf3db7cc..b3b82072d 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -302,7 +302,8 @@ "devTeam": "AAMasters", "codeName": "PlottersTradingSimulation", "moduleName": "TradingSimulation" - } + }, + "relatedToTradingEngine": true }, { "codeName": "Simulation-Conditions", @@ -341,7 +342,8 @@ "devTeam": "AAMasters", "codeName": "PlottersTradingSimulation", "moduleName": "Conditions" - } + }, + "relatedToTradingEngine": true }, { "codeName": "Simulation-Strategies", @@ -380,7 +382,8 @@ "devTeam": "AAMasters", "codeName": "PlottersTradingSimulation", "moduleName": "Strategies" - } + }, + "relatedToTradingEngine": true }, { "codeName": "Simulation-Trades", @@ -419,7 +422,8 @@ "devTeam": "AAMasters", "codeName": "PlottersTradingSimulation", "moduleName": "Trades" - } + }, + "relatedToTradingEngine": true } ] } From f67fdc34163ff8a0a074e4d0d8b80e570abae555 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 19 May 2019 13:04:39 +0200 Subject: [PATCH 077/244] FUSE to avoid infinity numbers due to division by 0 --- Commons.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index 82a881a0f..45ebb7287 100644 --- a/Commons.js +++ b/Commons.js @@ -84,6 +84,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* 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. let stopLossPercentage = 50; let previousStopLoss = 0; let stopLoss = 0; @@ -93,6 +94,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Buy Order Management */ + const MIN_BUY_ORDER_VALUE = 1 // We can not let the buy order be zero to avoid division by 0 error or infinity numbers as a result. let buyOrderPercentage = 1; let previousBuyOrder = 0; let buyOrder = 0; @@ -659,6 +661,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { stopLoss = previousStopLoss; } + if (stopLoss < MIN_STOP_LOSS_VALUE) { + stopLoss = MIN_STOP_LOSS_VALUE + } + for (let k = 0; k < phase.situations.length; k++) { let situation = phase.situations[k]; @@ -705,6 +711,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { */ } + if (buyOrder < MIN_BUY_ORDER_VALUE) { + buyOrder = MIN_BUY_ORDER_VALUE + } + for (let k = 0; k < phase.situations.length; k++) { let situation = phase.situations[k]; @@ -1313,6 +1323,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { const accessToken = await auth.authenticate() + let fbSlug = bot.codeName + if (process.env.TEST_FB !== undefined) { + fbSlug = process.env.TEST_FB + } + const strategizerResponse = await axios({ url: process.env.GATEWAY_ENDPOINT, method: 'post', @@ -1404,7 +1419,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { `, variables: { - fbSlug: bot.codeName + fbSlug: fbSlug }, }, headers: { From 98067190846c0de5fa68170020793dfec66e9265 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 19 May 2019 14:06:42 +0200 Subject: [PATCH 078/244] Separation of stop formula from advancing phase --- Commons.js | 82 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/Commons.js b/Commons.js index 45ebb7287..3b4ac69a5 100644 --- a/Commons.js +++ b/Commons.js @@ -637,34 +637,16 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (strategyPhase === 3) { + checkStopPhases() checkStopLoss(); } - function checkStopLoss() { + function checkStopPhases() { let strategy = simulationLogic.strategies[strategyNumber - 1]; - let phase = strategy.stopLoss.phases[stopLossPhase - 1]; - try { - eval(phase.code); // Here is where we apply the formula given for the stop loss for this phase. - } catch (err) { - /* - If the code produces an exception, we are covered. - */ - } - - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } - - if (stopLoss < MIN_STOP_LOSS_VALUE) { - stopLoss = MIN_STOP_LOSS_VALUE - } - for (let k = 0; k < phase.situations.length; k++) { let situation = phase.situations[k]; @@ -689,32 +671,45 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - /* Take Profit Management */ - - if (strategyPhase === 3) { - - checkBuyOrder(); - - } - - function checkBuyOrder() { + function checkStopLoss() { let strategy = simulationLogic.strategies[strategyNumber - 1]; - - let phase = strategy.buyOrder.phases[buyOrderPhase - 1]; + let phase = strategy.stopLoss.phases[stopLossPhase - 1]; try { - eval(phase.code); // Here is where we apply the formula given for the buy order at this phase. + eval(phase.code); // Here is where we apply the formula given for the stop loss for this phase. } catch (err) { /* If the code produces an exception, we are covered. */ } - if (buyOrder < MIN_BUY_ORDER_VALUE) { - buyOrder = MIN_BUY_ORDER_VALUE + if (newStopLoss < previousStopLoss) { + stopLoss = newStopLoss; + } else { + stopLoss = previousStopLoss; } + if (stopLoss < MIN_STOP_LOSS_VALUE) { + stopLoss = MIN_STOP_LOSS_VALUE + } + + } + + /* Take Profit Management */ + + if (strategyPhase === 3) { + + checkBuyOrderPhases(); + checkBuyOrder(); + + } + + function checkBuyOrderPhases() { + + let strategy = simulationLogic.strategies[strategyNumber - 1]; + let phase = strategy.buyOrder.phases[buyOrderPhase - 1]; + for (let k = 0; k < phase.situations.length; k++) { let situation = phase.situations[k]; @@ -739,6 +734,24 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } + function checkBuyOrder() { + + let strategy = simulationLogic.strategies[strategyNumber - 1]; + let phase = strategy.buyOrder.phases[buyOrderPhase - 1]; + + try { + eval(phase.code); // Here is where we apply the formula given for the buy order at this phase. + } catch (err) { + /* + If the code produces an exception, we are covered. + */ + } + + if (buyOrder < MIN_BUY_ORDER_VALUE) { + buyOrder = MIN_BUY_ORDER_VALUE + } + } + /* Entering into a Trade */ if (strategyPhase === 2) { @@ -748,6 +761,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { sellAmount = balanceAssetA; stopLoss = sellRate + sellRate * stopLossPercentage / 100; + previousStopLoss = stopLoss; stopLossDecay = 0; From 648885d3b0bf201700d71223669e470113fb12ca Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 16:00:17 +0200 Subject: [PATCH 079/244] Reading Protocol v.0.1 --- Commons.js | 95 ++++++------------------------------------------------ 1 file changed, 9 insertions(+), 86 deletions(-) diff --git a/Commons.js b/Commons.js index 3b4ac69a5..124256778 100644 --- a/Commons.js +++ b/Commons.js @@ -256,7 +256,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } - simulationLogic.strategies = await getStrategy(); + simulationLogic.strategies = await getStrategies(); /* Main Simulation Loop: We go thourgh all the candles at this time period. */ @@ -1331,7 +1331,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - async function getStrategy() { + async function getStrategies() { try { @@ -1347,90 +1347,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { method: 'post', data: { query: ` - query($fbSlug: String!){ - - strategizer_StrategyByFb(fbSlug: $fbSlug){ - subStrategies(activeOnly: true){ - name - entryPoint{ - situations{ - name - conditions{ - name - code - } - } - } - exitPoint{ - situations{ - name - conditions{ - name - code - } - } - } - sellPoint{ - situations{ - name - conditions{ - name - code - } - } - } - buyPoint{ - situations{ - name - conditions{ - name - code - } - } - } - stopLoss{ - phases{ - name - code - situations{ - name - conditions{ - name - code - } - } - } - } - buyOrder{ - phases{ - name - code - situations{ - name - conditions{ - name - code - } - } - } - } - sellOrder{ - phases{ - name - code - situations{ - name - conditions{ - name - code - } - } - } - } + query($fbSlug: String!){ + strategizer_TradingSystemByFb(fbSlug: $fbSlug){ + id + fbSlug + data + } } - } - } - `, variables: { fbSlug: fbSlug @@ -1444,7 +1367,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (strategizerResponse.data.errors) throw new Error(strategizerResponse.data.errors[0].message) - return strategizerResponse.data.data.strategizer_StrategyByFb.subStrategies; + return strategizerResponse.data.data.strategizer_TradingSystemByFb.data.strategies; } catch (error) { throw new Error('There has been an error getting the strategy to run on the simulator. Error: ' + error) From 23c70934ab60f4bc0f327168eb24d98587d5a4e1 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 16:55:14 +0200 Subject: [PATCH 080/244] Refactoring simulationLogic --- Commons.js | 24 ++++++++++++------------ Multi-Period-Daily/User.Bot.js | 6 +++--- Multi-Period-Market/User.Bot.js | 6 +++--- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Commons.js b/Commons.js index 124256778..bd612453c 100644 --- a/Commons.js +++ b/Commons.js @@ -59,7 +59,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategiesArray, tradesArray, lastObjectsArray, - simulationLogic, + tradingSystem, timePeriod, currentDay, startDate, @@ -256,7 +256,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } - simulationLogic.strategies = await getStrategies(); + tradingSystem.strategies = await getStrategies(); /* Main Simulation Loop: We go thourgh all the candles at this time period. */ @@ -325,9 +325,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { conditionsArrayRecord.push(candle.begin); conditionsArrayRecord.push(candle.end); - for (let j = 0; j < simulationLogic.strategies.length; j++) { + for (let j = 0; j < tradingSystem.strategies.length; j++) { - let strategy = simulationLogic.strategies[j]; + let strategy = tradingSystem.strategies[j]; for (let k = 0; k < strategy.entryPoint.situations.length; k++) { @@ -455,9 +455,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkEntryPoints() { - for (let j = 0; j < simulationLogic.strategies.length; j++) { + for (let j = 0; j < tradingSystem.strategies.length; j++) { - let strategy = simulationLogic.strategies[j]; + let strategy = tradingSystem.strategies[j]; for (let k = 0; k < strategy.entryPoint.situations.length; k++) { @@ -496,7 +496,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkExitPoints() { - let strategy = simulationLogic.strategies[strategyNumber - 1]; + let strategy = tradingSystem.strategies[strategyNumber - 1]; for (let k = 0; k < strategy.exitPoint.situations.length; k++) { @@ -601,7 +601,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkSellPoints() { - let strategy = simulationLogic.strategies[strategyNumber - 1]; + let strategy = tradingSystem.strategies[strategyNumber - 1]; for (let k = 0; k < strategy.sellPoint.situations.length; k++) { @@ -644,7 +644,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkStopPhases() { - let strategy = simulationLogic.strategies[strategyNumber - 1]; + let strategy = tradingSystem.strategies[strategyNumber - 1]; let phase = strategy.stopLoss.phases[stopLossPhase - 1]; for (let k = 0; k < phase.situations.length; k++) { @@ -673,7 +673,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkStopLoss() { - let strategy = simulationLogic.strategies[strategyNumber - 1]; + let strategy = tradingSystem.strategies[strategyNumber - 1]; let phase = strategy.stopLoss.phases[stopLossPhase - 1]; try { @@ -707,7 +707,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkBuyOrderPhases() { - let strategy = simulationLogic.strategies[strategyNumber - 1]; + let strategy = tradingSystem.strategies[strategyNumber - 1]; let phase = strategy.buyOrder.phases[buyOrderPhase - 1]; for (let k = 0; k < phase.situations.length; k++) { @@ -736,7 +736,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkBuyOrder() { - let strategy = simulationLogic.strategies[strategyNumber - 1]; + let strategy = tradingSystem.strategies[strategyNumber - 1]; let phase = strategy.buyOrder.phases[buyOrderPhase - 1]; try { diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index eb96ce694..e1751c635 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -68,7 +68,7 @@ let strategiesArray = []; let tradesArray = []; - let simulationLogic = {}; + let tradingSystem = {}; let lastObjectsArray = []; commons.initializeData(); @@ -113,7 +113,7 @@ strategiesArray, tradesArray, lastObjectsArray, - simulationLogic, + tradingSystem, timePeriod, currentDay, startDate, @@ -260,7 +260,7 @@ } fileContent = "[" + fileContent + "]"; - fileContent = "[" + JSON.stringify(simulationLogic) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]"; + fileContent = "[" + JSON.stringify(tradingSystem) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]"; let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); let fileName = '' + market.assetA + '_' + market.assetB + '.json'; diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index d0aaf744c..52c201be9 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -69,7 +69,7 @@ let tradesArray = []; let lastObjectsArray = []; - let simulationLogic = {}; + let tradingSystem = {}; let interExecutionMemory = {}; let currentDay = bot.processDatetime; @@ -115,7 +115,7 @@ strategiesArray, tradesArray, lastObjectsArray, - simulationLogic, + tradingSystem, timePeriod, currentDay, startDate, @@ -250,7 +250,7 @@ } fileContent = "[" + fileContent + "]"; - fileContent = "[" + JSON.stringify(simulationLogic) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]"; + fileContent = "[" + JSON.stringify(tradingSystem) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]"; let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; From 7d6213988be4d95f57d9803417a3a236dbda9ec9 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 17:02:27 +0200 Subject: [PATCH 081/244] Refactoring to match protocol naming --- Commons.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Commons.js b/Commons.js index bd612453c..1d5f039ef 100644 --- a/Commons.js +++ b/Commons.js @@ -329,9 +329,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let strategy = tradingSystem.strategies[j]; - for (let k = 0; k < strategy.entryPoint.situations.length; k++) { + for (let k = 0; k < strategy.triggerOn.situations.length; k++) { - let situation = strategy.entryPoint.situations[k]; + let situation = strategy.triggerOn.situations[k]; for (let m = 0; m < situation.conditions.length; m++) { @@ -342,9 +342,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - for (let k = 0; k < strategy.exitPoint.situations.length; k++) { + for (let k = 0; k < strategy.triggerOff.situations.length; k++) { - let situation = strategy.exitPoint.situations[k]; + let situation = strategy.triggerOff.situations[k]; for (let m = 0; m < situation.conditions.length; m++) { @@ -355,9 +355,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - for (let k = 0; k < strategy.sellPoint.situations.length; k++) { + for (let k = 0; k < strategy.takePosition.situations.length; k++) { - let situation = strategy.sellPoint.situations[k]; + let situation = strategy.takePosition.situations[k]; for (let m = 0; m < situation.conditions.length; m++) { @@ -459,9 +459,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let strategy = tradingSystem.strategies[j]; - for (let k = 0; k < strategy.entryPoint.situations.length; k++) { + for (let k = 0; k < strategy.triggerOn.situations.length; k++) { - let situation = strategy.entryPoint.situations[k]; + let situation = strategy.triggerOn.situations[k]; let passed = true; for (let m = 0; m < situation.conditions.length; m++) { @@ -498,9 +498,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let strategy = tradingSystem.strategies[strategyNumber - 1]; - for (let k = 0; k < strategy.exitPoint.situations.length; k++) { + for (let k = 0; k < strategy.triggerOff.situations.length; k++) { - let situation = strategy.exitPoint.situations[k]; + let situation = strategy.triggerOff.situations[k]; let passed = true; for (let m = 0; m < situation.conditions.length; m++) { @@ -603,9 +603,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let strategy = tradingSystem.strategies[strategyNumber - 1]; - for (let k = 0; k < strategy.sellPoint.situations.length; k++) { + for (let k = 0; k < strategy.takePosition.situations.length; k++) { - let situation = strategy.sellPoint.situations[k]; + let situation = strategy.takePosition.situations[k]; let passed = true; for (let m = 0; m < situation.conditions.length; m++) { From c646ad0e390988d67fa39fc3cf3cb46eef2bd136 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 17:07:35 +0200 Subject: [PATCH 082/244] buyOrder refactoring --- Commons.js | 58 ++++++++++++++++----------------- Multi-Period-Daily/User.Bot.js | 4 +-- Multi-Period-Market/User.Bot.js | 4 +-- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/Commons.js b/Commons.js index 1d5f039ef..22a662ef5 100644 --- a/Commons.js +++ b/Commons.js @@ -95,11 +95,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Buy Order Management */ const MIN_BUY_ORDER_VALUE = 1 // We can not let the buy order be zero to avoid division by 0 error or infinity numbers as a result. - let buyOrderPercentage = 1; - let previousBuyOrder = 0; - let buyOrder = 0; - let buyOrderDecay = 0; - let buyOrderPhase = 0; + let takeProfitPercentage = 1; + let previousTakeProfit = 0; + let takeProfit = 0; + let takeProfitDecay = 0; + let takeProfitPhase = 0; /* Building records */ @@ -386,9 +386,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - for (let p = 0; p < strategy.buyOrder.phases.length; p++) { + for (let p = 0; p < strategy.takeProfit.phases.length; p++) { - let phase = strategy.buyOrder.phases[p]; + let phase = strategy.takeProfit.phases[p]; for (let k = 0; k < phase.situations.length; k++) { @@ -565,9 +565,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Buy Order condition: Here we verify if the Buy Order was filled or not. */ - if (candle.min <= buyOrder) { + if (candle.min <= takeProfit) { - balanceAssetA = balanceAssetB / buyOrder; + balanceAssetA = balanceAssetB / takeProfit; balanceAssetB = 0; if (currentDay !== undefined) { @@ -578,13 +578,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - rate = buyOrder; - type = '"Buy@BuyOrder"'; + rate = takeProfit; + type = '"Buy@TakeProfit"'; strategyPhase = 4; currentTrade.end = candle.end; currentTrade.status = 1; currentTrade.exitType = 2; - currentTrade.endRate = buyOrder; + currentTrade.endRate = takeProfit; currentStrategy.number = strategyNumber - 1 currentStrategy.end = candle.end; @@ -624,7 +624,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategyPhase = 2; stopLossPhase = 1; - buyOrderPhase = 1; + takeProfitPhase = 1; currentTrade.begin = candle.begin; currentTrade.beginRate = candle.close; return; @@ -700,15 +700,15 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (strategyPhase === 3) { - checkBuyOrderPhases(); - checkBuyOrder(); + checkTakeProfitPhases(); + checkTakeProfit(); } - function checkBuyOrderPhases() { + function checkTakeProfitPhases() { let strategy = tradingSystem.strategies[strategyNumber - 1]; - let phase = strategy.buyOrder.phases[buyOrderPhase - 1]; + let phase = strategy.takeProfit.phases[takeProfitPhase - 1]; for (let k = 0; k < phase.situations.length; k++) { @@ -727,17 +727,17 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (passed) { - buyOrderPhase++; + takeProfitPhase++; return; } } } - function checkBuyOrder() { + function checkTakeProfit() { let strategy = tradingSystem.strategies[strategyNumber - 1]; - let phase = strategy.buyOrder.phases[buyOrderPhase - 1]; + let phase = strategy.takeProfit.phases[takeProfitPhase - 1]; try { eval(phase.code); // Here is where we apply the formula given for the buy order at this phase. @@ -747,8 +747,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { */ } - if (buyOrder < MIN_BUY_ORDER_VALUE) { - buyOrder = MIN_BUY_ORDER_VALUE + if (takeProfit < MIN_BUY_ORDER_VALUE) { + takeProfit = MIN_BUY_ORDER_VALUE } } @@ -766,7 +766,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { stopLossDecay = 0; checkStopLoss(); - checkBuyOrder(); + checkTakeProfit(); previousBalanceAssetA = balanceAssetA; lastProfit = 0; @@ -862,10 +862,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { sellRate = 0; sellAmount = 0; sellInstant = undefined; - buyOrder = 0; + takeProfit = 0; strategyPhase = 0; stopLossPhase = 0; - buyOrderPhase = 0; + takeProfitPhase = 0; continue; } @@ -911,7 +911,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { ORDER_TYPE.Limit, rate, stopLoss, - buyOrder, + takeProfit, ORDER_DIRECTION.Sell, -1, ORDER_STATUS.Signaled, @@ -968,9 +968,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { lastProfitPercent: lastProfitPercent, strategy: strategyNumber, strategyPhase: strategyPhase, - buyOrder: buyOrder, + takeProfit: takeProfit, stopLossPhase: stopLossPhase, - buyOrderPhase: buyOrderPhase, + takeProfitPhase: takeProfitPhase, orderRecord: orderRecord, sellAmount: sellAmount } @@ -986,7 +986,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { conditionsArrayRecord.push(strategyNumber); conditionsArrayRecord.push(strategyPhase); conditionsArrayRecord.push(stopLossPhase); - conditionsArrayRecord.push(buyOrderPhase); + conditionsArrayRecord.push(takeProfitPhase); conditionsArrayRecord.push(conditionsArrayValues); conditionsArray.push(conditionsArrayRecord); diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index e1751c635..76a4b60c4 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -163,9 +163,9 @@ record.lastProfitPercent + "," + record.strategy + "," + record.strategyPhase + "," + - record.buyOrder + "," + + record.takeProfit + "," + record.stopLossPhase + "," + - record.buyOrderPhase + "," + + record.takeProfitPhase + "," + JSON.stringify(record.orderRecord) + "," + record.sellAmount + "]"; diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 52c201be9..bfddc4abd 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -161,9 +161,9 @@ record.lastProfitPercent + "," + record.strategy + "," + record.strategyPhase + "," + - record.buyOrder + "," + + record.takeProfit + "," + record.stopLossPhase + "," + - record.buyOrderPhase + "," + + record.takeProfitPhase + "," + JSON.stringify(record.orderRecord) + "," + record.sellAmount + "]"; From 6f22e438237f911a1e935e7e9c96620666cb764c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 17:13:31 +0200 Subject: [PATCH 083/244] Removing Unsuded variables --- Commons.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Commons.js b/Commons.js index 22a662ef5..6a8c92928 100644 --- a/Commons.js +++ b/Commons.js @@ -88,17 +88,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let stopLossPercentage = 50; let previousStopLoss = 0; let stopLoss = 0; - let stopLossDecay = 0; - let stopLossDecayIncrement = 0.06; let stopLossPhase = 0; /* Buy Order Management */ const MIN_BUY_ORDER_VALUE = 1 // We can not let the buy order be zero to avoid division by 0 error or infinity numbers as a result. - let takeProfitPercentage = 1; let previousTakeProfit = 0; let takeProfit = 0; - let takeProfitDecay = 0; let takeProfitPhase = 0; /* Building records */ @@ -763,8 +759,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { stopLoss = sellRate + sellRate * stopLossPercentage / 100; previousStopLoss = stopLoss; - stopLossDecay = 0; - checkStopLoss(); checkTakeProfit(); From 1908ab39ce46c355b434c1b533af37b543fdf6d4 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 17:20:09 +0200 Subject: [PATCH 084/244] Getting the Trading System early on --- Commons.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Commons.js b/Commons.js index 6a8c92928..dc03865af 100644 --- a/Commons.js +++ b/Commons.js @@ -71,6 +71,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Entering function."); } + tradingSystem.strategies = await getStrategies(); + /* Initial Values */ let initialDate = startDate; @@ -85,7 +87,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* 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. - let stopLossPercentage = 50; let previousStopLoss = 0; let stopLoss = 0; let stopLossPhase = 0; @@ -251,8 +252,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { yesterday.anualizedRateOfReturn = anualizedRateOfReturn; } - - tradingSystem.strategies = await getStrategies(); /* Main Simulation Loop: We go thourgh all the candles at this time period. */ @@ -756,7 +755,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { sellRate = rate; sellAmount = balanceAssetA; - stopLoss = sellRate + sellRate * stopLossPercentage / 100; + stopLoss = sellRate + sellRate * 1 / 100; previousStopLoss = stopLoss; checkStopLoss(); From a7205d6c2f47f0026899aa7e692f3bbb46383ce3 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 17:24:38 +0200 Subject: [PATCH 085/244] Refactoring and Cleaning --- Commons.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Commons.js b/Commons.js index dc03865af..1cf7da350 100644 --- a/Commons.js +++ b/Commons.js @@ -100,7 +100,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Building records */ - let record; let sellRate = 0; let sellAmount = 0; let sellInstant; @@ -873,7 +872,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { // Since we are going to write the message to a file that the Simulation Executor is going to read, we use the abbreviations. let messageType; let message; - let record; + let simulationRecord; let orderRecord; messageId++; @@ -938,7 +937,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { "") } - record = { + simulationRecord = { begin: candle.begin, end: candle.end, type: type, @@ -968,7 +967,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { sellAmount: sellAmount } - recordsArray.push(record); + recordsArray.push(simulationRecord); previousStopLoss = stopLoss; From de8fed8c2f685797e169324cd8b6899aece90c44 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 17:29:47 +0200 Subject: [PATCH 086/244] Removing the concept of newStopLoss --- Commons.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Commons.js b/Commons.js index 1cf7da350..b68528d0e 100644 --- a/Commons.js +++ b/Commons.js @@ -111,7 +111,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let anualizedRateOfReturn = 0; let type = '""'; let rate = 0; - let newStopLoss; /* In some cases we need to know if we are positioned at the last candle of the calendar day, for that we need thse variables. */ @@ -671,19 +670,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let phase = strategy.stopLoss.phases[stopLossPhase - 1]; try { - eval(phase.code); // Here is where we apply the formula given for the stop loss for this phase. + stopLoss = eval(phase.code); // Here is where we apply the formula given for the stop loss for this phase. } catch (err) { /* If the code produces an exception, we are covered. */ } - if (newStopLoss < previousStopLoss) { - stopLoss = newStopLoss; - } else { - stopLoss = previousStopLoss; - } - if (stopLoss < MIN_STOP_LOSS_VALUE) { stopLoss = MIN_STOP_LOSS_VALUE } @@ -734,7 +727,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let phase = strategy.takeProfit.phases[takeProfitPhase - 1]; try { - eval(phase.code); // Here is where we apply the formula given for the buy order at this phase. + takeProfit = eval(phase.code); // Here is where we apply the formula given for the buy order at this phase. } catch (err) { /* If the code produces an exception, we are covered. From 1615815dd27f5305f72ef529c3d205d6094135c7 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 17:36:01 +0200 Subject: [PATCH 087/244] Refactoring rate and sellRate --- Commons.js | 26 +++++++++++++------------- Multi-Period-Daily/User.Bot.js | 4 ++-- Multi-Period-Market/User.Bot.js | 4 ++-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Commons.js b/Commons.js index b68528d0e..9c98f9c9f 100644 --- a/Commons.js +++ b/Commons.js @@ -100,7 +100,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Building records */ - let sellRate = 0; + let positionRate = 0; let sellAmount = 0; let sellInstant; @@ -110,7 +110,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let days = 0; let anualizedRateOfReturn = 0; let type = '""'; - let rate = 0; + let marketRate = 0; /* In some cases we need to know if we are positioned at the last candle of the calendar day, for that we need thse variables. */ @@ -542,7 +542,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - rate = stopLoss; + marketRate = stopLoss; type = '"Buy@StopLoss"'; strategyPhase = 4; currentTrade.end = candle.end; @@ -571,7 +571,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - rate = takeProfit; + marketRate = takeProfit; type = '"Buy@TakeProfit"'; strategyPhase = 4; currentTrade.end = candle.end; @@ -743,11 +743,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (strategyPhase === 2) { - rate = candle.close; - sellRate = rate; + marketRate = candle.close; + positionRate = marketRate; sellAmount = balanceAssetA; - stopLoss = sellRate + sellRate * 1 / 100; + stopLoss = positionRate + positionRate * 1 / 100; previousStopLoss = stopLoss; checkStopLoss(); @@ -757,7 +757,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { lastProfit = 0; lastProfitPercent = 0; - balanceAssetB = balanceAssetA * rate; + balanceAssetB = balanceAssetA * marketRate; balanceAssetA = 0; sellInstant = candle.end; @@ -844,7 +844,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategyNumber = 0; stopLoss = 0; - sellRate = 0; + positionRate = 0; sellAmount = 0; sellInstant = undefined; takeProfit = 0; @@ -857,7 +857,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Not a buy or sell condition */ - rate = candle.close; + marketRate = candle.close; addRecord(); function addRecord() { @@ -894,7 +894,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { "BTC_USDT", 0, ORDER_TYPE.Limit, - rate, + marketRate, stopLoss, takeProfit, ORDER_DIRECTION.Sell, @@ -934,7 +934,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { begin: candle.begin, end: candle.end, type: type, - rate: rate, + marketRate: marketRate, amount: 1, balanceA: balanceAssetA, balanceB: balanceAssetB, @@ -949,7 +949,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { periods: periods, days: days, anualizedRateOfReturn: anualizedRateOfReturn, - sellRate: sellRate, + positionRate: positionRate, lastProfitPercent: lastProfitPercent, strategy: strategyNumber, strategyPhase: strategyPhase, diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 76a4b60c4..01fb41a61 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -144,7 +144,7 @@ record.begin + "," + record.end + "," + record.type + "," + - record.rate + "," + + record.marketRate + "," + record.amount + "," + record.balanceA + "," + record.balanceB + "," + @@ -159,7 +159,7 @@ record.periods + "," + record.days + "," + record.anualizedRateOfReturn + "," + - record.sellRate + "," + + record.positionRate + "," + record.lastProfitPercent + "," + record.strategy + "," + record.strategyPhase + "," + diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index bfddc4abd..0a1176136 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -142,7 +142,7 @@ record.begin + "," + record.end + "," + record.type + "," + - record.rate + "," + + record.marketRate + "," + record.amount + "," + record.balanceA + "," + record.balanceB + "," + @@ -157,7 +157,7 @@ record.periods + "," + record.days + "," + record.anualizedRateOfReturn + "," + - record.sellRate + "," + + record.positionRate + "," + record.lastProfitPercent + "," + record.strategy + "," + record.strategyPhase + "," + From 24dedbf40dff5994aa9986906ed7e57e4fb2a659 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 17:39:52 +0200 Subject: [PATCH 088/244] refactoring sellAmount --- Commons.js | 8 ++++---- Multi-Period-Daily/User.Bot.js | 2 +- Multi-Period-Market/User.Bot.js | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Commons.js b/Commons.js index 9c98f9c9f..0e981ef09 100644 --- a/Commons.js +++ b/Commons.js @@ -101,7 +101,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Building records */ let positionRate = 0; - let sellAmount = 0; + let positionSize = 0; let sellInstant; let previousBalanceAssetA = 0; @@ -745,7 +745,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { marketRate = candle.close; positionRate = marketRate; - sellAmount = balanceAssetA; + positionSize = balanceAssetA; stopLoss = positionRate + positionRate * 1 / 100; previousStopLoss = stopLoss; @@ -845,7 +845,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategyNumber = 0; stopLoss = 0; positionRate = 0; - sellAmount = 0; + positionSize = 0; sellInstant = undefined; takeProfit = 0; strategyPhase = 0; @@ -957,7 +957,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { stopLossPhase: stopLossPhase, takeProfitPhase: takeProfitPhase, orderRecord: orderRecord, - sellAmount: sellAmount + positionSize: positionSize } recordsArray.push(simulationRecord); diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 01fb41a61..a1d16199b 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -167,7 +167,7 @@ record.stopLossPhase + "," + record.takeProfitPhase + "," + JSON.stringify(record.orderRecord) + "," + - record.sellAmount + "]"; + record.positionSize + "]"; if (separator === "") { separator = ","; } diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 0a1176136..6ac39ba67 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -166,7 +166,7 @@ record.takeProfitPhase + "," + JSON.stringify(record.orderRecord) + "," + - record.sellAmount + "]"; + record.positionSize + "]"; if (separator === "") { separator = ","; } From 5e548349857e4e71a45a8d133c5b889b8c900203 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 17:41:45 +0200 Subject: [PATCH 089/244] Refactoring sellInstant --- Commons.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Commons.js b/Commons.js index 0e981ef09..814c5ba82 100644 --- a/Commons.js +++ b/Commons.js @@ -102,7 +102,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let positionRate = 0; let positionSize = 0; - let sellInstant; + let positionInstant; let previousBalanceAssetA = 0; let hitRatio = 0; @@ -536,7 +536,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { balanceAssetB = 0; if (currentDay !== undefined) { - if (sellInstant < currentDay.valueOf()) { + if (positionInstant < currentDay.valueOf()) { yesterday.balanceAssetA = balanceAssetA; yesterday.balanceAssetB = balanceAssetB; } @@ -564,7 +564,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { balanceAssetB = 0; if (currentDay !== undefined) { - if (sellInstant < currentDay.valueOf()) { + if (positionInstant < currentDay.valueOf()) { yesterday.balanceAssetA = balanceAssetA; yesterday.balanceAssetB = balanceAssetB; @@ -760,10 +760,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { balanceAssetB = balanceAssetA * marketRate; balanceAssetA = 0; - sellInstant = candle.end; + positionInstant = candle.end; if (currentDay !== undefined) { - if (sellInstant < currentDay.valueOf()) { + if (positionInstant < currentDay.valueOf()) { yesterday.balanceAssetA = balanceAssetA; yesterday.balanceAssetB = balanceAssetB; @@ -785,7 +785,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { roundtrips++; if (currentDay !== undefined) { - if (sellInstant < currentDay.valueOf()) { + if (positionInstant < currentDay.valueOf()) { yesterday.Roundtrips++; } } @@ -796,7 +796,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { profit = balanceAssetA - initialBalanceA; if (currentDay !== undefined) { - if (sellInstant < currentDay.valueOf()) { + if (positionInstant < currentDay.valueOf()) { yesterday.lastProfit = lastProfit; yesterday.profit = profit; yesterday.lastProfitPercent = lastProfitPercent; @@ -812,7 +812,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { hits++; if (currentDay !== undefined) { - if (sellInstant < currentDay.valueOf()) { + if (positionInstant < currentDay.valueOf()) { yesterday.hits++; } } @@ -821,7 +821,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { fails++; if (currentDay !== undefined) { - if (sellInstant < currentDay.valueOf()) { + if (positionInstant < currentDay.valueOf()) { yesterday.fails++; } } @@ -832,7 +832,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { anualizedRateOfReturn = ROI / days * 365; if (currentDay !== undefined) { - if (sellInstant < currentDay.valueOf()) { + if (positionInstant < currentDay.valueOf()) { yesterday.ROI = ROI; yesterday.hitRatio = hitRatio; yesterday.anualizedRateOfReturn = anualizedRateOfReturn; @@ -846,7 +846,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { stopLoss = 0; positionRate = 0; positionSize = 0; - sellInstant = undefined; + positionInstant = undefined; takeProfit = 0; strategyPhase = 0; stopLossPhase = 0; From 92c99e2cdd38993a52a44f63dfdc827546b2a4ca Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 17:51:29 +0200 Subject: [PATCH 090/244] Buy Order Refactoring --- Commons.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Commons.js b/Commons.js index 814c5ba82..1ecf6d084 100644 --- a/Commons.js +++ b/Commons.js @@ -91,14 +91,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let stopLoss = 0; let stopLossPhase = 0; - /* Buy Order Management */ + /* Take Profit Management */ - const MIN_BUY_ORDER_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 = 1 // We can not let the buy order be zero to avoid division by 0 error or infinity numbers as a result. let previousTakeProfit = 0; let takeProfit = 0; let takeProfitPhase = 0; - /* Building records */ + /* Simulation Records */ let positionRate = 0; let positionSize = 0; @@ -526,7 +526,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (strategyPhase === 3) { /* Checking what happened since the last execution. We need to know if the Stop Loss - or our Buy Order were hit. */ + or our Take Profit were hit. */ /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ @@ -556,7 +556,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentStrategy.status = 1; } - /* Buy Order condition: Here we verify if the Buy Order was filled or not. */ + /* Take Profit condition: Here we verify if the Take Profit was filled or not. */ if (candle.min <= takeProfit) { @@ -590,9 +590,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (strategyPhase === 1) { - checkSellPoints(); + checkTakePosition(); - function checkSellPoints() { + function checkTakePosition() { let strategy = tradingSystem.strategies[strategyNumber - 1]; @@ -676,7 +676,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { If the code produces an exception, we are covered. */ } - + if (isNaN(stopLoss)) { stopLoss = 0; } if (stopLoss < MIN_STOP_LOSS_VALUE) { stopLoss = MIN_STOP_LOSS_VALUE } @@ -733,9 +733,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { If the code produces an exception, we are covered. */ } - - if (takeProfit < MIN_BUY_ORDER_VALUE) { - takeProfit = MIN_BUY_ORDER_VALUE + if (isNaN(takeProfit)) { takeProfit = 0; } + if (takeProfit < MIN_TAKE_PROFIT_VALUE) { + takeProfit = MIN_TAKE_PROFIT_VALUE } } From 4f083f475da55d66f465de92f423a3f3dbc77d75 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 20:56:17 +0200 Subject: [PATCH 091/244] function evaluateConditions reimplemented --- Commons.js | 277 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 170 insertions(+), 107 deletions(-) diff --git a/Commons.js b/Commons.js index 1ecf6d084..7ce6c2ae3 100644 --- a/Commons.js +++ b/Commons.js @@ -318,114 +318,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { conditionsArrayRecord.push(candle.begin); conditionsArrayRecord.push(candle.end); - for (let j = 0; j < tradingSystem.strategies.length; j++) { + evaluateConditions(tradingSystem, conditions); - let strategy = tradingSystem.strategies[j]; - - for (let k = 0; k < strategy.triggerOn.situations.length; k++) { - - let situation = strategy.triggerOn.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + situation.name + '-' + condition.name; - - newCondition(key, condition.code); - } - } - - for (let k = 0; k < strategy.triggerOff.situations.length; k++) { - - let situation = strategy.triggerOff.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + situation.name + '-' + condition.name; - - newCondition(key, condition.code); - } - } - - for (let k = 0; k < strategy.takePosition.situations.length; k++) { - - let situation = strategy.takePosition.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + situation.name + '-' + condition.name; - - newCondition(key, condition.code); - } - } - - for (let p = 0; p < strategy.stopLoss.phases.length; p++) { - - let phase = strategy.stopLoss.phases[p]; - - for (let k = 0; k < phase.situations.length; k++) { - - let situation = phase.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name; - - newCondition(key, condition.code); - } - } - } - - for (let p = 0; p < strategy.takeProfit.phases.length; p++) { - - let phase = strategy.takeProfit.phases[p]; - - for (let k = 0; k < phase.situations.length; k++) { - - let situation = phase.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name; - - newCondition(key, condition.code); - } - } - } - } - - function newCondition(key, code) { - - let condition; - let value = false; - - try { - value = eval(code); - } catch (err) { - /* - One possible error is that the conditions references a .previous that is undefined. For this - reason and others, we will simply set the value to false. - */ - value = false - } - - condition = { - key: key, - value: value - }; - - conditions.set(condition.key, condition); - - if (condition.value) { - conditionsArrayValues.push(1); - } else { - conditionsArrayValues.push(0); - } - } /* Strategy Enter Condition */ @@ -1076,6 +970,175 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } + function evaluateConditions(tradingSystem, conditions) { + + for (let j = 0; j < tradingSystem.strategies.length; j++) { + + let strategy = tradingSystem.strategies[j]; + + let triggerStage = strategy.triggerStage + + if (triggerStage !== undefined) { + + for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { + + let situation = triggerStage.triggerOn.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; + + newCondition(key, condition.code); + } + } + + for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { + + let situation = triggerStage.triggerOff.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; + + newCondition(key, condition.code); + } + } + + for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { + + let situation = triggerStage.takePosition.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; + + newCondition(key, condition.code); + } + } + } + + let openStage = strategy.openStage + + if (openStage !== undefined) { + + let initialDefinition = openStage.initialDefinition + + if (initialDefinition !== undefined) { + + for (let p = 0; p < initialDefinition.stopLoss.phases.length; p++) { + + let phase = initialDefinition.stopLoss.phases[p]; + + for (let k = 0; k < phase.situations.length; k++) { + + let situation = phase.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; + + newCondition(key, condition.code); + } + } + } + + for (let p = 0; p < initialDefinition.takeProfit.phases.length; p++) { + + let phase = initialDefinition.takeProfit.phases[p]; + + for (let k = 0; k < phase.situations.length; k++) { + + let situation = phase.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; + + newCondition(key, condition.code); + } + } + } + } + } + + let manageStage = strategy.manageStage + + if (manageStage !== undefined) { + + for (let p = 0; p < manageStage.stopLoss.phases.length; p++) { + + let phase = manageStage.stopLoss.phases[p]; + + for (let k = 0; k < phase.situations.length; k++) { + + let situation = phase.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; + + newCondition(key, condition.code); + } + } + } + + for (let p = 0; p < manageStage.takeProfit.phases.length; p++) { + + let phase = manageStage.takeProfit.phases[p]; + + for (let k = 0; k < phase.situations.length; k++) { + + let situation = phase.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; + + newCondition(key, condition.code); + } + } + } + } + } + + function newCondition(key, code) { + + let condition; + let value = false; + + try { + value = eval(code); + } catch (err) { + /* + One possible error is that the conditions references a .previous that is undefined. For this + reason and others, we will simply set the value to false. + */ + value = false + } + + condition = { + key: key, + value: value + }; + + conditions.set(condition.key, condition); + + if (condition.value) { + conditionsArrayValues.push(1); + } else { + conditionsArrayValues.push(0); + } + } + + } + function buildLRC(dataFile, callBackFunction) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildLRC -> Entering function."); } From 76e7be2560debd4e5eb9f179a00c6e7a7e32174b Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 21:01:42 +0200 Subject: [PATCH 092/244] Refactoring Trigger On and Off --- Commons.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Commons.js b/Commons.js index 7ce6c2ae3..2865c3ed0 100644 --- a/Commons.js +++ b/Commons.js @@ -321,8 +321,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { evaluateConditions(tradingSystem, conditions); - - /* Strategy Enter Condition */ + /* Trigger On Conditions */ if (strategyNumber === 0 && balanceAssetA > minimunBalanceA) { @@ -331,16 +330,16 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { 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 an entering condition. Once we enter + 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 exit condition which can be hit before entering into a trade. If hit, we would + 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. */ - checkEntryPoints(); + checkTriggerOn(); - function checkEntryPoints() { + function checkTriggerOn() { for (let j = 0; j < tradingSystem.strategies.length; j++) { @@ -375,13 +374,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - /* Strategy Exit Condition */ + /* Trigger Off Condition */ if (strategyPhase === 1) { - checkExitPoints(); + checkTriggerOff(); - function checkExitPoints() { + function checkTriggerOff() { let strategy = tradingSystem.strategies[strategyNumber - 1]; From cc3881edde211d6bd1f4db2a7f44d32bc99e3dcc Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 21:03:46 +0200 Subject: [PATCH 093/244] Refactoring Strategy Number --- Commons.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Commons.js b/Commons.js index 2865c3ed0..22b1f741e 100644 --- a/Commons.js +++ b/Commons.js @@ -81,7 +81,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Strategy and Phases */ - let strategyNumber = 0; + let currentStrategyNumber = 0; let strategyPhase = 0; // So far we will consider 5 possible phases: 0 = Initial state, 1 = Signal to buy, 2 = Buy, 3 = After Buy, 4 = Sell. /* Stop Loss Management */ @@ -323,7 +323,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Trigger On Conditions */ - if (strategyNumber === 0 && + if (currentStrategyNumber === 0 && balanceAssetA > minimunBalanceA) { /* @@ -363,7 +363,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (passed) { strategyPhase = 1; - strategyNumber = j + 1; + currentStrategyNumber = j + 1; currentStrategy.begin = candle.begin; currentStrategy.beginRate = candle.min; currentStrategy.endRate = candle.min; // In case the strategy does not get exited @@ -382,7 +382,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkTriggerOff() { - let strategy = tradingSystem.strategies[strategyNumber - 1]; + let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; for (let k = 0; k < strategy.triggerOff.situations.length; k++) { @@ -401,12 +401,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (passed) { - currentStrategy.number = strategyNumber - 1 + currentStrategy.number = currentStrategyNumber - 1 currentStrategy.end = candle.end; currentStrategy.endRate = candle.min; currentStrategy.status = 1; strategyPhase = 0; - strategyNumber = 0; + currentStrategyNumber = 0; return; } @@ -443,7 +443,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentTrade.exitType = 1; currentTrade.endRate = stopLoss; - currentStrategy.number = strategyNumber - 1 + currentStrategy.number = currentStrategyNumber - 1 currentStrategy.end = candle.end; currentStrategy.endRate = candle.min; currentStrategy.status = 1; @@ -472,7 +472,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentTrade.exitType = 2; currentTrade.endRate = takeProfit; - currentStrategy.number = strategyNumber - 1 + currentStrategy.number = currentStrategyNumber - 1 currentStrategy.end = candle.end; currentStrategy.endRate = candle.min; currentStrategy.status = 1; @@ -487,7 +487,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkTakePosition() { - let strategy = tradingSystem.strategies[strategyNumber - 1]; + let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; for (let k = 0; k < strategy.takePosition.situations.length; k++) { @@ -530,7 +530,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkStopPhases() { - let strategy = tradingSystem.strategies[strategyNumber - 1]; + let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; let phase = strategy.stopLoss.phases[stopLossPhase - 1]; for (let k = 0; k < phase.situations.length; k++) { @@ -559,7 +559,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkStopLoss() { - let strategy = tradingSystem.strategies[strategyNumber - 1]; + let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; let phase = strategy.stopLoss.phases[stopLossPhase - 1]; try { @@ -587,7 +587,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkTakeProfitPhases() { - let strategy = tradingSystem.strategies[strategyNumber - 1]; + let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; let phase = strategy.takeProfit.phases[takeProfitPhase - 1]; for (let k = 0; k < phase.situations.length; k++) { @@ -616,7 +616,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkTakeProfit() { - let strategy = tradingSystem.strategies[strategyNumber - 1]; + let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; let phase = strategy.takeProfit.phases[takeProfitPhase - 1]; try { @@ -735,7 +735,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { addRecord(); - strategyNumber = 0; + currentStrategyNumber = 0; stopLoss = 0; positionRate = 0; positionSize = 0; @@ -844,7 +844,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { anualizedRateOfReturn: anualizedRateOfReturn, positionRate: positionRate, lastProfitPercent: lastProfitPercent, - strategy: strategyNumber, + strategy: currentStrategyNumber, strategyPhase: strategyPhase, takeProfit: takeProfit, stopLossPhase: stopLossPhase, @@ -861,7 +861,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Prepare the information for the Conditions File */ - conditionsArrayRecord.push(strategyNumber); + conditionsArrayRecord.push(currentStrategyNumber); conditionsArrayRecord.push(strategyPhase); conditionsArrayRecord.push(stopLossPhase); conditionsArrayRecord.push(takeProfitPhase); From 19223fde1b1b778584cbd20b1b7fb4f49f78d2d6 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 21:11:38 +0200 Subject: [PATCH 094/244] Naming Strategy Stages --- Commons.js | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/Commons.js b/Commons.js index 22b1f741e..34baf42ab 100644 --- a/Commons.js +++ b/Commons.js @@ -82,7 +82,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Strategy and Phases */ let currentStrategyNumber = 0; - let strategyPhase = 0; // So far we will consider 5 possible phases: 0 = Initial state, 1 = Signal to buy, 2 = Buy, 3 = After Buy, 4 = Sell. + let strategyStage = 'No Stage'; /* Stop Loss Management */ @@ -320,12 +320,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { evaluateConditions(tradingSystem, conditions); - - /* Trigger On Conditions */ - if (currentStrategyNumber === 0 && balanceAssetA > minimunBalanceA) { + /* Trigger On Conditions */ + /* 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. @@ -362,7 +361,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (passed) { - strategyPhase = 1; + strategyStage = 'Trigger Stage'; currentStrategyNumber = j + 1; currentStrategy.begin = candle.begin; currentStrategy.beginRate = candle.min; @@ -376,7 +375,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Trigger Off Condition */ - if (strategyPhase === 1) { + if (strategyStage === 'Trigger Stage') { checkTriggerOff(); @@ -405,7 +404,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentStrategy.end = candle.end; currentStrategy.endRate = candle.min; currentStrategy.status = 1; - strategyPhase = 0; + strategyStage = 'No Stage'; currentStrategyNumber = 0; return; @@ -416,7 +415,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Checking if Stop or Take Profit were hit */ - if (strategyPhase === 3) { + if (strategyStage === 'Manage Stage') { /* Checking what happened since the last execution. We need to know if the Stop Loss or our Take Profit were hit. */ @@ -437,7 +436,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { marketRate = stopLoss; type = '"Buy@StopLoss"'; - strategyPhase = 4; + strategyStage = 4; currentTrade.end = candle.end; currentTrade.status = 1; currentTrade.exitType = 1; @@ -466,7 +465,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { marketRate = takeProfit; type = '"Buy@TakeProfit"'; - strategyPhase = 4; + strategyStage = 4; currentTrade.end = candle.end; currentTrade.status = 1; currentTrade.exitType = 2; @@ -481,7 +480,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Trade Enter Condition */ - if (strategyPhase === 1) { + if (strategyStage === 'Trigger Stage') { checkTakePosition(); @@ -508,7 +507,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { type = '"Sell"'; - strategyPhase = 2; + strategyStage = 'Open Stage'; stopLossPhase = 1; takeProfitPhase = 1; currentTrade.begin = candle.begin; @@ -521,7 +520,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Stop Loss Management */ - if (strategyPhase === 3) { + if (strategyStage === 'Manage Stage') { checkStopPhases() checkStopLoss(); @@ -578,7 +577,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Take Profit Management */ - if (strategyPhase === 3) { + if (strategyStage === 'Manage Stage') { checkTakeProfitPhases(); checkTakeProfit(); @@ -634,7 +633,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Entering into a Trade */ - if (strategyPhase === 2) { + if (strategyStage === 'Open Stage') { marketRate = candle.close; positionRate = marketRate; @@ -667,13 +666,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { addRecord(); - strategyPhase = 3; + strategyStage = 3; continue; } /* Exiting a Trade */ - if (strategyPhase === 4) { + if (strategyStage === 'Close Stage') { roundtrips++; @@ -741,7 +740,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { positionSize = 0; positionInstant = undefined; takeProfit = 0; - strategyPhase = 0; + strategyStage = 'No Stage'; stopLossPhase = 0; takeProfitPhase = 0; continue; @@ -763,13 +762,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { messageId++; - if (strategyPhase === 2 || strategyPhase === 3) { + if (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') { - if (strategyPhase === 2) { + if (strategyStage === 'Open Stage') { messageType = MESSAGE_TYPE.Order; orderId++; } - if (strategyPhase === 3) { + if (strategyStage === 'Manage Stage') { messageType = MESSAGE_TYPE.OrderUpdate; } @@ -845,7 +844,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { positionRate: positionRate, lastProfitPercent: lastProfitPercent, strategy: currentStrategyNumber, - strategyPhase: strategyPhase, + strategyStage: strategyStage, takeProfit: takeProfit, stopLossPhase: stopLossPhase, takeProfitPhase: takeProfitPhase, @@ -862,7 +861,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Prepare the information for the Conditions File */ conditionsArrayRecord.push(currentStrategyNumber); - conditionsArrayRecord.push(strategyPhase); + conditionsArrayRecord.push(strategyStage); conditionsArrayRecord.push(stopLossPhase); conditionsArrayRecord.push(takeProfitPhase); conditionsArrayRecord.push(conditionsArrayValues); From e552d6fd4e373ad83b76bd139471460cbbec3495 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 21:19:20 +0200 Subject: [PATCH 095/244] Reorganizing Code and dividing in stages --- Commons.js | 91 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/Commons.js b/Commons.js index 34baf42ab..5701c3071 100644 --- a/Commons.js +++ b/Commons.js @@ -320,20 +320,23 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { evaluateConditions(tradingSystem, conditions); - if (currentStrategyNumber === 0 && - balanceAssetA > minimunBalanceA) { + if ( + strategyStage === 'No Stage' && + currentStrategyNumber === 0 && + balanceAssetA > minimunBalanceA + ) { /* Trigger On Conditions */ /* 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. - + */ checkTriggerOn(); @@ -413,6 +416,46 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } + /* Take Position Condition */ + + if (strategyStage === 'Trigger Stage') { + + checkTakePosition(); + + function checkTakePosition() { + + let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; + + for (let k = 0; k < strategy.takePosition.situations.length; k++) { + + let situation = strategy.takePosition.situations[k]; + let passed = true; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = strategy.name + '-' + situation.name + '-' + condition.name + + let value = conditions.get(key).value; + + if (value === false) { passed = false; } + } + + if (passed) { + + type = '"Sell"'; + + strategyStage = 'Open Stage'; + stopLossPhase = 1; + takeProfitPhase = 1; + currentTrade.begin = candle.begin; + currentTrade.beginRate = candle.close; + return; + } + } + } + } + /* Checking if Stop or Take Profit were hit */ if (strategyStage === 'Manage Stage') { @@ -478,46 +521,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - /* Trade Enter Condition */ - - if (strategyStage === 'Trigger Stage') { - - checkTakePosition(); - - function checkTakePosition() { - - let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; - - for (let k = 0; k < strategy.takePosition.situations.length; k++) { - - let situation = strategy.takePosition.situations[k]; - let passed = true; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = strategy.name + '-' + situation.name + '-' + condition.name - - let value = conditions.get(key).value; - - if (value === false) { passed = false; } - } - - if (passed) { - - type = '"Sell"'; - - strategyStage = 'Open Stage'; - stopLossPhase = 1; - takeProfitPhase = 1; - currentTrade.begin = candle.begin; - currentTrade.beginRate = candle.close; - return; - } - } - } - } - /* Stop Loss Management */ if (strategyStage === 'Manage Stage') { From 0cbf840149f4929456df146d97bf00e4c406564e Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 21:24:41 +0200 Subject: [PATCH 096/244] checkTriggerOn re implemented --- Commons.js | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/Commons.js b/Commons.js index 5701c3071..6f5043753 100644 --- a/Commons.js +++ b/Commons.js @@ -347,29 +347,34 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let strategy = tradingSystem.strategies[j]; - for (let k = 0; k < strategy.triggerOn.situations.length; k++) { + let triggerStage = strategy.triggerStage - let situation = strategy.triggerOn.situations[k]; - let passed = true; + if (triggerStage !== undefined) { - for (let m = 0; m < situation.conditions.length; m++) { + for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { - let condition = situation.conditions[m]; - let key = strategy.name + '-' + situation.name + '-' + condition.name + let situation = triggerStage.triggerOn.situations[k]; + let passed = true; - let value = conditions.get(key).value; + for (let m = 0; m < situation.conditions.length; m++) { - if (value === false) { passed = false; } - } + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; - if (passed) { + let value = conditions.get(key).value; - strategyStage = 'Trigger Stage'; - currentStrategyNumber = j + 1; - currentStrategy.begin = candle.begin; - currentStrategy.beginRate = candle.min; - currentStrategy.endRate = candle.min; // In case the strategy does not get exited - return; + if (value === false) { passed = false; } + } + + if (passed) { + + strategyStage = 'Trigger Stage'; + currentStrategyNumber = j + 1; + currentStrategy.begin = candle.begin; + currentStrategy.beginRate = candle.min; + currentStrategy.endRate = candle.min; // In case the strategy does not get exited + return; + } } } } From 0b2209c299dd15d3c1fba03bdee5d0d281cafbb7 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 21:28:54 +0200 Subject: [PATCH 097/244] Trigger Off evaluation re implemented --- Commons.js | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/Commons.js b/Commons.js index 6f5043753..9073cb668 100644 --- a/Commons.js +++ b/Commons.js @@ -391,31 +391,36 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; - for (let k = 0; k < strategy.triggerOff.situations.length; k++) { + let triggerStage = strategy.triggerStage - let situation = strategy.triggerOff.situations[k]; - let passed = true; + if (triggerStage !== undefined) { - for (let m = 0; m < situation.conditions.length; m++) { + for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { - let condition = situation.conditions[m]; - let key = strategy.name + '-' + situation.name + '-' + condition.name + let situation = triggerStage.triggerOff.situations[k]; + let passed = true; - let value = conditions.get(key).value; + for (let m = 0; m < situation.conditions.length; m++) { - if (value === false) { passed = false; } - } + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; - if (passed) { + let value = conditions.get(key).value; - currentStrategy.number = currentStrategyNumber - 1 - currentStrategy.end = candle.end; - currentStrategy.endRate = candle.min; - currentStrategy.status = 1; - strategyStage = 'No Stage'; - currentStrategyNumber = 0; + if (value === false) { passed = false; } + } - return; + if (passed) { + + currentStrategy.number = currentStrategyNumber - 1 + currentStrategy.end = candle.end; + currentStrategy.endRate = candle.min; + currentStrategy.status = 1; + strategyStage = 'No Stage'; + currentStrategyNumber = 0; + + return; + } } } } From 08eba2f94881ec80d627f6ca2c3a2d161ebdbe14 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 21:32:21 +0200 Subject: [PATCH 098/244] take position evaluation re implemented --- Commons.js | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/Commons.js b/Commons.js index 9073cb668..5fe9803ca 100644 --- a/Commons.js +++ b/Commons.js @@ -436,31 +436,36 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; - for (let k = 0; k < strategy.takePosition.situations.length; k++) { + let triggerStage = strategy.triggerStage - let situation = strategy.takePosition.situations[k]; - let passed = true; + if (triggerStage !== undefined) { - for (let m = 0; m < situation.conditions.length; m++) { + for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { - let condition = situation.conditions[m]; - let key = strategy.name + '-' + situation.name + '-' + condition.name + let situation = triggerStage.takePosition.situations[k]; + let passed = true; - let value = conditions.get(key).value; + for (let m = 0; m < situation.conditions.length; m++) { - if (value === false) { passed = false; } - } + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; - if (passed) { + let value = conditions.get(key).value; - type = '"Sell"'; + if (value === false) { passed = false; } + } - strategyStage = 'Open Stage'; - stopLossPhase = 1; - takeProfitPhase = 1; - currentTrade.begin = candle.begin; - currentTrade.beginRate = candle.close; - return; + if (passed) { + + type = '"Sell"'; + + strategyStage = 'Open Stage'; + stopLossPhase = 1; + takeProfitPhase = 1; + currentTrade.begin = candle.begin; + currentTrade.beginRate = candle.close; + return; + } } } } From 9d85f3f21bedcae6adc4facb53d7dc46bf13e3dd Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 21:35:05 +0200 Subject: [PATCH 099/244] Possible Bug fixed when properties of stages are undefined --- Commons.js | 109 +++++++++++++++++++++++++++++------------------------ 1 file changed, 59 insertions(+), 50 deletions(-) diff --git a/Commons.js b/Commons.js index 5fe9803ca..54b3f3433 100644 --- a/Commons.js +++ b/Commons.js @@ -351,29 +351,32 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (triggerStage !== undefined) { - for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { + if (triggerStage.triggerOn !== undefined) { - let situation = triggerStage.triggerOn.situations[k]; - let passed = true; + for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { - for (let m = 0; m < situation.conditions.length; m++) { + let situation = triggerStage.triggerOn.situations[k]; + let passed = true; - let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; + for (let m = 0; m < situation.conditions.length; m++) { - let value = conditions.get(key).value; + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; - if (value === false) { passed = false; } - } + let value = conditions.get(key).value; - if (passed) { + if (value === false) { passed = false; } + } - strategyStage = 'Trigger Stage'; - currentStrategyNumber = j + 1; - currentStrategy.begin = candle.begin; - currentStrategy.beginRate = candle.min; - currentStrategy.endRate = candle.min; // In case the strategy does not get exited - return; + if (passed) { + + strategyStage = 'Trigger Stage'; + currentStrategyNumber = j + 1; + currentStrategy.begin = candle.begin; + currentStrategy.beginRate = candle.min; + currentStrategy.endRate = candle.min; // In case the strategy does not get exited + return; + } } } } @@ -395,31 +398,34 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (triggerStage !== undefined) { - for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { + if (triggerStage.triggerOff !== undefined) { - let situation = triggerStage.triggerOff.situations[k]; - let passed = true; + for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { - for (let m = 0; m < situation.conditions.length; m++) { + let situation = triggerStage.triggerOff.situations[k]; + let passed = true; - let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; + for (let m = 0; m < situation.conditions.length; m++) { - let value = conditions.get(key).value; + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; - if (value === false) { passed = false; } - } + let value = conditions.get(key).value; - if (passed) { + if (value === false) { passed = false; } + } - currentStrategy.number = currentStrategyNumber - 1 - currentStrategy.end = candle.end; - currentStrategy.endRate = candle.min; - currentStrategy.status = 1; - strategyStage = 'No Stage'; - currentStrategyNumber = 0; + if (passed) { - return; + currentStrategy.number = currentStrategyNumber - 1 + currentStrategy.end = candle.end; + currentStrategy.endRate = candle.min; + currentStrategy.status = 1; + strategyStage = 'No Stage'; + currentStrategyNumber = 0; + + return; + } } } } @@ -440,31 +446,34 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (triggerStage !== undefined) { - for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { + if (triggerStage.takePosition !== undefined) { - let situation = triggerStage.takePosition.situations[k]; - let passed = true; + for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { - for (let m = 0; m < situation.conditions.length; m++) { + let situation = triggerStage.takePosition.situations[k]; + let passed = true; - let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; + for (let m = 0; m < situation.conditions.length; m++) { - let value = conditions.get(key).value; + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; - if (value === false) { passed = false; } - } + let value = conditions.get(key).value; - if (passed) { + if (value === false) { passed = false; } + } - type = '"Sell"'; + if (passed) { - strategyStage = 'Open Stage'; - stopLossPhase = 1; - takeProfitPhase = 1; - currentTrade.begin = candle.begin; - currentTrade.beginRate = candle.close; - return; + type = '"Sell"'; + + strategyStage = 'Open Stage'; + stopLossPhase = 1; + takeProfitPhase = 1; + currentTrade.begin = candle.begin; + currentTrade.beginRate = candle.close; + return; + } } } } From 0cbee1c11bd821c83b26b1cd8b2606767bee566f Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 21:40:33 +0200 Subject: [PATCH 100/244] Possible BUG evaluatiing conditions when properties are undefined --- Commons.js | 121 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 71 insertions(+), 50 deletions(-) diff --git a/Commons.js b/Commons.js index 54b3f3433..188a1d1d9 100644 --- a/Commons.js +++ b/Commons.js @@ -1005,42 +1005,51 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (triggerStage !== undefined) { - for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { + if (triggerStage.triggerOn !== undefined) { - let situation = triggerStage.triggerOn.situations[k]; + for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { - for (let m = 0; m < situation.conditions.length; m++) { + let situation = triggerStage.triggerOn.situations[k]; - let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; + for (let m = 0; m < situation.conditions.length; m++) { - newCondition(key, condition.code); + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; + + newCondition(key, condition.code); + } } } - for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { + if (triggerStage.triggerOff !== undefined) { - let situation = triggerStage.triggerOff.situations[k]; + for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { - for (let m = 0; m < situation.conditions.length; m++) { + let situation = triggerStage.triggerOff.situations[k]; - let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; + for (let m = 0; m < situation.conditions.length; m++) { - newCondition(key, condition.code); + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; + + newCondition(key, condition.code); + } } } - for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { + if (triggerStage.takePosition !== undefined) { - let situation = triggerStage.takePosition.situations[k]; + for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { - for (let m = 0; m < situation.conditions.length; m++) { + let situation = triggerStage.takePosition.situations[k]; - let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; + for (let m = 0; m < situation.conditions.length; m++) { - newCondition(key, condition.code); + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; + + newCondition(key, condition.code); + } } } } @@ -1053,38 +1062,44 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (initialDefinition !== undefined) { - for (let p = 0; p < initialDefinition.stopLoss.phases.length; p++) { + if (initialDefinition.stopLoss !== undefined) { - let phase = initialDefinition.stopLoss.phases[p]; + for (let p = 0; p < initialDefinition.stopLoss.phases.length; p++) { - for (let k = 0; k < phase.situations.length; k++) { + let phase = initialDefinition.stopLoss.phases[p]; - let situation = phase.situations[k]; + for (let k = 0; k < phase.situations.length; k++) { - for (let m = 0; m < situation.conditions.length; m++) { + let situation = phase.situations[k]; - let condition = situation.conditions[m]; - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; + for (let m = 0; m < situation.conditions.length; m++) { - newCondition(key, condition.code); + let condition = situation.conditions[m]; + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; + + newCondition(key, condition.code); + } } } } - for (let p = 0; p < initialDefinition.takeProfit.phases.length; p++) { + if (initialDefinition.takeProfit !== undefined) { - let phase = initialDefinition.takeProfit.phases[p]; + for (let p = 0; p < initialDefinition.takeProfit.phases.length; p++) { - for (let k = 0; k < phase.situations.length; k++) { + let phase = initialDefinition.takeProfit.phases[p]; - let situation = phase.situations[k]; + for (let k = 0; k < phase.situations.length; k++) { - for (let m = 0; m < situation.conditions.length; m++) { + let situation = phase.situations[k]; - let condition = situation.conditions[m]; - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; + for (let m = 0; m < situation.conditions.length; m++) { - newCondition(key, condition.code); + let condition = situation.conditions[m]; + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; + + newCondition(key, condition.code); + } } } } @@ -1095,38 +1110,44 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (manageStage !== undefined) { - for (let p = 0; p < manageStage.stopLoss.phases.length; p++) { + if (manageStage.stopLoss !== undefined) { - let phase = manageStage.stopLoss.phases[p]; + for (let p = 0; p < manageStage.stopLoss.phases.length; p++) { - for (let k = 0; k < phase.situations.length; k++) { + let phase = manageStage.stopLoss.phases[p]; - let situation = phase.situations[k]; + for (let k = 0; k < phase.situations.length; k++) { - for (let m = 0; m < situation.conditions.length; m++) { + let situation = phase.situations[k]; - let condition = situation.conditions[m]; - let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; + for (let m = 0; m < situation.conditions.length; m++) { - newCondition(key, condition.code); + let condition = situation.conditions[m]; + let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; + + newCondition(key, condition.code); + } } } } - for (let p = 0; p < manageStage.takeProfit.phases.length; p++) { + if (manageStage.takeProfit !== undefined) { - let phase = manageStage.takeProfit.phases[p]; + for (let p = 0; p < manageStage.takeProfit.phases.length; p++) { - for (let k = 0; k < phase.situations.length; k++) { + let phase = manageStage.takeProfit.phases[p]; - let situation = phase.situations[k]; + for (let k = 0; k < phase.situations.length; k++) { - for (let m = 0; m < situation.conditions.length; m++) { + let situation = phase.situations[k]; - let condition = situation.conditions[m]; - let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; + for (let m = 0; m < situation.conditions.length; m++) { - newCondition(key, condition.code); + let condition = situation.conditions[m]; + let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; + + newCondition(key, condition.code); + } } } } From eb7da338118c0c00a136cf05a87c95286f1c2361 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 21:48:11 +0200 Subject: [PATCH 101/244] Refactoring check for calculate --- Commons.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Commons.js b/Commons.js index 188a1d1d9..5ae6b1cac 100644 --- a/Commons.js +++ b/Commons.js @@ -550,7 +550,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (strategyStage === 'Manage Stage') { checkStopPhases() - checkStopLoss(); + calculateStopLoss(); } @@ -583,7 +583,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - function checkStopLoss() { + function calculateStopLoss() { let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; let phase = strategy.stopLoss.phases[stopLossPhase - 1]; @@ -607,7 +607,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (strategyStage === 'Manage Stage') { checkTakeProfitPhases(); - checkTakeProfit(); + calculateTakeProfit(); } @@ -640,7 +640,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - function checkTakeProfit() { + function calculateTakeProfit() { let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; let phase = strategy.takeProfit.phases[takeProfitPhase - 1]; @@ -669,8 +669,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { stopLoss = positionRate + positionRate * 1 / 100; previousStopLoss = stopLoss; - checkStopLoss(); - checkTakeProfit(); + calculateStopLoss(); + calculateTakeProfit(); previousBalanceAssetA = balanceAssetA; lastProfit = 0; From b962c0954c6205f20031a7008fe33b08855958bc Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 21:55:27 +0200 Subject: [PATCH 102/244] strategyStage --- Commons.js | 6 +++--- Multi-Period-Daily/User.Bot.js | 2 +- Multi-Period-Market/User.Bot.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Commons.js b/Commons.js index 5ae6b1cac..736a2c286 100644 --- a/Commons.js +++ b/Commons.js @@ -503,7 +503,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { marketRate = stopLoss; type = '"Buy@StopLoss"'; - strategyStage = 4; + strategyStage = 'Close Stage'; currentTrade.end = candle.end; currentTrade.status = 1; currentTrade.exitType = 1; @@ -532,7 +532,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { marketRate = takeProfit; type = '"Buy@TakeProfit"'; - strategyStage = 4; + strategyStage = 'Close Stage'; currentTrade.end = candle.end; currentTrade.status = 1; currentTrade.exitType = 2; @@ -693,7 +693,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { addRecord(); - strategyStage = 3; + strategyStage = 'Manage Stage'; continue; } diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index a1d16199b..44991c675 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -162,7 +162,7 @@ record.positionRate + "," + record.lastProfitPercent + "," + record.strategy + "," + - record.strategyPhase + "," + + "'" + record.strategyStage + "'" + "," + record.takeProfit + "," + record.stopLossPhase + "," + record.takeProfitPhase + "," + diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 6ac39ba67..28c80827a 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -160,7 +160,7 @@ record.positionRate + "," + record.lastProfitPercent + "," + record.strategy + "," + - record.strategyPhase + "," + + "'" + record.strategyStage + "'" + "," + record.takeProfit + "," + record.stopLossPhase + "," + record.takeProfitPhase + "," + From dbaf0b3e7d9df83cface409579a5522492319c61 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 4 Jun 2019 22:00:44 +0200 Subject: [PATCH 103/244] Checking if Stop or Take Profit were hit --- Commons.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Commons.js b/Commons.js index 736a2c286..b09d30b06 100644 --- a/Commons.js +++ b/Commons.js @@ -482,7 +482,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Checking if Stop or Take Profit were hit */ - if (strategyStage === 'Manage Stage') { + if ( + strategyStage === 'Open Stage' || + strategyStage === 'Manage Stage' + ) { /* Checking what happened since the last execution. We need to know if the Stop Loss or our Take Profit were hit. */ @@ -547,7 +550,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Stop Loss Management */ - if (strategyStage === 'Manage Stage') { + if ( + strategyStage === 'Open Stage' || + strategyStage === 'Manage Stage' + ) { checkStopPhases() calculateStopLoss(); @@ -604,7 +610,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Take Profit Management */ - if (strategyStage === 'Manage Stage') { + if ( + strategyStage === 'Open Stage' || + strategyStage === 'Manage Stage' + ) { checkTakeProfitPhases(); calculateTakeProfit(); From da03150d147a9fb7734de91e7be31dadb6b217d9 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 10:17:04 +0200 Subject: [PATCH 104/244] checkStopPhases and calculateStopLoss re implemented --- Commons.js | 101 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 72 insertions(+), 29 deletions(-) diff --git a/Commons.js b/Commons.js index b09d30b06..69c652b46 100644 --- a/Commons.js +++ b/Commons.js @@ -81,7 +81,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Strategy and Phases */ - let currentStrategyNumber = 0; + let currentStrategyIndex = 0; let strategyStage = 'No Stage'; /* Stop Loss Management */ @@ -322,7 +322,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if ( strategyStage === 'No Stage' && - currentStrategyNumber === 0 && + currentStrategyIndex === 0 && balanceAssetA > minimunBalanceA ) { @@ -371,7 +371,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (passed) { strategyStage = 'Trigger Stage'; - currentStrategyNumber = j + 1; + currentStrategyIndex = j; currentStrategy.begin = candle.begin; currentStrategy.beginRate = candle.min; currentStrategy.endRate = candle.min; // In case the strategy does not get exited @@ -392,7 +392,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkTriggerOff() { - let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; + let strategy = tradingSystem.strategies[currentStrategyIndex]; let triggerStage = strategy.triggerStage @@ -417,12 +417,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (passed) { - currentStrategy.number = currentStrategyNumber - 1 + currentStrategy.number = currentStrategyIndex currentStrategy.end = candle.end; currentStrategy.endRate = candle.min; currentStrategy.status = 1; strategyStage = 'No Stage'; - currentStrategyNumber = 0; + currentStrategyIndex = 0; return; } @@ -440,7 +440,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkTakePosition() { - let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; + let strategy = tradingSystem.strategies[currentStrategyIndex]; let triggerStage = strategy.triggerStage @@ -512,7 +512,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentTrade.exitType = 1; currentTrade.endRate = stopLoss; - currentStrategy.number = currentStrategyNumber - 1 + currentStrategy.number = currentStrategyIndex currentStrategy.end = candle.end; currentStrategy.endRate = candle.min; currentStrategy.status = 1; @@ -541,7 +541,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentTrade.exitType = 2; currentTrade.endRate = takeProfit; - currentStrategy.number = currentStrategyNumber - 1 + currentStrategy.number = currentStrategyIndex currentStrategy.end = candle.end; currentStrategy.endRate = candle.min; currentStrategy.status = 1; @@ -562,8 +562,36 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkStopPhases() { - let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; - let phase = strategy.stopLoss.phases[stopLossPhase - 1]; + let strategy = tradingSystem.strategies[currentStrategyIndex]; + + let openStage = strategy.openStage + let manageStage = strategy.manageStage + let parentNode + let j = currentStrategyIndex + let stageKey + let initialDefinitionKey = '' + let p + + if (strategyStage === 'Open Stage' && openStage !== undefined) { + if (openStage.initialDefinition !== undefined) { + if (openStage.initialDefinition.stopLoss !== undefined) { + parentNode = openStage.initialDefinition + initialDefinitionKey = '-' + 'initialDefinition' + stageKey = 'openStage' + p = stopLossPhase - 1 + } + } + } + + if (strategyStage === 'Manage Stage' && manageStage !== undefined) { + if (manageStage.stopLoss !== undefined) { + parentNode = manageStage + stageKey = 'manageStage' + p = stopLossPhase - 2 + } + } + + let phase = parentNode.stopLoss.phases[p]; for (let k = 0; k < phase.situations.length; k++) { @@ -573,7 +601,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { for (let m = 0; m < situation.conditions.length; m++) { let condition = situation.conditions[m]; - let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name + let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; let value = conditions.get(key).value; @@ -591,21 +619,36 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function calculateStopLoss() { - let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; - let phase = strategy.stopLoss.phases[stopLossPhase - 1]; + let strategy = tradingSystem.strategies[currentStrategyIndex]; + let openStage = strategy.openStage + let manageStage = strategy.manageStage + let phase - try { - stopLoss = eval(phase.code); // Here is where we apply the formula given for the stop loss for this phase. - } catch (err) { - /* - If the code produces an exception, we are covered. - */ - } - if (isNaN(stopLoss)) { stopLoss = 0; } - if (stopLoss < MIN_STOP_LOSS_VALUE) { - stopLoss = MIN_STOP_LOSS_VALUE + if (strategyStage === 'Open Stage' && openStage !== undefined) { + if (openStage.initialDefinition !== undefined) { + if (openStage.initialDefinition.stopLoss !== undefined) { + phase = openStage.initialDefinition.stopLoss.phases[stopLossPhase - 1]; + } + } } + if (strategyStage === 'Manage Stage' && manageStage !== undefined) { + if (manageStage.stopLoss !== undefined) { + phase = manageStage.stopLoss.phases[stopLossPhase - 2]; + } + } + + if (phase.formula !== undefined) { + try { + stopLoss = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. + } catch (err) { + phase.formula.error = err.message + } + if (isNaN(stopLoss)) { stopLoss = 0; } + if (stopLoss < MIN_STOP_LOSS_VALUE) { + stopLoss = MIN_STOP_LOSS_VALUE + } + } } /* Take Profit Management */ @@ -622,7 +665,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkTakeProfitPhases() { - let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; + let strategy = tradingSystem.strategies[currentStrategyIndex]; let phase = strategy.takeProfit.phases[takeProfitPhase - 1]; for (let k = 0; k < phase.situations.length; k++) { @@ -651,7 +694,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function calculateTakeProfit() { - let strategy = tradingSystem.strategies[currentStrategyNumber - 1]; + let strategy = tradingSystem.strategies[currentStrategyIndex]; let phase = strategy.takeProfit.phases[takeProfitPhase - 1]; try { @@ -770,7 +813,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { addRecord(); - currentStrategyNumber = 0; + currentStrategyIndex = 0; stopLoss = 0; positionRate = 0; positionSize = 0; @@ -879,7 +922,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { anualizedRateOfReturn: anualizedRateOfReturn, positionRate: positionRate, lastProfitPercent: lastProfitPercent, - strategy: currentStrategyNumber, + strategy: currentStrategyIndex, strategyStage: strategyStage, takeProfit: takeProfit, stopLossPhase: stopLossPhase, @@ -896,7 +939,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Prepare the information for the Conditions File */ - conditionsArrayRecord.push(currentStrategyNumber); + conditionsArrayRecord.push(currentStrategyIndex); conditionsArrayRecord.push(strategyStage); conditionsArrayRecord.push(stopLossPhase); conditionsArrayRecord.push(takeProfitPhase); From 2f6d1d98ea925dfa979870b2b67e8d035b81949a Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 10:23:06 +0200 Subject: [PATCH 105/244] checkTakeProfitPhases re implemented --- Commons.js | 72 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 14 deletions(-) diff --git a/Commons.js b/Commons.js index 69c652b46..7d823b35f 100644 --- a/Commons.js +++ b/Commons.js @@ -666,7 +666,35 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function checkTakeProfitPhases() { let strategy = tradingSystem.strategies[currentStrategyIndex]; - let phase = strategy.takeProfit.phases[takeProfitPhase - 1]; + + let openStage = strategy.openStage + let manageStage = strategy.manageStage + let parentNode + let j = currentStrategyIndex + let stageKey + let initialDefinitionKey = '' + let p + + if (strategyStage === 'Open Stage' && openStage !== undefined) { + if (openStage.initialDefinition !== undefined) { + if (openStage.initialDefinition.takeProfit !== undefined) { + parentNode = openStage.initialDefinition + initialDefinitionKey = '-' + 'initialDefinition' + stageKey = 'openStage' + p = takeProfitPhase - 1 + } + } + } + + if (strategyStage === 'Manage Stage' && manageStage !== undefined) { + if (manageStage.takeProfit !== undefined) { + parentNode = manageStage + stageKey = 'manageStage' + p = takeProfitPhase - 2 + } + } + + let phase = parentNode.takeProfit.phases[p]; for (let k = 0; k < phase.situations.length; k++) { @@ -676,7 +704,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { for (let m = 0; m < situation.conditions.length; m++) { let condition = situation.conditions[m]; - let key = strategy.name + '-' + phase.name + '-' + situation.name + '-' + condition.name + let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; let value = conditions.get(key).value; @@ -692,25 +720,41 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - function calculateTakeProfit() { + function calculateTakeProfitLoss() { let strategy = tradingSystem.strategies[currentStrategyIndex]; - let phase = strategy.takeProfit.phases[takeProfitPhase - 1]; + let openStage = strategy.openStage + let manageStage = strategy.manageStage + let phase - try { - takeProfit = eval(phase.code); // Here is where we apply the formula given for the buy order at this phase. - } catch (err) { - /* - If the code produces an exception, we are covered. - */ + if (strategyStage === 'Open Stage' && openStage !== undefined) { + if (openStage.initialDefinition !== undefined) { + if (openStage.initialDefinition.takeProfit !== undefined) { + phase = openStage.initialDefinition.takeProfit.phases[takeProfitPhase - 1]; + } + } } - if (isNaN(takeProfit)) { takeProfit = 0; } - if (takeProfit < MIN_TAKE_PROFIT_VALUE) { - takeProfit = MIN_TAKE_PROFIT_VALUE + + if (strategyStage === 'Manage Stage' && manageStage !== undefined) { + if (manageStage.takeProfit !== undefined) { + phase = manageStage.takeProfit.phases[takeProfitPhase - 2]; + } + } + + if (phase.formula !== undefined) { + try { + takeProfit = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. + } catch (err) { + phase.formula.error = err.message + } + if (isNaN(takeProfit)) { takeProfit = 0; } + if (takeProfit < MIN_TAKE_PROFIT_VALUE) { + takeProfit = MIN_TAKE_PROFIT_VALUE + } } } - /* Entering into a Trade */ + /* Taking a Position */ if (strategyStage === 'Open Stage') { From 9093b2e7437e1aa51ad7f181f8c047b46647c11f Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 10:29:22 +0200 Subject: [PATCH 106/244] Condition.code.code --- Commons.js | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/Commons.js b/Commons.js index 7d823b35f..260b23b35 100644 --- a/Commons.js +++ b/Commons.js @@ -1112,7 +1112,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let condition = situation.conditions[m]; let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; - newCondition(key, condition.code); + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } } } } @@ -1128,7 +1130,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let condition = situation.conditions[m]; let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; - newCondition(key, condition.code); + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } } } } @@ -1144,7 +1148,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let condition = situation.conditions[m]; let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; - newCondition(key, condition.code); + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } } } } @@ -1173,7 +1179,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let condition = situation.conditions[m]; let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; - newCondition(key, condition.code); + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } } } } @@ -1194,7 +1202,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let condition = situation.conditions[m]; let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; - newCondition(key, condition.code); + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } } } } @@ -1221,7 +1231,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let condition = situation.conditions[m]; let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; - newCondition(key, condition.code); + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } } } } @@ -1242,7 +1254,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let condition = situation.conditions[m]; let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; - newCondition(key, condition.code); + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } } } } From de491e6004c188bcd22edb9fd0ee44856f51e2c7 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 11:40:56 +0200 Subject: [PATCH 107/244] takeProfitStage and stopLossStage introduced --- Commons.js | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/Commons.js b/Commons.js index 260b23b35..55017b73c 100644 --- a/Commons.js +++ b/Commons.js @@ -90,6 +90,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let previousStopLoss = 0; let stopLoss = 0; let stopLossPhase = 0; + let stopLossStage = 'No Stage'; /* Take Profit Management */ @@ -97,6 +98,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let previousTakeProfit = 0; let takeProfit = 0; let takeProfitPhase = 0; + let takeProfitStage = 'No Stage'; /* Simulation Records */ @@ -111,6 +113,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let anualizedRateOfReturn = 0; let type = '""'; let marketRate = 0; + let takePositionNow = false /* In some cases we need to know if we are positioned at the last candle of the calendar day, for that we need thse variables. */ @@ -468,10 +471,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { type = '"Sell"'; strategyStage = 'Open Stage'; + stopLossStage = 'Open Stage'; + takeProfitStage = 'Open Stage'; stopLossPhase = 1; takeProfitPhase = 1; currentTrade.begin = candle.begin; currentTrade.beginRate = candle.close; + takePositionNow = true return; } } @@ -507,6 +513,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { marketRate = stopLoss; type = '"Buy@StopLoss"'; strategyStage = 'Close Stage'; + stopLossStage = 'No Stage'; + takeProfitStage = 'No Stage'; currentTrade.end = candle.end; currentTrade.status = 1; currentTrade.exitType = 1; @@ -536,6 +544,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { marketRate = takeProfit; type = '"Buy@TakeProfit"'; strategyStage = 'Close Stage'; + stopLossStage = 'No Stage'; + takeProfitStage = 'No Stage'; currentTrade.end = candle.end; currentTrade.status = 1; currentTrade.exitType = 2; @@ -572,7 +582,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let initialDefinitionKey = '' let p - if (strategyStage === 'Open Stage' && openStage !== undefined) { + if (stopLossStage === 'Open Stage' && openStage !== undefined) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.stopLoss !== undefined) { parentNode = openStage.initialDefinition @@ -583,7 +593,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - if (strategyStage === 'Manage Stage' && manageStage !== undefined) { + if (stopLossStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.stopLoss !== undefined) { parentNode = manageStage stageKey = 'manageStage' @@ -611,7 +621,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (passed) { stopLossPhase++; - + stopLossStage = 'Manage Stage' + if (takeProfitPhase > 1) { strategyStage = 'Manage Stage'} return; } } @@ -624,7 +635,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let manageStage = strategy.manageStage let phase - if (strategyStage === 'Open Stage' && openStage !== undefined) { + if (stopLossStage === 'Open Stage' && openStage !== undefined) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.stopLoss !== undefined) { phase = openStage.initialDefinition.stopLoss.phases[stopLossPhase - 1]; @@ -632,7 +643,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - if (strategyStage === 'Manage Stage' && manageStage !== undefined) { + if (stopLossStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.stopLoss !== undefined) { phase = manageStage.stopLoss.phases[stopLossPhase - 2]; } @@ -675,7 +686,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let initialDefinitionKey = '' let p - if (strategyStage === 'Open Stage' && openStage !== undefined) { + if (takeProfitStage === 'Open Stage' && openStage !== undefined) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.takeProfit !== undefined) { parentNode = openStage.initialDefinition @@ -686,7 +697,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - if (strategyStage === 'Manage Stage' && manageStage !== undefined) { + if (takeProfitStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.takeProfit !== undefined) { parentNode = manageStage stageKey = 'manageStage' @@ -714,7 +725,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (passed) { takeProfitPhase++; - + takeProfitStage = 'Manage Stage' + if (stopLossPhase > 1) { strategyStage = 'Manage Stage' } return; } } @@ -727,7 +739,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let manageStage = strategy.manageStage let phase - if (strategyStage === 'Open Stage' && openStage !== undefined) { + if (takeProfitStage === 'Open Stage' && openStage !== undefined) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.takeProfit !== undefined) { phase = openStage.initialDefinition.takeProfit.phases[takeProfitPhase - 1]; @@ -735,7 +747,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - if (strategyStage === 'Manage Stage' && manageStage !== undefined) { + if (takeProfitStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.takeProfit !== undefined) { phase = manageStage.takeProfit.phases[takeProfitPhase - 2]; } @@ -756,7 +768,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Taking a Position */ - if (strategyStage === 'Open Stage') { + if ( + takePositionNow === true + ) { marketRate = candle.close; positionRate = marketRate; @@ -787,13 +801,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - addRecord(); - strategyStage = 'Manage Stage'; + addRecord(); continue; } - /* Exiting a Trade */ + /* Closing a Position */ if (strategyStage === 'Close Stage') { @@ -864,6 +877,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { positionInstant = undefined; takeProfit = 0; strategyStage = 'No Stage'; + stopLossStage = 'No Stage'; + takeProfitStage = 'No Stage'; stopLossPhase = 0; takeProfitPhase = 0; continue; From 1a9bfddbe002964a62f313716761dd30a0f91395 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 11:56:24 +0200 Subject: [PATCH 108/244] Ready to Debug --- Commons.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Commons.js b/Commons.js index 55017b73c..bca088d35 100644 --- a/Commons.js +++ b/Commons.js @@ -801,7 +801,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - addRecord(); continue; } From 6a8ad059cae2408740dfb7550be16104067e3930 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 12:15:37 +0200 Subject: [PATCH 109/244] moving functions where they have execution context --- Commons.js | 409 +++++++++++++++++++++++++++-------------------------- 1 file changed, 205 insertions(+), 204 deletions(-) diff --git a/Commons.js b/Commons.js index bca088d35..eb9364163 100644 --- a/Commons.js +++ b/Commons.js @@ -323,6 +323,211 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { evaluateConditions(tradingSystem, conditions); + function evaluateConditions(tradingSystem, conditions) { + + for (let j = 0; j < tradingSystem.strategies.length; j++) { + + let strategy = tradingSystem.strategies[j]; + + let triggerStage = strategy.triggerStage + + if (triggerStage !== undefined) { + + if (triggerStage.triggerOn !== undefined) { + + for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { + + let situation = triggerStage.triggerOn.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; + + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } + } + } + } + + if (triggerStage.triggerOff !== undefined) { + + for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { + + let situation = triggerStage.triggerOff.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; + + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } + } + } + } + + if (triggerStage.takePosition !== undefined) { + + for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { + + let situation = triggerStage.takePosition.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; + + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } + } + } + } + } + + let openStage = strategy.openStage + + if (openStage !== undefined) { + + let initialDefinition = openStage.initialDefinition + + if (initialDefinition !== undefined) { + + if (initialDefinition.stopLoss !== undefined) { + + for (let p = 0; p < initialDefinition.stopLoss.phases.length; p++) { + + let phase = initialDefinition.stopLoss.phases[p]; + + for (let k = 0; k < phase.situations.length; k++) { + + let situation = phase.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; + + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } + } + } + } + } + + if (initialDefinition.takeProfit !== undefined) { + + for (let p = 0; p < initialDefinition.takeProfit.phases.length; p++) { + + let phase = initialDefinition.takeProfit.phases[p]; + + for (let k = 0; k < phase.situations.length; k++) { + + let situation = phase.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; + + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } + } + } + } + } + } + } + + let manageStage = strategy.manageStage + + if (manageStage !== undefined) { + + if (manageStage.stopLoss !== undefined) { + + for (let p = 0; p < manageStage.stopLoss.phases.length; p++) { + + let phase = manageStage.stopLoss.phases[p]; + + for (let k = 0; k < phase.situations.length; k++) { + + let situation = phase.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; + + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } + } + } + } + } + + if (manageStage.takeProfit !== undefined) { + + for (let p = 0; p < manageStage.takeProfit.phases.length; p++) { + + let phase = manageStage.takeProfit.phases[p]; + + for (let k = 0; k < phase.situations.length; k++) { + + let situation = phase.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; + + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } + } + } + } + } + } + } + + function newCondition(key, code) { + + let condition; + let value = false; + + try { + value = eval(code); + } catch (err) { + /* + One possible error is that the conditions references a .previous that is undefined. For this + reason and others, we will simply set the value to false. + */ + value = false + } + + condition = { + key: key, + value: value + }; + + conditions.set(condition.key, condition); + + if (condition.value) { + conditionsArrayValues.push(1); + } else { + conditionsArrayValues.push(0); + } + } + + } + + if ( strategyStage === 'No Stage' && currentStrategyIndex === 0 && @@ -1105,210 +1310,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - function evaluateConditions(tradingSystem, conditions) { - - for (let j = 0; j < tradingSystem.strategies.length; j++) { - - let strategy = tradingSystem.strategies[j]; - - let triggerStage = strategy.triggerStage - - if (triggerStage !== undefined) { - - if (triggerStage.triggerOn !== undefined) { - - for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { - - let situation = triggerStage.triggerOn.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; - - if (condition.code !== undefined) { - newCondition(key, condition.code.code); - } - } - } - } - - if (triggerStage.triggerOff !== undefined) { - - for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { - - let situation = triggerStage.triggerOff.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; - - if (condition.code !== undefined) { - newCondition(key, condition.code.code); - } - } - } - } - - if (triggerStage.takePosition !== undefined) { - - for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { - - let situation = triggerStage.takePosition.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; - - if (condition.code !== undefined) { - newCondition(key, condition.code.code); - } - } - } - } - } - - let openStage = strategy.openStage - - if (openStage !== undefined) { - - let initialDefinition = openStage.initialDefinition - - if (initialDefinition !== undefined) { - - if (initialDefinition.stopLoss !== undefined) { - - for (let p = 0; p < initialDefinition.stopLoss.phases.length; p++) { - - let phase = initialDefinition.stopLoss.phases[p]; - - for (let k = 0; k < phase.situations.length; k++) { - - let situation = phase.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; - - if (condition.code !== undefined) { - newCondition(key, condition.code.code); - } - } - } - } - } - - if (initialDefinition.takeProfit !== undefined) { - - for (let p = 0; p < initialDefinition.takeProfit.phases.length; p++) { - - let phase = initialDefinition.takeProfit.phases[p]; - - for (let k = 0; k < phase.situations.length; k++) { - - let situation = phase.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; - - if (condition.code !== undefined) { - newCondition(key, condition.code.code); - } - } - } - } - } - } - } - - let manageStage = strategy.manageStage - - if (manageStage !== undefined) { - - if (manageStage.stopLoss !== undefined) { - - for (let p = 0; p < manageStage.stopLoss.phases.length; p++) { - - let phase = manageStage.stopLoss.phases[p]; - - for (let k = 0; k < phase.situations.length; k++) { - - let situation = phase.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; - - if (condition.code !== undefined) { - newCondition(key, condition.code.code); - } - } - } - } - } - - if (manageStage.takeProfit !== undefined) { - - for (let p = 0; p < manageStage.takeProfit.phases.length; p++) { - - let phase = manageStage.takeProfit.phases[p]; - - for (let k = 0; k < phase.situations.length; k++) { - - let situation = phase.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; - - if (condition.code !== undefined) { - newCondition(key, condition.code.code); - } - } - } - } - } - } - } - - function newCondition(key, code) { - - let condition; - let value = false; - - try { - value = eval(code); - } catch (err) { - /* - One possible error is that the conditions references a .previous that is undefined. For this - reason and others, we will simply set the value to false. - */ - value = false - } - - condition = { - key: key, - value: value - }; - - conditions.set(condition.key, condition); - - if (condition.value) { - conditionsArrayValues.push(1); - } else { - conditionsArrayValues.push(0); - } - } - - } - function buildLRC(dataFile, callBackFunction) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildLRC -> Entering function."); } From d00721f7110de70f0941d20c92869c65307548ec Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 12:23:20 +0200 Subject: [PATCH 110/244] getting ready to send errors to plotter --- Commons.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index eb9364163..a1372b3a3 100644 --- a/Commons.js +++ b/Commons.js @@ -500,6 +500,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let condition; let value = false; + let error = '' try { value = eval(code); @@ -509,11 +510,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { reason and others, we will simply set the value to false. */ value = false + error = err.message } condition = { key: key, - value: value + value: value, + error: error }; conditions.set(condition.key, condition); From bff336dc4d8c9171beb637f2dcb5c257f6dd5869 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 13:08:58 +0200 Subject: [PATCH 111/244] nextPhaseEvent --- Commons.js | 72 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/Commons.js b/Commons.js index a1372b3a3..7fe3be8a8 100644 --- a/Commons.js +++ b/Commons.js @@ -402,17 +402,21 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let phase = initialDefinition.stopLoss.phases[p]; - for (let k = 0; k < phase.situations.length; k++) { + let nextPhaseEvent = phase.nextPhaseEvent; + if (nextPhaseEvent !== undefined) { - let situation = phase.situations[k]; + for (let k = 0; k < nextPhaseEvent.situations.length; k++) { - for (let m = 0; m < situation.conditions.length; m++) { + let situation = nextPhaseEvent.situations[k]; - let condition = situation.conditions[m]; - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; + for (let m = 0; m < situation.conditions.length; m++) { - if (condition.code !== undefined) { - newCondition(key, condition.code.code); + let condition = situation.conditions[m]; + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; + + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } } } } @@ -425,17 +429,21 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let phase = initialDefinition.takeProfit.phases[p]; - for (let k = 0; k < phase.situations.length; k++) { + let nextPhaseEvent = phase.nextPhaseEvent; + if (nextPhaseEvent !== undefined) { - let situation = phase.situations[k]; + for (let k = 0; k < nextPhaseEvent.situations.length; k++) { - for (let m = 0; m < situation.conditions.length; m++) { + let situation = nextPhaseEvent.situations[k]; - let condition = situation.conditions[m]; - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; + for (let m = 0; m < situation.conditions.length; m++) { - if (condition.code !== undefined) { - newCondition(key, condition.code.code); + let condition = situation.conditions[m]; + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; + + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } } } } @@ -454,17 +462,21 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let phase = manageStage.stopLoss.phases[p]; - for (let k = 0; k < phase.situations.length; k++) { + let nextPhaseEvent = phase.nextPhaseEvent; + if (nextPhaseEvent !== undefined) { - let situation = phase.situations[k]; + for (let k = 0; k < nextPhaseEvent.situations.length; k++) { - for (let m = 0; m < situation.conditions.length; m++) { + let situation = nextPhaseEvent.situations[k]; - let condition = situation.conditions[m]; - let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; + for (let m = 0; m < situation.conditions.length; m++) { - if (condition.code !== undefined) { - newCondition(key, condition.code.code); + let condition = situation.conditions[m]; + let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; + + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } } } } @@ -477,17 +489,21 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let phase = manageStage.takeProfit.phases[p]; - for (let k = 0; k < phase.situations.length; k++) { + let nextPhaseEvent = phase.nextPhaseEvent; + if (nextPhaseEvent !== undefined) { - let situation = phase.situations[k]; + for (let k = 0; k < nextPhaseEvent.situations.length; k++) { - for (let m = 0; m < situation.conditions.length; m++) { + let situation = nextPhaseEvent.situations[k]; - let condition = situation.conditions[m]; - let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; + for (let m = 0; m < situation.conditions.length; m++) { - if (condition.code !== undefined) { - newCondition(key, condition.code.code); + let condition = situation.conditions[m]; + let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; + + if (condition.code !== undefined) { + newCondition(key, condition.code.code); + } } } } From 2402c1809eadc649d1621d16efe390b66b2c6bb1 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 13:39:43 +0200 Subject: [PATCH 112/244] removing unnecesary nestled functions --- Commons.js | 148 ++++++++++++++++++++++++----------------------------- 1 file changed, 66 insertions(+), 82 deletions(-) diff --git a/Commons.js b/Commons.js index 7fe3be8a8..4dac7e25a 100644 --- a/Commons.js +++ b/Commons.js @@ -566,44 +566,39 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { */ - checkTriggerOn(); + for (let j = 0; j < tradingSystem.strategies.length; j++) { - function checkTriggerOn() { + let strategy = tradingSystem.strategies[j]; - for (let j = 0; j < tradingSystem.strategies.length; j++) { + let triggerStage = strategy.triggerStage - let strategy = tradingSystem.strategies[j]; + if (triggerStage !== undefined) { - let triggerStage = strategy.triggerStage + if (triggerStage.triggerOn !== undefined) { - if (triggerStage !== undefined) { + for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { - if (triggerStage.triggerOn !== undefined) { + let situation = triggerStage.triggerOn.situations[k]; + let passed = true; - for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { + for (let m = 0; m < situation.conditions.length; m++) { - let situation = triggerStage.triggerOn.situations[k]; - let passed = true; + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; - for (let m = 0; m < situation.conditions.length; m++) { + let value = conditions.get(key).value; - let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; + if (value === false) { passed = false; } + } - let value = conditions.get(key).value; + if (passed) { - if (value === false) { passed = false; } - } - - if (passed) { - - strategyStage = 'Trigger Stage'; - currentStrategyIndex = j; - currentStrategy.begin = candle.begin; - currentStrategy.beginRate = candle.min; - currentStrategy.endRate = candle.min; // In case the strategy does not get exited - return; - } + strategyStage = 'Trigger Stage'; + currentStrategyIndex = j; + currentStrategy.begin = candle.begin; + currentStrategy.beginRate = candle.min; + currentStrategy.endRate = candle.min; // In case the strategy does not get exited + break; } } } @@ -615,44 +610,38 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (strategyStage === 'Trigger Stage') { - checkTriggerOff(); + let strategy = tradingSystem.strategies[currentStrategyIndex]; - function checkTriggerOff() { + let triggerStage = strategy.triggerStage - let strategy = tradingSystem.strategies[currentStrategyIndex]; + if (triggerStage !== undefined) { - let triggerStage = strategy.triggerStage + if (triggerStage.triggerOff !== undefined) { - if (triggerStage !== undefined) { + for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { - if (triggerStage.triggerOff !== undefined) { + let situation = triggerStage.triggerOff.situations[k]; + let passed = true; - for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { + for (let m = 0; m < situation.conditions.length; m++) { - let situation = triggerStage.triggerOff.situations[k]; - let passed = true; + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; - for (let m = 0; m < situation.conditions.length; m++) { + let value = conditions.get(key).value; - let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; + if (value === false) { passed = false; } + } - let value = conditions.get(key).value; + if (passed) { - if (value === false) { passed = false; } - } - - if (passed) { - - currentStrategy.number = currentStrategyIndex - currentStrategy.end = candle.end; - currentStrategy.endRate = candle.min; - currentStrategy.status = 1; - strategyStage = 'No Stage'; - currentStrategyIndex = 0; - - return; - } + currentStrategy.number = currentStrategyIndex + currentStrategy.end = candle.end; + currentStrategy.endRate = candle.min; + currentStrategy.status = 1; + strategyStage = 'No Stage'; + currentStrategyIndex = 0; + break; } } } @@ -663,47 +652,42 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (strategyStage === 'Trigger Stage') { - checkTakePosition(); + let strategy = tradingSystem.strategies[currentStrategyIndex]; - function checkTakePosition() { + let triggerStage = strategy.triggerStage - let strategy = tradingSystem.strategies[currentStrategyIndex]; + if (triggerStage !== undefined) { - let triggerStage = strategy.triggerStage + if (triggerStage.takePosition !== undefined) { - if (triggerStage !== undefined) { + for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { - if (triggerStage.takePosition !== undefined) { + let situation = triggerStage.takePosition.situations[k]; + let passed = true; - for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { + for (let m = 0; m < situation.conditions.length; m++) { - let situation = triggerStage.takePosition.situations[k]; - let passed = true; + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; - for (let m = 0; m < situation.conditions.length; m++) { + let value = conditions.get(key).value; - let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; + if (value === false) { passed = false; } + } - let value = conditions.get(key).value; + if (passed) { - if (value === false) { passed = false; } - } + type = '"Sell"'; - if (passed) { - - type = '"Sell"'; - - strategyStage = 'Open Stage'; - stopLossStage = 'Open Stage'; - takeProfitStage = 'Open Stage'; - stopLossPhase = 1; - takeProfitPhase = 1; - currentTrade.begin = candle.begin; - currentTrade.beginRate = candle.close; - takePositionNow = true - return; - } + strategyStage = 'Open Stage'; + stopLossStage = 'Open Stage'; + takeProfitStage = 'Open Stage'; + stopLossPhase = 1; + takeProfitPhase = 1; + currentTrade.begin = candle.begin; + currentTrade.beginRate = candle.close; + takePositionNow = true + break; } } } From e07323382f69202a4d6501f8345475535be8eb97 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 13:45:22 +0200 Subject: [PATCH 113/244] Bug Fixed on Trigger Off --- Commons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index 4dac7e25a..1b39dc9a9 100644 --- a/Commons.js +++ b/Commons.js @@ -626,7 +626,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { for (let m = 0; m < situation.conditions.length; m++) { let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; + let key = currentStrategyIndex + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; let value = conditions.get(key).value; From 2ec63a94fafd6dc01159a5a3cd4179ddd9952c44 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 13:47:52 +0200 Subject: [PATCH 114/244] bug at take position --- Commons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index 1b39dc9a9..875e715c2 100644 --- a/Commons.js +++ b/Commons.js @@ -668,7 +668,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { for (let m = 0; m < situation.conditions.length; m++) { let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; + let key = currentStrategyIndex + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; let value = conditions.get(key).value; From 3a9c5c82f01dbbdf6378196e0c19f800f1ecf70d Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 13:53:09 +0200 Subject: [PATCH 115/244] repositioning Take Position function --- Commons.js | 92 +++++++++++++++++++++++++++--------------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/Commons.js b/Commons.js index 875e715c2..551c711ee 100644 --- a/Commons.js +++ b/Commons.js @@ -648,52 +648,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - /* Take Position Condition */ - - if (strategyStage === 'Trigger Stage') { - - let strategy = tradingSystem.strategies[currentStrategyIndex]; - - let triggerStage = strategy.triggerStage - - if (triggerStage !== undefined) { - - if (triggerStage.takePosition !== undefined) { - - for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { - - let situation = triggerStage.takePosition.situations[k]; - let passed = true; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = currentStrategyIndex + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; - - let value = conditions.get(key).value; - - if (value === false) { passed = false; } - } - - if (passed) { - - type = '"Sell"'; - - strategyStage = 'Open Stage'; - stopLossStage = 'Open Stage'; - takeProfitStage = 'Open Stage'; - stopLossPhase = 1; - takeProfitPhase = 1; - currentTrade.begin = candle.begin; - currentTrade.beginRate = candle.close; - takePositionNow = true - break; - } - } - } - } - } - /* Checking if Stop or Take Profit were hit */ if ( @@ -766,6 +720,52 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } + /* Take Position Condition */ + + if (strategyStage === 'Trigger Stage') { + + let strategy = tradingSystem.strategies[currentStrategyIndex]; + + let triggerStage = strategy.triggerStage + + if (triggerStage !== undefined) { + + if (triggerStage.takePosition !== undefined) { + + for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { + + let situation = triggerStage.takePosition.situations[k]; + let passed = true; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = currentStrategyIndex + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; + + let value = conditions.get(key).value; + + if (value === false) { passed = false; } + } + + if (passed) { + + type = '"Sell"'; + + strategyStage = 'Open Stage'; + stopLossStage = 'Open Stage'; + takeProfitStage = 'Open Stage'; + stopLossPhase = 1; + takeProfitPhase = 1; + currentTrade.begin = candle.begin; + currentTrade.beginRate = candle.close; + takePositionNow = true + break; + } + } + } + } + } + /* Stop Loss Management */ if ( From ac588ce1135a9de25a36ad87db4e4f78cc6234da Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 16:00:10 +0200 Subject: [PATCH 116/244] missing nextPhaseEvent --- Commons.js | 64 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/Commons.js b/Commons.js index 551c711ee..1cc2d0f98 100644 --- a/Commons.js +++ b/Commons.js @@ -811,27 +811,31 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let phase = parentNode.stopLoss.phases[p]; - for (let k = 0; k < phase.situations.length; k++) { + let nextPhaseEvent = phase.nextPhaseEvent; + if (nextPhaseEvent !== undefined) { - let situation = phase.situations[k]; - let passed = true; + for (let k = 0; k < nextPhaseEvent.situations.length; k++) { - for (let m = 0; m < situation.conditions.length; m++) { + let situation = nextPhaseEvent.situations[k]; + let passed = true; - let condition = situation.conditions[m]; - let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; + for (let m = 0; m < situation.conditions.length; m++) { - let value = conditions.get(key).value; + let condition = situation.conditions[m]; + let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; - if (value === false) { passed = false; } - } + let value = conditions.get(key).value; - if (passed) { + if (value === false) { passed = false; } + } - stopLossPhase++; - stopLossStage = 'Manage Stage' - if (takeProfitPhase > 1) { strategyStage = 'Manage Stage'} - return; + if (passed) { + + stopLossPhase++; + stopLossStage = 'Manage Stage' + if (takeProfitPhase > 1) { strategyStage = 'Manage Stage' } + return; + } } } } @@ -915,27 +919,31 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let phase = parentNode.takeProfit.phases[p]; - for (let k = 0; k < phase.situations.length; k++) { + let nextPhaseEvent = phase.nextPhaseEvent; + if (nextPhaseEvent !== undefined) { - let situation = phase.situations[k]; - let passed = true; + for (let k = 0; k < nextPhaseEvent.situations.length; k++) { - for (let m = 0; m < situation.conditions.length; m++) { + let situation = nextPhaseEvent.situations[k]; + let passed = true; - let condition = situation.conditions[m]; - let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; + for (let m = 0; m < situation.conditions.length; m++) { - let value = conditions.get(key).value; + let condition = situation.conditions[m]; + let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; - if (value === false) { passed = false; } - } + let value = conditions.get(key).value; - if (passed) { + if (value === false) { passed = false; } + } - takeProfitPhase++; - takeProfitStage = 'Manage Stage' - if (stopLossPhase > 1) { strategyStage = 'Manage Stage' } - return; + if (passed) { + + takeProfitPhase++; + takeProfitStage = 'Manage Stage' + if (stopLossPhase > 1) { strategyStage = 'Manage Stage' } + return; + } } } } From 41f7bbe33ccbfc3a88a84464bb40ac0391d4289e Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 16:16:32 +0200 Subject: [PATCH 117/244] calculateTakeProfit bug --- Commons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index 1cc2d0f98..a80be565b 100644 --- a/Commons.js +++ b/Commons.js @@ -948,7 +948,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - function calculateTakeProfitLoss() { + function calculateTakeProfit() { let strategy = tradingSystem.strategies[currentStrategyIndex]; let openStage = strategy.openStage From c9df7ab3146345a90075fc85868529b41c589a67 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 16:43:00 +0200 Subject: [PATCH 118/244] takePositionNow BUG --- Commons.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Commons.js b/Commons.js index a80be565b..8ebe8458a 100644 --- a/Commons.js +++ b/Commons.js @@ -861,6 +861,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } + if (phase === undefined) { + console.log('O AQUI ES') + } + if (phase.formula !== undefined) { try { stopLoss = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. @@ -969,6 +973,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } + if (phase === undefined) { + console.log('AQUI ES') + } + if (phase.formula !== undefined) { try { takeProfit = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. @@ -987,6 +995,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if ( takePositionNow === true ) { + takePositionNow = false marketRate = candle.close; positionRate = marketRate; From 8ef0f8f1279bf58943f0587812fa6ced2281f110 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 16:45:50 +0200 Subject: [PATCH 119/244] It is running! --- Commons.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Commons.js b/Commons.js index 8ebe8458a..115012afd 100644 --- a/Commons.js +++ b/Commons.js @@ -861,10 +861,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - if (phase === undefined) { - console.log('O AQUI ES') - } - if (phase.formula !== undefined) { try { stopLoss = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. @@ -973,10 +969,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - if (phase === undefined) { - console.log('AQUI ES') - } - if (phase.formula !== undefined) { try { takeProfit = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. From bf195f65a42d1b3220eeb1503daffde77d97442d Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 19:11:14 +0200 Subject: [PATCH 120/244] corrections for records file --- Multi-Period-Daily/User.Bot.js | 2 +- Multi-Period-Market/User.Bot.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 44991c675..d3fef5d04 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -162,7 +162,7 @@ record.positionRate + "," + record.lastProfitPercent + "," + record.strategy + "," + - "'" + record.strategyStage + "'" + "," + + '"' + record.strategyStage + '"' + "," + record.takeProfit + "," + record.stopLossPhase + "," + record.takeProfitPhase + "," + diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 28c80827a..7d9dc8670 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -160,7 +160,7 @@ record.positionRate + "," + record.lastProfitPercent + "," + record.strategy + "," + - "'" + record.strategyStage + "'" + "," + + '"' + record.strategyStage + '"' + "," + record.takeProfit + "," + record.stopLossPhase + "," + record.takeProfitPhase + "," + From c3f45350103725fb84a33046ac4c45d8332fcf88 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 19:20:03 +0200 Subject: [PATCH 121/244] Using Stage Number instead of text --- Commons.js | 24 ++++++++++++++++++++++-- Multi-Period-Daily/User.Bot.js | 2 +- Multi-Period-Market/User.Bot.js | 2 +- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/Commons.js b/Commons.js index 115012afd..90f83d756 100644 --- a/Commons.js +++ b/Commons.js @@ -1176,6 +1176,26 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { "") } + let strategyStageNumber + switch (strategyStage) { + case 'Trigger Stage': { + strategyStageNumber = 1 + break + } + case 'Open Stage': { + strategyStageNumber = 2 + break + } + case 'Manage Stage': { + strategyStageNumber = 3 + break + } + case 'Close Stage': { + strategyStageNumber = 4 + break + } + } + simulationRecord = { begin: candle.begin, end: candle.end, @@ -1198,7 +1218,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { positionRate: positionRate, lastProfitPercent: lastProfitPercent, strategy: currentStrategyIndex, - strategyStage: strategyStage, + strategyStageNumber: strategyStageNumber, takeProfit: takeProfit, stopLossPhase: stopLossPhase, takeProfitPhase: takeProfitPhase, @@ -1215,7 +1235,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Prepare the information for the Conditions File */ conditionsArrayRecord.push(currentStrategyIndex); - conditionsArrayRecord.push(strategyStage); + conditionsArrayRecord.push(strategyStageNumber); conditionsArrayRecord.push(stopLossPhase); conditionsArrayRecord.push(takeProfitPhase); conditionsArrayRecord.push(conditionsArrayValues); diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index d3fef5d04..68ce0df4e 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -162,7 +162,7 @@ record.positionRate + "," + record.lastProfitPercent + "," + record.strategy + "," + - '"' + record.strategyStage + '"' + "," + + record.strategyStageNumber + "," + record.takeProfit + "," + record.stopLossPhase + "," + record.takeProfitPhase + "," + diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 7d9dc8670..ac5a13578 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -160,7 +160,7 @@ record.positionRate + "," + record.lastProfitPercent + "," + record.strategy + "," + - '"' + record.strategyStage + '"' + "," + + record.strategyStageNumber + "," + record.takeProfit + "," + record.stopLossPhase + "," + record.takeProfitPhase + "," + From 8e1a8ef165d5639345b35d028159c7613f38b387 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 19:23:47 +0200 Subject: [PATCH 122/244] missing one --- Commons.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Commons.js b/Commons.js index 90f83d756..10b40ecfe 100644 --- a/Commons.js +++ b/Commons.js @@ -1178,6 +1178,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let strategyStageNumber switch (strategyStage) { + case 'No Stage': { + strategyStageNumber = 1 + break + } case 'Trigger Stage': { strategyStageNumber = 1 break From c52c81f6d083469d23ce040084900f1ce746e767 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 19:24:27 +0200 Subject: [PATCH 123/244] Update Commons.js --- Commons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index 10b40ecfe..fb9b46702 100644 --- a/Commons.js +++ b/Commons.js @@ -1179,7 +1179,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let strategyStageNumber switch (strategyStage) { case 'No Stage': { - strategyStageNumber = 1 + strategyStageNumber = 0 break } case 'Trigger Stage': { From 843f0ce046985dc0e1c53c2005471c47f10fe938 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 5 Jun 2019 21:13:34 +0200 Subject: [PATCH 124/244] Sending Formula and Condition Values to the Plotter --- Commons.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Commons.js b/Commons.js index fb9b46702..10fc39b22 100644 --- a/Commons.js +++ b/Commons.js @@ -345,7 +345,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; if (condition.code !== undefined) { - newCondition(key, condition.code.code); + newCondition(key, condition.code); } } } @@ -363,7 +363,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; if (condition.code !== undefined) { - newCondition(key, condition.code.code); + newCondition(key, condition.code); } } } @@ -381,7 +381,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; if (condition.code !== undefined) { - newCondition(key, condition.code.code); + newCondition(key, condition.code); } } } @@ -415,7 +415,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; if (condition.code !== undefined) { - newCondition(key, condition.code.code); + newCondition(key, condition.code); } } } @@ -442,7 +442,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; if (condition.code !== undefined) { - newCondition(key, condition.code.code); + newCondition(key, condition.code); } } } @@ -475,7 +475,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; if (condition.code !== undefined) { - newCondition(key, condition.code.code); + newCondition(key, condition.code); } } } @@ -502,7 +502,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; if (condition.code !== undefined) { - newCondition(key, condition.code.code); + newCondition(key, condition.code); } } } @@ -512,27 +512,25 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - function newCondition(key, code) { + function newCondition(key, node) { let condition; - let value = false; let error = '' try { - value = eval(code); + node.value = eval(node.code); } catch (err) { /* One possible error is that the conditions references a .previous that is undefined. For this reason and others, we will simply set the value to false. */ - value = false - error = err.message + node.value = false + node.error = err.message } condition = { key: key, - value: value, - error: error + value: node.value }; conditions.set(condition.key, condition); @@ -863,7 +861,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (phase.formula !== undefined) { try { - stopLoss = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. + phase.formula.value = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. + stopLoss = phase.formula.value } catch (err) { phase.formula.error = err.message } @@ -971,7 +970,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (phase.formula !== undefined) { try { - takeProfit = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. + phase.formula.value = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. + takeProfit = phase.formula.value } catch (err) { phase.formula.error = err.message } From 30f80afd82237e5d4ee1e4851fc525d55c689a8c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 6 Jun 2019 17:23:44 +0200 Subject: [PATCH 125/244] Receiving Parameters --- Commons.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Commons.js b/Commons.js index 10fc39b22..a3abcabc7 100644 --- a/Commons.js +++ b/Commons.js @@ -71,7 +71,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Entering function."); } - tradingSystem.strategies = await getStrategies(); + tradingSystem = await getTradingSystem(); /* Initial Values */ @@ -1586,7 +1586,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - async function getStrategies() { + async function getTradingSystem() { try { @@ -1622,7 +1622,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (strategizerResponse.data.errors) throw new Error(strategizerResponse.data.errors[0].message) - return strategizerResponse.data.data.strategizer_TradingSystemByFb.data.strategies; + return strategizerResponse.data.data.strategizer_TradingSystemByFb.data; } catch (error) { throw new Error('There has been an error getting the strategy to run on the simulator. Error: ' + error) From 296c3be178930f25a5ac9f9b33cf48cf53b5be31 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 7 Jun 2019 10:39:42 +0200 Subject: [PATCH 126/244] position Size implemented --- Commons.js | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/Commons.js b/Commons.js index a3abcabc7..21310273f 100644 --- a/Commons.js +++ b/Commons.js @@ -79,6 +79,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let initialBalanceA = 1; let minimunBalanceA = 0.5; + /* We overide the initial balance with whatever was set as position size */ + + + /* Strategy and Phases */ let currentStrategyIndex = 0; @@ -87,7 +91,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* 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. - let previousStopLoss = 0; let stopLoss = 0; let stopLossPhase = 0; let stopLossStage = 'No Stage'; @@ -989,12 +992,27 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { ) { takePositionNow = false + positionSize = balanceAssetA; // This is by default if no size was defined by the user + + let strategy = tradingSystem.strategies[currentStrategyIndex]; + let triggerStage = strategy.triggerStage + + if (triggerStage !== undefined) { + if (triggerStage.positionSize !== undefined) { + if (triggerStage.positionSize.formula !== undefined) { + try { + triggerStage.positionSize.formula.value = eval(triggerStage.positionSize.formula.code); + positionSize = phase.formula.value + } catch (err) { + triggerStage.positionSize.formula.error = err.message + } + if (isNaN(positionSize)) { positionSize = balanceAssetA; } + } + } + } + marketRate = candle.close; positionRate = marketRate; - positionSize = balanceAssetA; - - stopLoss = positionRate + positionRate * 1 / 100; - previousStopLoss = stopLoss; calculateStopLoss(); calculateTakeProfit(); @@ -1232,8 +1250,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { recordsArray.push(simulationRecord); - previousStopLoss = stopLoss; - type = '""'; /* Prepare the information for the Conditions File */ From 8dd9e273bdf91ca9bc0650ac35fc252094c49b9a Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 7 Jun 2019 10:56:07 +0200 Subject: [PATCH 127/244] Position Size Implemented --- Commons.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Commons.js b/Commons.js index 21310273f..10c65e51c 100644 --- a/Commons.js +++ b/Commons.js @@ -663,7 +663,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (candle.max >= stopLoss) { - balanceAssetA = balanceAssetB / stopLoss; + balanceAssetA = balanceAssetA + balanceAssetB / stopLoss; balanceAssetB = 0; if (currentDay !== undefined) { @@ -693,7 +693,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (candle.min <= takeProfit) { - balanceAssetA = balanceAssetB / takeProfit; + balanceAssetA = balanceAssetA + balanceAssetB / takeProfit; balanceAssetB = 0; if (currentDay !== undefined) { @@ -1021,8 +1021,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { lastProfit = 0; lastProfitPercent = 0; - balanceAssetB = balanceAssetA * marketRate; - balanceAssetA = 0; + balanceAssetB = balanceAssetB + positionSize * marketRate; + balanceAssetA = balanceAssetA - positionSize; positionInstant = candle.end; From f0b6cf112db14315afb4a8303d4474709a16edee Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 8 Jun 2019 06:28:01 +0200 Subject: [PATCH 128/244] Extracting Parameters from Base Asset --- Commons.js | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/Commons.js b/Commons.js index 10c65e51c..3a15b953c 100644 --- a/Commons.js +++ b/Commons.js @@ -73,15 +73,38 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { tradingSystem = await getTradingSystem(); - /* Initial Values */ + /* Initial Default Values */ let initialDate = startDate; let initialBalanceA = 1; let minimunBalanceA = 0.5; + let initialBalanceB = 0; + let minimunBalanceB = 0; + let baseAsset = 'BTC' - /* We overide the initial balance with whatever was set as position size */ - + /* Parameters Processing */ + if (tradingSystem.parameters !== undefined) { + if (tradingSystem.parameters.baseAsset !== undefined) { + if (tradingSystem.parameters.baseAsset.formula !== undefined) { + let receivedParameters + try { + receivedParameters = JSON.parse(tradingSystem.parameters.baseAsset.formula.code); + if (receivedParameters.initialBalance !== undefined) { + initialBalanceA = receivedParameters.initialBalance; + } + if (receivedParameters.minimunBalance !== undefined) { + minimunBalanceA = receivedParameters.minimunBalance; + } + if (receivedParameters.name !== undefined) { + baseAsset = receivedParameters.name; + } + } catch (err) { + tradingSystem.parameters.baseAsset.formula.error = err.message + } + } + } + } /* Strategy and Phases */ From aaab66d248be8b586fd5ebee67de165fade23957 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 8 Jun 2019 06:43:31 +0200 Subject: [PATCH 129/244] Processing Parameters working --- Commons.js | 58 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/Commons.js b/Commons.js index 3a15b953c..48cf4490a 100644 --- a/Commons.js +++ b/Commons.js @@ -75,11 +75,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Initial Default Values */ - let initialDate = startDate; - let initialBalanceA = 1; - let minimunBalanceA = 0.5; - let initialBalanceB = 0; - let minimunBalanceB = 0; + let initialDate = startDate; + + const DEFAULT_BASE_ASSET_BALANCE = 1 + const DEFAULT_BASE_ASSET_MINIMUN_BALANCE = 0.5 + let initialBalanceA + let minimunBalanceA + let initialBalanceB + let minimunBalanceB let baseAsset = 'BTC' /* Parameters Processing */ @@ -90,14 +93,45 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let receivedParameters try { receivedParameters = JSON.parse(tradingSystem.parameters.baseAsset.formula.code); - if (receivedParameters.initialBalance !== undefined) { - initialBalanceA = receivedParameters.initialBalance; - } - if (receivedParameters.minimunBalance !== undefined) { - minimunBalanceA = receivedParameters.minimunBalance; - } + if (receivedParameters.name !== undefined) { baseAsset = receivedParameters.name; + if (baseAsset !== 'BTC' && baseAsset !== 'USDT') { + tradingSystem.parameters.baseAsset.formula.error = 'The only supported assets so far are BTC and USDT. Using default BTC.' + baseAsset = 'BTC' + } + } + + if (baseAsset === 'BTC') { + if (receivedParameters.initialBalance !== undefined) { + initialBalanceA = receivedParameters.initialBalance; + initialBalanceB = 0 + } else { + initialBalanceA = DEFAULT_BASE_ASSET_BALANCE; + initialBalanceB = 0 + } + if (receivedParameters.minimunBalance !== undefined) { + minimunBalanceA = receivedParameters.minimunBalance; + minimunBalanceB = 0 + } else { + minimunBalanceA = DEFAULT_BASE_ASSET_MINIMUN_BALANCE; + minimunBalanceB = 0 + } + } else { + if (receivedParameters.initialBalance !== undefined) { + initialBalanceB = receivedParameters.initialBalance; + initialBalanceA = 0 + } else { + initialBalanceB = DEFAULT_BASE_ASSET_BALANCE; + initialBalanceA = 0 + } + if (receivedParameters.minimunBalance !== undefined) { + minimunBalanceB = receivedParameters.minimunBalance; + minimunBalanceA = 0 + } else { + minimunBalanceB = DEFAULT_BASE_ASSET_MINIMUN_BALANCE; + minimunBalanceA = 0 + } } } catch (err) { tradingSystem.parameters.baseAsset.formula.error = err.message @@ -184,7 +218,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { */ let balanceAssetA = initialBalanceA; - let balanceAssetB = 0; + let balanceAssetB = initialBalanceB; let lastProfit = 0; let profit = 0; From e8319ccda6032ef21e4dd4b032d728720d51b576 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 8 Jun 2019 07:03:03 +0200 Subject: [PATCH 130/244] Upgrading Check of Minimun Balance --- Commons.js | 89 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 38 deletions(-) diff --git a/Commons.js b/Commons.js index 48cf4490a..fc6d3f9c6 100644 --- a/Commons.js +++ b/Commons.js @@ -79,10 +79,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { const DEFAULT_BASE_ASSET_BALANCE = 1 const DEFAULT_BASE_ASSET_MINIMUN_BALANCE = 0.5 - let initialBalanceA - let minimunBalanceA - let initialBalanceB - let minimunBalanceB + let initialBalanceA = DEFAULT_BASE_ASSET_BALANCE + let minimunBalanceA = DEFAULT_BASE_ASSET_MINIMUN_BALANCE + let initialBalanceB = 0 + let minimunBalanceB = 0 let baseAsset = 'BTC' /* Parameters Processing */ @@ -142,7 +142,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Strategy and Phases */ - let currentStrategyIndex = 0; + let currentStrategyIndex = -1; let strategyStage = 'No Stage'; /* Stop Loss Management */ @@ -607,60 +607,73 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if ( strategyStage === 'No Stage' && - currentStrategyIndex === 0 && - balanceAssetA > minimunBalanceA + currentStrategyIndex === -1 ) { + let minimunBalance + let balance - /* Trigger On Conditions */ + if (baseAsset === 'BTC') { + balance = balanceAssetA + minimunBalance = minimunBalanceA + } else { + balance = balanceAssetB + minimunBalance = minimunBalanceB + } - /* - 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. + if (balance > minimunBalance) { + /* Trigger On Conditions */ + + /* + 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 = conditions.get(key).value; + let value = conditions.get(key).value; - if (value === false) { passed = false; } - } + if (value === false) { passed = false; } + } - if (passed) { + if (passed) { - strategyStage = 'Trigger Stage'; - currentStrategyIndex = j; - currentStrategy.begin = candle.begin; - currentStrategy.beginRate = candle.min; - currentStrategy.endRate = candle.min; // In case the strategy does not get exited - break; + strategyStage = 'Trigger Stage'; + currentStrategyIndex = j; + currentStrategy.begin = candle.begin; + currentStrategy.beginRate = candle.min; + currentStrategy.endRate = candle.min; // In case the strategy does not get exited + break; + } } } } } + } else { + tradingSystem.error = "Balance below the minimun. No more strategies will be executed." } } From 798a73682370946420c702d2f3b1c2a1ff5d01d3 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 8 Jun 2019 07:39:48 +0200 Subject: [PATCH 131/244] baseAsset Fully Implemented --- Commons.js | 65 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/Commons.js b/Commons.js index fc6d3f9c6..1db8ce08e 100644 --- a/Commons.js +++ b/Commons.js @@ -167,6 +167,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let positionInstant; let previousBalanceAssetA = 0; + let previousBalanceAssetB = 0; let hitRatio = 0; let ROI = 0; let days = 0; @@ -733,8 +734,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (candle.max >= stopLoss) { - balanceAssetA = balanceAssetA + balanceAssetB / stopLoss; - balanceAssetB = 0; + if (baseAsset === 'BTC') { + balanceAssetA = balanceAssetA + balanceAssetB / stopLoss; + balanceAssetB = 0; + } else { + balanceAssetB = balanceAssetB + balanceAssetA / stopLoss; + balanceAssetA = 0; + } if (currentDay !== undefined) { if (positionInstant < currentDay.valueOf()) { @@ -763,8 +769,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (candle.min <= takeProfit) { - balanceAssetA = balanceAssetA + balanceAssetB / takeProfit; - balanceAssetB = 0; + if (baseAsset === 'BTC') { + balanceAssetA = balanceAssetA + balanceAssetB / takeProfit; + balanceAssetB = 0; + } else { + balanceAssetB = balanceAssetB + balanceAssetA / takeProfit; + balanceAssetA = 0; + } if (currentDay !== undefined) { if (positionInstant < currentDay.valueOf()) { @@ -1062,8 +1073,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { ) { takePositionNow = false - positionSize = balanceAssetA; // This is by default if no size was defined by the user - + /* positionSize default is the whole balance if no size was defined by the user */ + if (baseAsset === 'BTC') { + positionSize = balanceAssetA; + } else { + positionSize = balanceAssetB; + } + + /* Check if the user defined a position size */ let strategy = tradingSystem.strategies[currentStrategyIndex]; let triggerStage = strategy.triggerStage @@ -1076,7 +1093,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } catch (err) { triggerStage.positionSize.formula.error = err.message } - if (isNaN(positionSize)) { positionSize = balanceAssetA; } + if (isNaN(positionSize)) { + if (baseAsset === 'BTC') { + positionSize = balanceAssetA; + } else { + positionSize = balanceAssetB; + } + } } } } @@ -1088,11 +1111,18 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { calculateTakeProfit(); previousBalanceAssetA = balanceAssetA; + previousBalanceAssetB = balanceAssetB; + lastProfit = 0; lastProfitPercent = 0; - balanceAssetB = balanceAssetB + positionSize * marketRate; - balanceAssetA = balanceAssetA - positionSize; + if (baseAsset === 'BTC') { + balanceAssetB = balanceAssetB + positionSize * marketRate; + balanceAssetA = balanceAssetA - positionSize; + } else { + balanceAssetA = balanceAssetA + positionSize / marketRate; + balanceAssetB = balanceAssetB - positionSize; + } positionInstant = candle.end; @@ -1121,11 +1151,18 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { yesterday.Roundtrips++; } } - - lastProfit = balanceAssetA - previousBalanceAssetA; - lastProfitPercent = lastProfit / previousBalanceAssetA * 100; - if (isNaN(lastProfitPercent)) { lastProfitPercent = 0; } - profit = balanceAssetA - initialBalanceA; + + if (baseAsset === 'BTC') { + lastProfit = balanceAssetA - previousBalanceAssetA; + lastProfitPercent = lastProfit / previousBalanceAssetA * 100; + if (isNaN(lastProfitPercent)) { lastProfitPercent = 0; } + profit = balanceAssetA - initialBalanceA; + } else { + lastProfit = balanceAssetB - previousBalanceAssetB; + lastProfitPercent = lastProfit / previousBalanceAssetB * 100; + if (isNaN(lastProfitPercent)) { lastProfitPercent = 0; } + profit = balanceAssetB - initialBalanceB; + } if (currentDay !== undefined) { if (positionInstant < currentDay.valueOf()) { From ec9bea24778d9b66368de7e3768ed984476ee0c6 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 8 Jun 2019 08:20:08 +0200 Subject: [PATCH 132/244] Fixing comparison when checking stoploss and take profit --- Commons.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Commons.js b/Commons.js index 1db8ce08e..d98900328 100644 --- a/Commons.js +++ b/Commons.js @@ -732,7 +732,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - if (candle.max >= stopLoss) { + if ((baseAsset === 'BTC' && candle.max >= stopLoss) || (baseAsset !== 'BTC' && candle.min <= stopLoss)) { if (baseAsset === 'BTC') { balanceAssetA = balanceAssetA + balanceAssetB / stopLoss; @@ -767,7 +767,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Take Profit condition: Here we verify if the Take Profit was filled or not. */ - if (candle.min <= takeProfit) { + if ((baseAsset === 'BTC' && candle.min <= takeProfit) || (baseAsset !== 'BTC' && candle.max >= takeProfit)) { if (baseAsset === 'BTC') { balanceAssetA = balanceAssetA + balanceAssetB / takeProfit; @@ -1174,9 +1174,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentTrade.lastProfitPercent = lastProfitPercent; currentTrade.stopRate = stopLoss; - - //if (isNaN(ROI)) { ROI = 0; } - + if (lastProfit > 0) { hits++; @@ -1196,9 +1194,15 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - ROI = (initialBalanceA + profit) / initialBalanceA - 1; - hitRatio = hits / roundtrips; - anualizedRateOfReturn = ROI / days * 365; + if (baseAsset === 'BTC') { + ROI = (initialBalanceA + profit) / initialBalanceA - 1; + hitRatio = hits / roundtrips; + anualizedRateOfReturn = ROI / days * 365; + } else { + ROI = (initialBalanceB + profit) / initialBalanceB - 1; + hitRatio = hits / roundtrips; + anualizedRateOfReturn = ROI / days * 365; + } if (currentDay !== undefined) { if (positionInstant < currentDay.valueOf()) { From b73ed023b7d7ecf77daa9ea2677d26a0ec54ed06 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 8 Jun 2019 08:38:07 +0200 Subject: [PATCH 133/244] Bug fixed * insted of / --- Commons.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Commons.js b/Commons.js index d98900328..54c3c0578 100644 --- a/Commons.js +++ b/Commons.js @@ -738,7 +738,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { balanceAssetA = balanceAssetA + balanceAssetB / stopLoss; balanceAssetB = 0; } else { - balanceAssetB = balanceAssetB + balanceAssetA / stopLoss; + balanceAssetB = balanceAssetB + balanceAssetA * stopLoss; balanceAssetA = 0; } @@ -773,7 +773,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { balanceAssetA = balanceAssetA + balanceAssetB / takeProfit; balanceAssetB = 0; } else { - balanceAssetB = balanceAssetB + balanceAssetA / takeProfit; + balanceAssetB = balanceAssetB + balanceAssetA * takeProfit; balanceAssetA = 0; } From e18dab3e00593b9300f1db23a54979f03f7f2ef9 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 8 Jun 2019 08:48:08 +0200 Subject: [PATCH 134/244] Bug Fixed --- Commons.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Commons.js b/Commons.js index 54c3c0578..9597578ae 100644 --- a/Commons.js +++ b/Commons.js @@ -712,7 +712,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentStrategy.endRate = candle.min; currentStrategy.status = 1; strategyStage = 'No Stage'; - currentStrategyIndex = 0; + currentStrategyIndex = -1; break; } } @@ -1215,7 +1215,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { addRecord(); - currentStrategyIndex = 0; + currentStrategyIndex = -1; stopLoss = 0; positionRate = 0; positionSize = 0; From a437734e4cd2b487d9d79e08bb7f88c9f9faf7a8 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 8 Jun 2019 08:54:07 +0200 Subject: [PATCH 135/244] Bug Fixed, position Size working --- Commons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index 9597578ae..dc6670812 100644 --- a/Commons.js +++ b/Commons.js @@ -1089,7 +1089,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (triggerStage.positionSize.formula !== undefined) { try { triggerStage.positionSize.formula.value = eval(triggerStage.positionSize.formula.code); - positionSize = phase.formula.value + positionSize = triggerStage.positionSize.formula.value } catch (err) { triggerStage.positionSize.formula.error = err.message } From ce863c470a89ad709a5a126b6ae515d3e36f3be3 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 8 Jun 2019 11:29:00 +0200 Subject: [PATCH 136/244] Handling infinity in Phases formulas --- Commons.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Commons.js b/Commons.js index dc6670812..cc1368172 100644 --- a/Commons.js +++ b/Commons.js @@ -148,6 +148,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Stop Loss Management */ const MIN_STOP_LOSS_VALUE = 1 // We can not let the stop be zero to avoid division by 0 error or infinity numbers as a result. + const MAX_STOP_LOSS_VALUE = Number.MAX_SAFE_INTEGER let stopLoss = 0; let stopLossPhase = 0; let stopLossStage = 'No Stage'; @@ -155,6 +156,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Take Profit Management */ const MIN_TAKE_PROFIT_VALUE = 1 // We can not let the buy order be zero to avoid division by 0 error or infinity numbers as a result. + const MAX_TAKE_PROFIT_VALUE = Number.MAX_SAFE_INTEGER let previousTakeProfit = 0; let takeProfit = 0; let takeProfitPhase = 0; @@ -947,6 +949,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { try { phase.formula.value = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. stopLoss = phase.formula.value + if (stopLoss === Infinity) { + phase.formula.error = "Formula evaluates to Infinity." + takeProfit = MAX_STOP_LOSS_VALUE + } } catch (err) { phase.formula.error = err.message } @@ -1056,6 +1062,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { try { phase.formula.value = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. takeProfit = phase.formula.value + if (takeProfit === Infinity) { + phase.formula.error = "Formula evaluates to Infinity." + takeProfit = MAX_TAKE_PROFIT_VALUE + } } catch (err) { phase.formula.error = err.message } From a20fae746213a005b4a44b6550b98a05dfafe666 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 8 Jun 2019 11:39:30 +0200 Subject: [PATCH 137/244] Bug fix with infitiy handling --- Commons.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Commons.js b/Commons.js index cc1368172..0bf7c6e8e 100644 --- a/Commons.js +++ b/Commons.js @@ -951,7 +951,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { stopLoss = phase.formula.value if (stopLoss === Infinity) { phase.formula.error = "Formula evaluates to Infinity." - takeProfit = MAX_STOP_LOSS_VALUE + stopLoss = MAX_STOP_LOSS_VALUE + phase.formula.value = stopLoss } } catch (err) { phase.formula.error = err.message @@ -1064,7 +1065,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { takeProfit = phase.formula.value if (takeProfit === Infinity) { phase.formula.error = "Formula evaluates to Infinity." - takeProfit = MAX_TAKE_PROFIT_VALUE + takeProfit = MAX_TAKE_PROFIT_VALUE + phase.formula.value = takeProfit } } catch (err) { phase.formula.error = err.message From 1cf6b7254587495a600827b8f2d4ef57741ef4ba Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 8 Jun 2019 12:14:42 +0200 Subject: [PATCH 138/244] tradingSystem passed as parameter --- Commons.js | 5 ++--- Multi-Period-Daily/User.Bot.js | 8 ++++++-- Multi-Period-Market/User.Bot.js | 8 ++++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Commons.js b/Commons.js index 0bf7c6e8e..b514289cb 100644 --- a/Commons.js +++ b/Commons.js @@ -59,7 +59,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategiesArray, tradesArray, lastObjectsArray, - tradingSystem, timePeriod, currentDay, startDate, @@ -71,7 +70,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Entering function."); } - tradingSystem = await getTradingSystem(); + let tradingSystem = await getTradingSystem(); /* Initial Default Values */ @@ -1457,7 +1456,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - callback(); + callback(tradingSystem); function getElement(pArray, begin, end) { diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 68ce0df4e..d0f3ba431 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -113,13 +113,17 @@ strategiesArray, tradesArray, lastObjectsArray, - tradingSystem, timePeriod, currentDay, startDate, endDate, interExecutionMemory, - writeRecordsFile) + writeFiles) + + function writeFiles(pTradingSystem) { + tradingSystem = pTradingSystem + writeRecordsFile() + } function writeRecordsFile() { diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index ac5a13578..f9de8ae12 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -115,13 +115,17 @@ strategiesArray, tradesArray, lastObjectsArray, - tradingSystem, timePeriod, currentDay, startDate, endDate, interExecutionMemory, - writeRecordsFile) + writeFiles) + + function writeFiles(pTradingSystem) { + tradingSystem = pTradingSystem + writeRecordsFile() + } function writeRecordsFile() { From d7266af11100604b4902272e949fffef998ca4e5 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 8 Jun 2019 15:39:43 +0200 Subject: [PATCH 139/244] Removing values from tradingSystem structure --- Commons.js | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/Commons.js b/Commons.js index b514289cb..3671a81f9 100644 --- a/Commons.js +++ b/Commons.js @@ -578,21 +578,22 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let condition; let error = '' + let value try { - node.value = eval(node.code); + value = eval(node.code); } catch (err) { /* One possible error is that the conditions references a .previous that is undefined. For this reason and others, we will simply set the value to false. */ - node.value = false + value = false node.error = err.message } condition = { key: key, - value: node.value + value: value }; conditions.set(condition.key, condition); @@ -946,12 +947,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (phase.formula !== undefined) { try { - phase.formula.value = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. - stopLoss = phase.formula.value + stopLoss = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. if (stopLoss === Infinity) { phase.formula.error = "Formula evaluates to Infinity." stopLoss = MAX_STOP_LOSS_VALUE - phase.formula.value = stopLoss } } catch (err) { phase.formula.error = err.message @@ -1060,12 +1059,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (phase.formula !== undefined) { try { - phase.formula.value = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. - takeProfit = phase.formula.value + takeProfit = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. if (takeProfit === Infinity) { phase.formula.error = "Formula evaluates to Infinity." takeProfit = MAX_TAKE_PROFIT_VALUE - phase.formula.value = takeProfit } } catch (err) { phase.formula.error = err.message @@ -1099,8 +1096,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (triggerStage.positionSize !== undefined) { if (triggerStage.positionSize.formula !== undefined) { try { - triggerStage.positionSize.formula.value = eval(triggerStage.positionSize.formula.code); - positionSize = triggerStage.positionSize.formula.value + positionSize = eval(triggerStage.positionSize.formula.code); } catch (err) { triggerStage.positionSize.formula.error = err.message } From 617c2641b45d3238cd5891f7cb5fbe9d121c2ed8 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 8 Jun 2019 17:19:58 +0200 Subject: [PATCH 140/244] Bug Fixes with currently running --- Commons.js | 133 ++++++++++++++++++++++++++++---- Multi-Period-Daily/User.Bot.js | 6 +- Multi-Period-Market/User.Bot.js | 6 +- 3 files changed, 126 insertions(+), 19 deletions(-) diff --git a/Commons.js b/Commons.js index 3671a81f9..37fa1f605 100644 --- a/Commons.js +++ b/Commons.js @@ -375,17 +375,20 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } let conditions = new Map; // Here we store the conditions values that will be use in the simulator for decision making. + let formulas = new Map; let conditionsArrayRecord = []; // These are the records that will be saved in a file for the plotter to consume. let conditionsArrayValues = []; // Here we store the conditions values that will be written on file for the plotter. + let formulasErrors = []; // Here we store the errors produced by all phase formulas. + let formulasValues = []; // Here we store the values produced by all phase formulas. /* We define and evaluate all conditions to be used later during the simulation loop. */ conditionsArrayRecord.push(candle.begin); conditionsArrayRecord.push(candle.end); - evaluateConditions(tradingSystem, conditions); + evaluateConditionsAndFormulas(tradingSystem, conditions); - function evaluateConditions(tradingSystem, conditions) { + function evaluateConditionsAndFormulas(tradingSystem, conditions) { for (let j = 0; j < tradingSystem.strategies.length; j++) { @@ -464,6 +467,32 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let phase = initialDefinition.stopLoss.phases[p]; + /* Evaluate Formula */ + let formulaValue + let formulaError = '' + + if (phase.formula !== undefined) { + try { + formulaValue = eval(phase.formula.code); + if (formulaValue === Infinity) { + formulaError= "Formula evaluates to Infinity." + formulaValue = MAX_STOP_LOSS_VALUE + } + } catch (err) { + formulaError = err.message + } + if (isNaN(formulaValue)) { formulaValue = 0; } + if (formulaValue < MIN_STOP_LOSS_VALUE) { + formulaValue = MIN_STOP_LOSS_VALUE + } + } + + formulasErrors.push('"' + formulaError + '"') + formulasValues.push( formulaValue) + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p; + formulas.set(key, formulaValue) + + /* next phase event */ let nextPhaseEvent = phase.nextPhaseEvent; if (nextPhaseEvent !== undefined) { @@ -491,6 +520,32 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let phase = initialDefinition.takeProfit.phases[p]; + /* Evaluate Formula */ + let formulaValue + let formulaError = '' + + if (phase.formula !== undefined) { + try { + formulaValue = eval(phase.formula.code); + if (formulaValue === Infinity) { + formulaError = "Formula evaluates to Infinity." + formulaValue = MAX_TAKE_PROFIT_VALUE + } + } catch (err) { + formulaError = err.message + } + if (isNaN(formulaValue)) { formulaValue = 0; } + if (formulaValue < MIN_TAKE_PROFIT_VALUE) { + formulaValue = MIN_TAKE_PROFIT_VALUE + } + } + + formulasErrors.push('"' + formulaError + '"') + formulasValues.push(formulaValue) + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p; + formulas.set(key, formulaValue) + + /* next phase event */ let nextPhaseEvent = phase.nextPhaseEvent; if (nextPhaseEvent !== undefined) { @@ -524,6 +579,32 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let phase = manageStage.stopLoss.phases[p]; + /* Evaluate Formula */ + let formulaValue + let formulaError = '' + + if (phase.formula !== undefined) { + try { + formulaValue = eval(phase.formula.code); + if (formulaValue === Infinity) { + formulaError = "Formula evaluates to Infinity." + formulaValue = MAX_STOP_LOSS_VALUE + } + } catch (err) { + formulaError = err.message + } + if (isNaN(formulaValue)) { formulaValue = 0; } + if (formulaValue < MIN_STOP_LOSS_VALUE) { + formulaValue = MIN_STOP_LOSS_VALUE + } + } + + formulasErrors.push('"' + formulaError + '"') + formulasValues.push(formulaValue) + let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p; + formulas.set(key, formulaValue) + + /* next phase event */ let nextPhaseEvent = phase.nextPhaseEvent; if (nextPhaseEvent !== undefined) { @@ -551,6 +632,32 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let phase = manageStage.takeProfit.phases[p]; + /* Evaluate Formula */ + let formulaValue + let formulaError = '' + + if (phase.formula !== undefined) { + try { + formulaValue = eval(phase.formula.code); + if (formulaValue === Infinity) { + formulaError = "Formula evaluates to Infinity." + formulaValue = MAX_TAKE_PROFIT_VALUE + } + } catch (err) { + formulaError = err.message + } + if (isNaN(formulaValue)) { formulaValue = 0; } + if (formulaValue < MIN_TAKE_PROFIT_VALUE) { + formulaValue = MIN_TAKE_PROFIT_VALUE + } + } + + formulasErrors.push('"' + formulaError + '"') + formulasValues.push(formulaValue) + let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p; + formulas.set(key, formulaValue) + + /* next phase event */ let nextPhaseEvent = phase.nextPhaseEvent; if (nextPhaseEvent !== undefined) { @@ -930,11 +1037,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let openStage = strategy.openStage let manageStage = strategy.manageStage let phase + let key if (stopLossStage === 'Open Stage' && openStage !== undefined) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.stopLoss !== undefined) { phase = openStage.initialDefinition.stopLoss.phases[stopLossPhase - 1]; + key = currentStrategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + (stopLossPhase - 1); } } } @@ -942,23 +1051,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (stopLossStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.stopLoss !== undefined) { phase = manageStage.stopLoss.phases[stopLossPhase - 2]; + key = currentStrategyIndex + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + (stopLossPhase - 2); } } if (phase.formula !== undefined) { - try { - stopLoss = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. - if (stopLoss === Infinity) { - phase.formula.error = "Formula evaluates to Infinity." - stopLoss = MAX_STOP_LOSS_VALUE - } - } catch (err) { - phase.formula.error = err.message - } - if (isNaN(stopLoss)) { stopLoss = 0; } - if (stopLoss < MIN_STOP_LOSS_VALUE) { - stopLoss = MIN_STOP_LOSS_VALUE - } + stopLoss = formulas.get(key) } } @@ -1042,11 +1140,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let openStage = strategy.openStage let manageStage = strategy.manageStage let phase + let key if (takeProfitStage === 'Open Stage' && openStage !== undefined) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.takeProfit !== undefined) { phase = openStage.initialDefinition.takeProfit.phases[takeProfitPhase - 1]; + key = currentStrategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + (stopLossPhase - 1); } } } @@ -1054,6 +1154,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (takeProfitStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.takeProfit !== undefined) { phase = manageStage.takeProfit.phases[takeProfitPhase - 2]; + key = currentStrategyIndex + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (stopLossPhase - 2); } } @@ -1377,6 +1478,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { conditionsArrayRecord.push(stopLossPhase); conditionsArrayRecord.push(takeProfitPhase); conditionsArrayRecord.push(conditionsArrayValues); + conditionsArrayRecord.push(formulasErrors); + conditionsArrayRecord.push(formulasValues); conditionsArray.push(conditionsArrayRecord); diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index d0f3ba431..cbf3001ba 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -248,12 +248,14 @@ if (record.begin < currentDay.valueOf()) { continue; } - for (let j = 0; j < record.length - 1; j++) { + for (let j = 0; j < record.length - 3; j++) { conditions = conditions + conditionsSeparator + record[j]; if (conditionsSeparator === "") { conditionsSeparator = ","; } } - conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of condition values. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 3] + ']'; // The last item contains an Array of condition values. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 2] + ']'; // The last item contains an Array of formulaErrors. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of formulaValues. fileContent = fileContent + separator + '[' + conditions + ']'; diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index f9de8ae12..d040beb75 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -238,12 +238,14 @@ let conditions = ""; let conditionsSeparator = ""; - for (let j = 0; j < record.length - 1; j++) { + for (let j = 0; j < record.length - 3; j++) { conditions = conditions + conditionsSeparator + record[j]; if (conditionsSeparator === "") { conditionsSeparator = ","; } } - conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of condition values. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 3] + ']'; // The last item contains an Array of condition values. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 2] + ']'; // The last item contains an Array of formulaErrors. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of formulaValues. fileContent = fileContent + separator + '[' + conditions + ']'; From bac96ad0d240db33cc936ce38867efb6e3f72182 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 8 Jun 2019 17:59:03 +0200 Subject: [PATCH 141/244] Bug Fixed takeProfit --- Commons.js | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/Commons.js b/Commons.js index 37fa1f605..9506b2326 100644 --- a/Commons.js +++ b/Commons.js @@ -1146,7 +1146,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.takeProfit !== undefined) { phase = openStage.initialDefinition.takeProfit.phases[takeProfitPhase - 1]; - key = currentStrategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + (stopLossPhase - 1); + key = currentStrategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 1); } } } @@ -1154,24 +1154,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (takeProfitStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.takeProfit !== undefined) { phase = manageStage.takeProfit.phases[takeProfitPhase - 2]; - key = currentStrategyIndex + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (stopLossPhase - 2); + key = currentStrategyIndex + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 2); } } if (phase.formula !== undefined) { - try { - takeProfit = eval(phase.formula.code); // Here is where we apply the formula given for the stop loss. - if (takeProfit === Infinity) { - phase.formula.error = "Formula evaluates to Infinity." - takeProfit = MAX_TAKE_PROFIT_VALUE - } - } catch (err) { - phase.formula.error = err.message - } - if (isNaN(takeProfit)) { takeProfit = 0; } - if (takeProfit < MIN_TAKE_PROFIT_VALUE) { - takeProfit = MIN_TAKE_PROFIT_VALUE - } + takeProfit = formulas.get(key) } } From c594c64f15de66b035d7a9d3c0cced50d0ab64ba Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 8 Jun 2019 18:04:08 +0200 Subject: [PATCH 142/244] error text changed --- Commons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index 9506b2326..fee0221b4 100644 --- a/Commons.js +++ b/Commons.js @@ -96,7 +96,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (receivedParameters.name !== undefined) { baseAsset = receivedParameters.name; if (baseAsset !== 'BTC' && baseAsset !== 'USDT') { - tradingSystem.parameters.baseAsset.formula.error = 'The only supported assets so far are BTC and USDT. Using default BTC.' + tradingSystem.parameters.baseAsset.formula.error = baseAsset + ' is not supported. Using default: BTC.' baseAsset = 'BTC' } } From b2f3990edf6d742a97d9e8ce66a2dfab58bc3254 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 9 Jun 2019 16:21:34 +0200 Subject: [PATCH 143/244] maximunBalance --- Commons.js | 31 +++++++++++++++++++++++++++++-- Multi-Period-Daily/User.Bot.js | 8 +++++++- Multi-Period-Market/User.Bot.js | 9 +++++++-- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/Commons.js b/Commons.js index fee0221b4..92ea42f09 100644 --- a/Commons.js +++ b/Commons.js @@ -78,10 +78,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { const DEFAULT_BASE_ASSET_BALANCE = 1 const DEFAULT_BASE_ASSET_MINIMUN_BALANCE = 0.5 + const DEFAULT_BASE_ASSET_MAXIMUN_BALANCE = 2 + let initialBalanceA = DEFAULT_BASE_ASSET_BALANCE let minimunBalanceA = DEFAULT_BASE_ASSET_MINIMUN_BALANCE + let maximunBalanceA = DEFAULT_BASE_ASSET_MAXIMUN_BALANCE let initialBalanceB = 0 let minimunBalanceB = 0 + let maximunBalanceB = 0 let baseAsset = 'BTC' /* Parameters Processing */ @@ -116,6 +120,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { minimunBalanceA = DEFAULT_BASE_ASSET_MINIMUN_BALANCE; minimunBalanceB = 0 } + if (receivedParameters.maximunBalance !== undefined) { + maximunBalanceA = receivedParameters.maximunBalance; + maximunBalanceB = 0 + } else { + maximunBalanceA = DEFAULT_BASE_ASSET_MAXIMUN_BALANCE; + maximunBalanceB = 0 + } } else { if (receivedParameters.initialBalance !== undefined) { initialBalanceB = receivedParameters.initialBalance; @@ -131,6 +142,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { minimunBalanceB = DEFAULT_BASE_ASSET_MINIMUN_BALANCE; minimunBalanceA = 0 } + if (receivedParameters.maximunBalance !== undefined) { + maximunBalanceB = receivedParameters.maximunBalance; + maximunBalanceA = 0 + } else { + maximunBalanceB = DEFAULT_BASE_ASSET_MAXIMUN_BALANCE; + maximunBalanceA = 0 + } } } catch (err) { tradingSystem.parameters.baseAsset.formula.error = err.message @@ -720,17 +738,20 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentStrategyIndex === -1 ) { let minimunBalance + let maximunBalance let balance if (baseAsset === 'BTC') { balance = balanceAssetA minimunBalance = minimunBalanceA + maximunBalance = maximunBalanceA } else { balance = balanceAssetB minimunBalance = minimunBalanceB + maximunBalance = maximunBalanceB } - if (balance > minimunBalance) { + if (balance > minimunBalance && balance < maximunBalance) { /* Trigger On Conditions */ /* @@ -1452,7 +1473,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { stopLossPhase: stopLossPhase, takeProfitPhase: takeProfitPhase, orderRecord: orderRecord, - positionSize: positionSize + positionSize: positionSize, + initialBalanceA: initialBalanceA, + minimunBalanceA: minimunBalanceA, + maximunBalanceA: maximunBalanceA, + initialBalanceB: initialBalanceB, + minimunBalanceB: minimunBalanceB, + maximunBalanceB: maximunBalanceB } recordsArray.push(simulationRecord); diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index cbf3001ba..365607ecb 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -171,7 +171,13 @@ record.stopLossPhase + "," + record.takeProfitPhase + "," + JSON.stringify(record.orderRecord) + "," + - record.positionSize + "]"; + record.positionSize + "," + + record.initialBalanceA + "," + + record.minimunBalanceA + "," + + record.maximunBalanceA + "," + + record.initialBalanceB + "," + + record.minimunBalanceB + "," + + record.maximunBalanceB + "]"; if (separator === "") { separator = ","; } diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index d040beb75..fb4b675e6 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -168,9 +168,14 @@ record.takeProfit + "," + record.stopLossPhase + "," + record.takeProfitPhase + "," + - JSON.stringify(record.orderRecord) + "," + - record.positionSize + "]"; + record.positionSize + "," + + record.initialBalanceA + "," + + record.minimunBalanceA + "," + + record.maximunBalanceA + "," + + record.initialBalanceB + "," + + record.minimunBalanceB + "," + + record.maximunBalanceB + "]"; if (separator === "") { separator = ","; } From a4dbcfd25cae47370fbfeb22b125c0bf46827d84 Mon Sep 17 00:00:00 2001 From: Matias Date: Mon, 17 Jun 2019 21:07:03 -0300 Subject: [PATCH 144/244] Integration with saweb --- Commons.js | 48 ++------------------------------- Multi-Period-Daily/User.Bot.js | 39 ++++++++++++--------------- Multi-Period-Market/User.Bot.js | 39 +++++++++++---------------- this.bot.config.json | 38 -------------------------- 4 files changed, 35 insertions(+), 129 deletions(-) diff --git a/Commons.js b/Commons.js index 92ea42f09..d0f98ae4b 100644 --- a/Commons.js +++ b/Commons.js @@ -1,5 +1,4 @@ -const axios = require('axios') -const auth = require('./utils/auth') +const strategy = require('./Integrations/Strategy') exports.newCommons = function newCommons(bot, logger, UTILITIES) { @@ -70,7 +69,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Entering function."); } - let tradingSystem = await getTradingSystem(); + let tradingSystem = await strategy.getStrategy(); /* Initial Default Values */ @@ -1837,49 +1836,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - - async function getTradingSystem() { - - try { - - const accessToken = await auth.authenticate() - - let fbSlug = bot.codeName - if (process.env.TEST_FB !== undefined) { - fbSlug = process.env.TEST_FB - } - - const strategizerResponse = await axios({ - url: process.env.GATEWAY_ENDPOINT, - method: 'post', - data: { - query: ` - query($fbSlug: String!){ - strategizer_TradingSystemByFb(fbSlug: $fbSlug){ - id - fbSlug - data - } - } - `, - variables: { - fbSlug: fbSlug - }, - }, - headers: { - authorization: 'Bearer ' + accessToken - } - }) - - if (strategizerResponse.data.errors) - throw new Error(strategizerResponse.data.errors[0].message) - - return strategizerResponse.data.data.strategizer_TradingSystemByFb.data; - - } catch (error) { - throw new Error('There has been an error getting the strategy to run on the simulator. Error: ' + error) - } - } }; diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 365607ecb..1b03337f1 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -1,4 +1,4 @@ -exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, FILE_STORAGE) { +exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES) { const FULL_LOG = true; const LOG_FILE_CONTENT = false; @@ -18,7 +18,9 @@ }; let utilities = UTILITIES.newCloudUtilities(bot, logger); - let thisBotStorage = BLOB_STORAGE.newBlobStorage(bot, logger); + + const FILE_STORAGE = require('./Integrations/FileStorage.js'); + let botStorage = FILE_STORAGE.newFileStorage(); let dataDependencies; @@ -35,19 +37,8 @@ dataDependencies = pDataDependencies; - thisBotStorage.initialize(bot.devTeam, onStorageInizialized); + callBackFunction(global.DEFAULT_OK_RESPONSE); - function onStorageInizialized(err) { - - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - - callBackFunction(global.DEFAULT_OK_RESPONSE); - - } else { - logger.write(MODULE_NAME, "[ERROR] initializeStorage -> onStorageInizialized -> err = " + err.stack); - callBackFunction(err); - } - } } catch (err) { logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); @@ -190,10 +181,11 @@ let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + filePath += '/' + fileName - thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + botStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { @@ -277,10 +269,11 @@ let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + filePath += '/' + fileName - thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + botStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { @@ -353,10 +346,11 @@ let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + filePath += '/' + fileName - thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + botStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { @@ -432,10 +426,11 @@ let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + filePath += '/' + fileName - thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + botStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index fb4b675e6..699cfc583 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -1,4 +1,4 @@ -exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, FILE_STORAGE) { +exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES) { const FULL_LOG = true; const LOG_FILE_CONTENT = false; @@ -17,8 +17,8 @@ start: start }; - let utilities = UTILITIES.newCloudUtilities(bot, logger); - let thisBotStorage = BLOB_STORAGE.newBlobStorage(bot, logger); + const FILE_STORAGE = require('./Integrations/FileStorage.js'); + let botStorage = FILE_STORAGE.newFileStorage(); let dataDependencies; @@ -35,19 +35,8 @@ dataDependencies = pDataDependencies; - thisBotStorage.initialize(bot.devTeam, onStorageInizialized); + callBackFunction(global.DEFAULT_OK_RESPONSE); - function onStorageInizialized(err) { - - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - - callBackFunction(global.DEFAULT_OK_RESPONSE); - - } else { - logger.write(MODULE_NAME, "[ERROR] initializeStorage -> onStorageInizialized -> err = " + err.stack); - callBackFunction(err); - } - } } catch (err) { logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); @@ -187,10 +176,11 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; + filePath += '/' + fileName - thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + botStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { @@ -264,10 +254,11 @@ fileContent = "[" + JSON.stringify(tradingSystem) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]"; let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; + filePath += '/' + fileName - thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + botStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { @@ -333,10 +324,11 @@ fileContent = "[" + fileContent + "]"; let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; + filePath += '/' + fileName - thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + botStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { @@ -405,10 +397,11 @@ fileContent = "[" + fileContent + "]"; let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; + filePath += '/' + fileName - thisBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated); + botStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { diff --git a/this.bot.config.json b/this.bot.config.json index b3b82072d..2f17c31ad 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -14,25 +14,6 @@ { "name": "Multi-Period-Market", "description": "Produces a single file for each time period covering all the market.", - "startMode": { - "allMonths": { - "run": "false", - "minYear": "", - "maxYear": "" - }, - "oneMonth": { - "run": "false", - "year": "", - "month": "" - }, - "noTime": { - "run": "true" - }, - "fixedInterval": { - "run": "false", - "interval": 0 - } - }, "normalWaitTime": 60000, "retryWaitTime": 10000, "sleepWaitTime": 3600000, @@ -129,25 +110,6 @@ { "name": "Multi-Period-Daily", "description": "Produces a Daily File at each time period.", - "startMode": { - "allMonths": { - "run": "false", - "minYear": "", - "maxYear": "" - }, - "oneMonth": { - "run": "false", - "year": "", - "month": "" - }, - "noTime": { - "run": "true" - }, - "fixedInterval": { - "run": "false", - "interval": 0 - } - }, "normalWaitTime": 60000, "retryWaitTime": 10000, "sleepWaitTime": 3600000, From 11ad478ee59e11c5daad430bc471eaf5493b792f Mon Sep 17 00:00:00 2001 From: Matias Date: Sat, 22 Jun 2019 19:29:34 -0300 Subject: [PATCH 145/244] File storage dependency --- Multi-Period-Daily/User.Bot.js | 17 +++++++---------- Multi-Period-Market/User.Bot.js | 17 +++++++---------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 1b03337f1..7f2baca56 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -1,4 +1,4 @@ -exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES) { +exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, fileStorage) { const FULL_LOG = true; const LOG_FILE_CONTENT = false; @@ -19,9 +19,6 @@ let utilities = UTILITIES.newCloudUtilities(bot, logger); - const FILE_STORAGE = require('./Integrations/FileStorage.js'); - let botStorage = FILE_STORAGE.newFileStorage(); - let dataDependencies; return thisObject; @@ -113,7 +110,7 @@ function writeFiles(pTradingSystem) { tradingSystem = pTradingSystem - writeRecordsFile() + writeRecordsFile() } function writeRecordsFile() { @@ -168,7 +165,7 @@ record.maximunBalanceA + "," + record.initialBalanceB + "," + record.minimunBalanceB + "," + - record.maximunBalanceB + "]"; + record.maximunBalanceB + "]"; if (separator === "") { separator = ","; } @@ -185,7 +182,7 @@ let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; filePath += '/' + fileName - botStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { @@ -273,7 +270,7 @@ let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; filePath += '/' + fileName - botStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { @@ -350,7 +347,7 @@ let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; filePath += '/' + fileName - botStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { @@ -430,7 +427,7 @@ let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; filePath += '/' + fileName - botStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 699cfc583..52658e30e 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -1,4 +1,4 @@ -exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES) { +exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, fileStorage) { const FULL_LOG = true; const LOG_FILE_CONTENT = false; @@ -17,9 +17,6 @@ start: start }; - const FILE_STORAGE = require('./Integrations/FileStorage.js'); - let botStorage = FILE_STORAGE.newFileStorage(); - let dataDependencies; return thisObject; @@ -164,8 +161,8 @@ record.maximunBalanceA + "," + record.initialBalanceB + "," + record.minimunBalanceB + "," + - record.maximunBalanceB + "]"; - + record.maximunBalanceB + "]"; + if (separator === "") { separator = ","; } fileRecordCounter++; @@ -180,7 +177,7 @@ let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; filePath += '/' + fileName - botStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { @@ -258,7 +255,7 @@ let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; filePath += '/' + fileName - botStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { @@ -328,7 +325,7 @@ let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; filePath += '/' + fileName - botStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { @@ -401,7 +398,7 @@ let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; filePath += '/' + fileName - botStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); function onFileCreated(err) { From 85c9c74c3b80c9fc1a94909735a6f7353b00a28c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 24 Jun 2019 23:23:43 +0200 Subject: [PATCH 146/244] 2 Bugs Fixed: formulas without values and stopRate undefined --- Commons.js | 40 ++++++++++++++++----------------- Multi-Period-Daily/User.Bot.js | 1 + Multi-Period-Market/User.Bot.js | 1 + 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/Commons.js b/Commons.js index d0f98ae4b..ee498e8ab 100644 --- a/Commons.js +++ b/Commons.js @@ -502,12 +502,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (formulaValue < MIN_STOP_LOSS_VALUE) { formulaValue = MIN_STOP_LOSS_VALUE } - } - formulasErrors.push('"' + formulaError + '"') - formulasValues.push( formulaValue) - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p; - formulas.set(key, formulaValue) + formulasErrors.push('"' + formulaError + '"') + formulasValues.push(formulaValue) + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p; + formulas.set(key, formulaValue) + } /* next phase event */ let nextPhaseEvent = phase.nextPhaseEvent; @@ -555,12 +555,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (formulaValue < MIN_TAKE_PROFIT_VALUE) { formulaValue = MIN_TAKE_PROFIT_VALUE } - } - formulasErrors.push('"' + formulaError + '"') - formulasValues.push(formulaValue) - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p; - formulas.set(key, formulaValue) + formulasErrors.push('"' + formulaError + '"') + formulasValues.push(formulaValue) + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p; + formulas.set(key, formulaValue) + } /* next phase event */ let nextPhaseEvent = phase.nextPhaseEvent; @@ -614,12 +614,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (formulaValue < MIN_STOP_LOSS_VALUE) { formulaValue = MIN_STOP_LOSS_VALUE } - } - formulasErrors.push('"' + formulaError + '"') - formulasValues.push(formulaValue) - let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p; - formulas.set(key, formulaValue) + formulasErrors.push('"' + formulaError + '"') + formulasValues.push(formulaValue) + let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p; + formulas.set(key, formulaValue) + } /* next phase event */ let nextPhaseEvent = phase.nextPhaseEvent; @@ -667,12 +667,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (formulaValue < MIN_TAKE_PROFIT_VALUE) { formulaValue = MIN_TAKE_PROFIT_VALUE } - } - formulasErrors.push('"' + formulaError + '"') - formulasValues.push(formulaValue) - let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p; - formulas.set(key, formulaValue) + formulasErrors.push('"' + formulaError + '"') + formulasValues.push(formulaValue) + let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p; + formulas.set(key, formulaValue) + } /* next phase event */ let nextPhaseEvent = phase.nextPhaseEvent; diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 7f2baca56..9bd5892a0 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -401,6 +401,7 @@ at the current date. */ if (record.end < currentDay.valueOf()) { continue; } + if (record.stopRate === undefined) { record.stopRate = 0} fileContent = fileContent + separator + '[' + record.begin + "," + diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 52658e30e..8c976caed 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -374,6 +374,7 @@ for (let i = 0; i < tradesArray.length; i++) { let record = tradesArray[i]; + if (record.stopRate === undefined) { record.stopRate = 0 } fileContent = fileContent + separator + '[' + record.begin + "," + From 515d8f2f0b7b68c252b82cc233f716b68362060d Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 27 Jun 2019 00:52:10 +0200 Subject: [PATCH 147/244] PositionRate pre calculated and BUG FIXED negative balances --- Commons.js | 20 ++++++++++++++++---- this.bot.config.json | 12 ++++-------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/Commons.js b/Commons.js index ee498e8ab..44f6912e1 100644 --- a/Commons.js +++ b/Commons.js @@ -398,6 +398,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let formulasErrors = []; // Here we store the errors produced by all phase formulas. let formulasValues = []; // Here we store the values produced by all phase formulas. + /* We set some variables that would be nice if they have a value before the formulas are calculated. */ + + if (strategyStage === 'Trigger Stage') { + + positionRate = candle.close; + + } + /* We define and evaluate all conditions to be used later during the simulation loop. */ conditionsArrayRecord.push(candle.begin); @@ -731,7 +739,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } - if ( strategyStage === 'No Stage' && currentStrategyIndex === -1 @@ -1214,6 +1221,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { positionSize = balanceAssetA; } else { positionSize = balanceAssetB; + } + } else { + if (baseAsset === 'BTC') { + if (positionSize > balanceAssetA) { positionSize = balanceAssetA} + } else { + if (positionSize > balanceAssetB) { positionSize = balanceAssetB} } } } @@ -1221,7 +1234,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } marketRate = candle.close; - positionRate = marketRate; calculateStopLoss(); calculateTakeProfit(); @@ -1233,10 +1245,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { lastProfitPercent = 0; if (baseAsset === 'BTC') { - balanceAssetB = balanceAssetB + positionSize * marketRate; + balanceAssetB = balanceAssetB + positionSize * positionRate; balanceAssetA = balanceAssetA - positionSize; } else { - balanceAssetA = balanceAssetA + positionSize / marketRate; + balanceAssetA = balanceAssetA + positionSize / positionRate; balanceAssetB = balanceAssetB - positionSize; } diff --git a/this.bot.config.json b/this.bot.config.json index 2f17c31ad..b1043d5d8 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -264,8 +264,7 @@ "devTeam": "AAMasters", "codeName": "PlottersTradingSimulation", "moduleName": "TradingSimulation" - }, - "relatedToTradingEngine": true + } }, { "codeName": "Simulation-Conditions", @@ -304,8 +303,7 @@ "devTeam": "AAMasters", "codeName": "PlottersTradingSimulation", "moduleName": "Conditions" - }, - "relatedToTradingEngine": true + } }, { "codeName": "Simulation-Strategies", @@ -344,8 +342,7 @@ "devTeam": "AAMasters", "codeName": "PlottersTradingSimulation", "moduleName": "Strategies" - }, - "relatedToTradingEngine": true + } }, { "codeName": "Simulation-Trades", @@ -384,8 +381,7 @@ "devTeam": "AAMasters", "codeName": "PlottersTradingSimulation", "moduleName": "Trades" - }, - "relatedToTradingEngine": true + } } ] } From 9a8cac86f4aceb703b68c910451cdbe2766b6747 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 27 Jun 2019 12:44:47 +0200 Subject: [PATCH 148/244] BUG FIXED: Rellocation of where we check if stop or TP were hit --- Commons.js | 178 +++++++++++++++++++++++++++-------------------------- 1 file changed, 91 insertions(+), 87 deletions(-) diff --git a/Commons.js b/Commons.js index 44f6912e1..08685cd63 100644 --- a/Commons.js +++ b/Commons.js @@ -413,7 +413,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { evaluateConditionsAndFormulas(tradingSystem, conditions); - function evaluateConditionsAndFormulas(tradingSystem, conditions) { + function evaluateConditionsAndFormulas(tradingSystem, conditions) { for (let j = 0; j < tradingSystem.strategies.length; j++) { @@ -856,88 +856,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - /* Checking if Stop or Take Profit were hit */ - - if ( - strategyStage === 'Open Stage' || - strategyStage === 'Manage Stage' - ) { - - /* Checking what happened since the last execution. We need to know if the Stop Loss - or our Take Profit were hit. */ - - /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - - if ((baseAsset === 'BTC' && candle.max >= stopLoss) || (baseAsset !== 'BTC' && candle.min <= stopLoss)) { - - if (baseAsset === 'BTC') { - balanceAssetA = balanceAssetA + balanceAssetB / stopLoss; - balanceAssetB = 0; - } else { - balanceAssetB = balanceAssetB + balanceAssetA * stopLoss; - balanceAssetA = 0; - } - - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { - yesterday.balanceAssetA = balanceAssetA; - yesterday.balanceAssetB = balanceAssetB; - } - } - - marketRate = stopLoss; - type = '"Buy@StopLoss"'; - strategyStage = 'Close Stage'; - stopLossStage = 'No Stage'; - takeProfitStage = 'No Stage'; - currentTrade.end = candle.end; - currentTrade.status = 1; - currentTrade.exitType = 1; - currentTrade.endRate = stopLoss; - - currentStrategy.number = currentStrategyIndex - currentStrategy.end = candle.end; - currentStrategy.endRate = candle.min; - currentStrategy.status = 1; - } - - /* Take Profit condition: Here we verify if the Take Profit was filled or not. */ - - if ((baseAsset === 'BTC' && candle.min <= takeProfit) || (baseAsset !== 'BTC' && candle.max >= takeProfit)) { - - if (baseAsset === 'BTC') { - balanceAssetA = balanceAssetA + balanceAssetB / takeProfit; - balanceAssetB = 0; - } else { - balanceAssetB = balanceAssetB + balanceAssetA * takeProfit; - balanceAssetA = 0; - } - - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { - yesterday.balanceAssetA = balanceAssetA; - yesterday.balanceAssetB = balanceAssetB; - - } - } - - marketRate = takeProfit; - type = '"Buy@TakeProfit"'; - strategyStage = 'Close Stage'; - stopLossStage = 'No Stage'; - takeProfitStage = 'No Stage'; - currentTrade.end = candle.end; - currentTrade.status = 1; - currentTrade.exitType = 2; - currentTrade.endRate = takeProfit; - - currentStrategy.number = currentStrategyIndex - currentStrategy.end = candle.end; - currentStrategy.endRate = candle.min; - currentStrategy.status = 1; - } - } - /* Take Position Condition */ if (strategyStage === 'Trigger Stage') { @@ -1082,8 +1000,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - if (phase.formula !== undefined) { - stopLoss = formulas.get(key) + if (phase !== undefined) { + if (phase.formula !== undefined) { + stopLoss = formulas.get(key) + } } } @@ -1185,8 +1105,92 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - if (phase.formula !== undefined) { - takeProfit = formulas.get(key) + if (phase !== undefined) { + if (phase.formula !== undefined) { + takeProfit = formulas.get(key) + } + } + } + + /* Checking if Stop or Take Profit were hit */ + + if ( + strategyStage === 'Open Stage' || + strategyStage === 'Manage Stage' + ) { + + /* Checking what happened since the last execution. We need to know if the Stop Loss + or our Take Profit were hit. */ + + /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ + + if ((baseAsset === 'BTC' && candle.max >= stopLoss) || (baseAsset !== 'BTC' && candle.min <= stopLoss)) { + + if (baseAsset === 'BTC') { + balanceAssetA = balanceAssetA + balanceAssetB / stopLoss; + balanceAssetB = 0; + } else { + balanceAssetB = balanceAssetB + balanceAssetA * stopLoss; + balanceAssetA = 0; + } + + if (currentDay !== undefined) { + if (positionInstant < currentDay.valueOf()) { + yesterday.balanceAssetA = balanceAssetA; + yesterday.balanceAssetB = balanceAssetB; + } + } + + marketRate = stopLoss; + type = '"Buy@StopLoss"'; + strategyStage = 'Close Stage'; + stopLossStage = 'No Stage'; + takeProfitStage = 'No Stage'; + currentTrade.end = candle.end; + currentTrade.status = 1; + currentTrade.exitType = 1; + currentTrade.endRate = stopLoss; + + currentStrategy.number = currentStrategyIndex + currentStrategy.end = candle.end; + currentStrategy.endRate = candle.min; + currentStrategy.status = 1; + } + + /* Take Profit condition: Here we verify if the Take Profit was filled or not. */ + + if ((baseAsset === 'BTC' && candle.min <= takeProfit) || (baseAsset !== 'BTC' && candle.max >= takeProfit)) { + + if (baseAsset === 'BTC') { + balanceAssetA = balanceAssetA + balanceAssetB / takeProfit; + balanceAssetB = 0; + } else { + balanceAssetB = balanceAssetB + balanceAssetA * takeProfit; + balanceAssetA = 0; + } + + if (currentDay !== undefined) { + if (positionInstant < currentDay.valueOf()) { + yesterday.balanceAssetA = balanceAssetA; + yesterday.balanceAssetB = balanceAssetB; + + } + } + + marketRate = takeProfit; + type = '"Buy@TakeProfit"'; + strategyStage = 'Close Stage'; + stopLossStage = 'No Stage'; + takeProfitStage = 'No Stage'; + currentTrade.end = candle.end; + currentTrade.status = 1; + currentTrade.exitType = 2; + currentTrade.endRate = takeProfit; + + currentStrategy.number = currentStrategyIndex + currentStrategy.end = candle.end; + currentStrategy.endRate = candle.min; + currentStrategy.status = 1; } } From 40a045298d1658708a9e094f4f3efb2e8fb935c4 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 27 Jun 2019 14:04:22 +0200 Subject: [PATCH 149/244] Bug Fixed: if (strategyStage === 'Trigger Stage' || strategyStage === 'No Stage') { --- Commons.js | 96 +++++++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/Commons.js b/Commons.js index 08685cd63..630de1ccf 100644 --- a/Commons.js +++ b/Commons.js @@ -400,7 +400,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* We set some variables that would be nice if they have a value before the formulas are calculated. */ - if (strategyStage === 'Trigger Stage') { + if (strategyStage === 'Trigger Stage' || strategyStage === 'No Stage') { positionRate = candle.close; @@ -1388,56 +1388,56 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } orderRecord = createMessage( - messageId, - MESSAGE_ENTITY.SimulationEngine, - MESSAGE_ENTITY.SimulationExecutor, - messageType, - (new Date()).valueOf(), - orderId.toString(), - ORDER_CREATOR.SimulationEngine, - (new Date()).valueOf(), - ORDER_OWNER.User, - global.EXCHANGE_NAME, - "BTC_USDT", - 0, - ORDER_TYPE.Limit, - marketRate, - stopLoss, - takeProfit, - ORDER_DIRECTION.Sell, - -1, - ORDER_STATUS.Signaled, - 0, - "") + messageId, + MESSAGE_ENTITY.SimulationEngine, + MESSAGE_ENTITY.SimulationExecutor, + messageType, + (new Date()).valueOf(), + orderId.toString(), + ORDER_CREATOR.SimulationEngine, + (new Date()).valueOf(), + ORDER_OWNER.User, + global.EXCHANGE_NAME, + "BTC_USDT", + 0, + ORDER_TYPE.Limit, + marketRate, + stopLoss, + takeProfit, + ORDER_DIRECTION.Sell, + -1, + ORDER_STATUS.Signaled, + 0, + "") } else { orderRecord = createMessage( - messageId, - MESSAGE_ENTITY.SimulationEngine, - MESSAGE_ENTITY.SimulationExecutor, - MESSAGE_TYPE.HeartBeat, - (new Date()).valueOf(), - "", - "", - 0, - "", - "", - "", - 0, - "", - 0, - 0, - 0, - "", - 0, - "", - 0, - "") + messageId, + MESSAGE_ENTITY.SimulationEngine, + MESSAGE_ENTITY.SimulationExecutor, + MESSAGE_TYPE.HeartBeat, + (new Date()).valueOf(), + "", + "", + 0, + "", + "", + "", + 0, + "", + 0, + 0, + 0, + "", + 0, + "", + 0, + "") } - let strategyStageNumber + let strategyStageNumber switch (strategyStage) { case 'No Stage': { strategyStageNumber = 0 @@ -1461,6 +1461,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } + if (balanceAssetA === Infinity) { + balanceAssetA = Number.MAX_SAFE_INTEGER + } + + if (balanceAssetB === Infinity) { + balanceAssetB = Number.MAX_SAFE_INTEGER + } + simulationRecord = { begin: candle.begin, end: candle.end, From 2691dd2c543775b4ff7e86f15e9750d0b3ee7cb5 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 27 Jun 2019 21:12:45 +0200 Subject: [PATCH 150/244] BUG FIXED: When a condition does not have a code object --- Commons.js | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/Commons.js b/Commons.js index 630de1ccf..9b6a0e6a0 100644 --- a/Commons.js +++ b/Commons.js @@ -791,7 +791,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let condition = situation.conditions[m]; let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; - let value = conditions.get(key).value; + let value = false + if (conditions.get(key) !== undefined) { + value = conditions.get(key).value; + } if (value === false) { passed = false; } } @@ -836,7 +839,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let condition = situation.conditions[m]; let key = currentStrategyIndex + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; - let value = conditions.get(key).value; + let value = false + if (conditions.get(key) !== undefined) { + value = conditions.get(key).value; + } if (value === false) { passed = false; } } @@ -878,7 +884,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let condition = situation.conditions[m]; let key = currentStrategyIndex + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; - let value = conditions.get(key).value; + let value = false + if (conditions.get(key) !== undefined) { + value = conditions.get(key).value; + } if (value === false) { passed = false; } } @@ -960,7 +969,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let condition = situation.conditions[m]; let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; - let value = conditions.get(key).value; + let value = false + if (conditions.get(key) !== undefined) { + value = conditions.get(key).value; + } if (value === false) { passed = false; } } @@ -1065,7 +1077,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let condition = situation.conditions[m]; let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; - let value = conditions.get(key).value; + let value = false + if (conditions.get(key) !== undefined) { + value = conditions.get(key).value; + } if (value === false) { passed = false; } } From 719ca3d6b25ac68230cdcc06b51d2f3d3fed9d25 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 28 Jun 2019 13:48:44 +0200 Subject: [PATCH 151/244] Several Bug Fixes: No taking profit and closing at the same candle --- Commons.js | 80 +++++++++++++++------------------ Multi-Period-Daily/User.Bot.js | 6 +-- Multi-Period-Market/User.Bot.js | 6 +-- 3 files changed, 41 insertions(+), 51 deletions(-) diff --git a/Commons.js b/Commons.js index 9b6a0e6a0..8dfc42d87 100644 --- a/Commons.js +++ b/Commons.js @@ -239,9 +239,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let balanceAssetA = initialBalanceA; let balanceAssetB = initialBalanceB; - let lastProfit = 0; + let lastTradeProfitLoss = 0; let profit = 0; - let lastProfitPercent = 0; + let lastTradeROI = 0; let roundtrips = 0; let fails = 0; @@ -258,9 +258,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { yesterday.balanceAssetA = balanceAssetA; yesterday.balanceAssetB = balanceAssetB; - yesterday.lastProfit = 0; + yesterday.lastTradeProfitLoss = 0; yesterday.profit = 0; - yesterday.lastProfitPercent = 0; + yesterday.lastTradeROI = 0; yesterday.Roundtrips = 0; yesterday.fails = 0; @@ -281,9 +281,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { interExecutionMemory.balanceAssetA = balanceAssetA; interExecutionMemory.balanceAssetB = balanceAssetB; - interExecutionMemory.lastProfit = lastProfit; + interExecutionMemory.lastTradeProfitLoss = lastTradeProfitLoss; interExecutionMemory.profit = profit; - interExecutionMemory.lastProfitPercent = lastProfitPercent; + interExecutionMemory.lastTradeROI = lastTradeROI; interExecutionMemory.roundtrips = 0; interExecutionMemory.fails = 0; @@ -311,9 +311,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } - lastProfit = interExecutionMemory.lastProfit; + lastTradeProfitLoss = interExecutionMemory.lastTradeProfitLoss; profit = interExecutionMemory.profit; - lastProfitPercent = interExecutionMemory.lastProfitPercent; + lastTradeROI = interExecutionMemory.lastTradeROI; roundtrips = interExecutionMemory.roundtrips; fails = interExecutionMemory.fails; @@ -739,6 +739,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } + /* Trigger On Conditions */ if ( strategyStage === 'No Stage' && currentStrategyIndex === -1 @@ -758,7 +759,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } if (balance > minimunBalance && balance < maximunBalance) { - /* Trigger On Conditions */ /* Here we need to pick a strategy, or if there is not suitable strategy for the current @@ -818,7 +818,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } /* Trigger Off Condition */ - if (strategyStage === 'Trigger Stage') { let strategy = tradingSystem.strategies[currentStrategyIndex]; @@ -863,7 +862,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } /* Take Position Condition */ - if (strategyStage === 'Trigger Stage') { let strategy = tradingSystem.strategies[currentStrategyIndex]; @@ -912,10 +910,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } /* Stop Loss Management */ - if ( - strategyStage === 'Open Stage' || - strategyStage === 'Manage Stage' + (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') && + takePositionNow !== true ) { checkStopPhases() @@ -1020,10 +1017,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } /* Take Profit Management */ - if ( - strategyStage === 'Open Stage' || - strategyStage === 'Manage Stage' + (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') && + takePositionNow !== true ) { checkTakeProfitPhases(); @@ -1128,10 +1124,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } /* Checking if Stop or Take Profit were hit */ - if ( - strategyStage === 'Open Stage' || - strategyStage === 'Manage Stage' + (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') && + takePositionNow !== true ) { /* Checking what happened since the last execution. We need to know if the Stop Loss @@ -1210,7 +1205,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } /* Taking a Position */ - if ( takePositionNow === true ) { @@ -1254,14 +1248,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { marketRate = candle.close; - calculateStopLoss(); - calculateTakeProfit(); - previousBalanceAssetA = balanceAssetA; previousBalanceAssetB = balanceAssetB; - lastProfit = 0; - lastProfitPercent = 0; + lastTradeProfitLoss = 0; + lastTradeROI = 0; if (baseAsset === 'BTC') { balanceAssetB = balanceAssetB + positionSize * positionRate; @@ -1278,8 +1269,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { yesterday.balanceAssetA = balanceAssetA; yesterday.balanceAssetB = balanceAssetB; - yesterday.lastProfit = lastProfit; - yesterday.lastProfitPercent = lastProfitPercent; + yesterday.lastTradeProfitLoss = lastTradeProfitLoss; + yesterday.lastTradeROI = lastTradeROI; } } @@ -1288,7 +1279,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } /* Closing a Position */ - if (strategyStage === 'Close Stage') { roundtrips++; @@ -1300,29 +1290,29 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } if (baseAsset === 'BTC') { - lastProfit = balanceAssetA - previousBalanceAssetA; - lastProfitPercent = lastProfit / previousBalanceAssetA * 100; - if (isNaN(lastProfitPercent)) { lastProfitPercent = 0; } + lastTradeProfitLoss = balanceAssetA - previousBalanceAssetA; + lastTradeROI = lastTradeProfitLoss * 100 / positionSize; + if (isNaN(lastTradeROI)) { lastTradeROI = 0; } profit = balanceAssetA - initialBalanceA; } else { - lastProfit = balanceAssetB - previousBalanceAssetB; - lastProfitPercent = lastProfit / previousBalanceAssetB * 100; - if (isNaN(lastProfitPercent)) { lastProfitPercent = 0; } + lastTradeProfitLoss = balanceAssetB - previousBalanceAssetB; + lastTradeROI = lastTradeProfitLoss * 100 / positionSize; + if (isNaN(lastTradeROI)) { lastTradeROI = 0; } profit = balanceAssetB - initialBalanceB; } if (currentDay !== undefined) { if (positionInstant < currentDay.valueOf()) { - yesterday.lastProfit = lastProfit; + yesterday.lastTradeProfitLoss = lastTradeProfitLoss; yesterday.profit = profit; - yesterday.lastProfitPercent = lastProfitPercent; + yesterday.lastTradeROI = lastTradeROI; } } - currentTrade.lastProfitPercent = lastProfitPercent; + currentTrade.lastTradeROI = lastTradeROI; currentTrade.stopRate = stopLoss; - if (lastProfit > 0) { + if (lastTradeProfitLoss > 0) { hits++; if (currentDay !== undefined) { @@ -1493,7 +1483,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { balanceA: balanceAssetA, balanceB: balanceAssetB, profit: profit, - lastProfit: lastProfit, + lastTradeProfitLoss: lastTradeProfitLoss, stopLoss: stopLoss, roundtrips: roundtrips, hits: hits, @@ -1504,7 +1494,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { days: days, anualizedRateOfReturn: anualizedRateOfReturn, positionRate: positionRate, - lastProfitPercent: lastProfitPercent, + lastTradeROI: lastTradeROI, strategy: currentStrategyIndex, strategyStageNumber: strategyStageNumber, takeProfit: takeProfit, @@ -1562,7 +1552,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { (currentTrade.begin !== 0 && i === candles.length - 1 && lastCandle.end !== lastInstantOfTheDay) ) { - currentTrade.profit = lastProfit; + currentTrade.profit = lastTradeProfitLoss; tradesArray.push(currentTrade); @@ -1570,7 +1560,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { begin: 0, end: 0, status: 0, - lastProfitPercent: 0, + lastTradeROI: 0, exitType: 0, beginRate: 0, endRate: 0 @@ -1590,9 +1580,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { interExecutionMemory.balanceAssetA = yesterday.balanceAssetA; interExecutionMemory.balanceAssetB = yesterday.balanceAssetB; - interExecutionMemory.lastProfit = yesterday.lastProfit; + interExecutionMemory.lastTradeProfitLoss = yesterday.lastTradeProfitLoss; interExecutionMemory.profit = yesterday.profit; - interExecutionMemory.lastProfitPercent = yesterday.lastProfitPercent; + interExecutionMemory.lastTradeROI = yesterday.lastTradeROI; interExecutionMemory.roundtrips = interExecutionMemory.roundtrips + yesterday.Roundtrips; interExecutionMemory.fails = interExecutionMemory.fails + yesterday.fails; diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 9bd5892a0..905046f12 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -141,7 +141,7 @@ record.balanceA + "," + record.balanceB + "," + record.profit + "," + - record.lastProfit + "," + + record.lastTradeProfitLoss + "," + record.stopLoss + "," + record.roundtrips + "," + record.hits + "," + @@ -152,7 +152,7 @@ record.days + "," + record.anualizedRateOfReturn + "," + record.positionRate + "," + - record.lastProfitPercent + "," + + record.lastTradeROI + "," + record.strategy + "," + record.strategyStageNumber + "," + record.takeProfit + "," + @@ -407,7 +407,7 @@ record.begin + "," + record.end + "," + record.status + "," + - record.lastProfitPercent + "," + + record.lastTradeROI + "," + record.beginRate + "," + record.endRate + "," + record.exitType + "," + diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 8c976caed..7c3c96331 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -137,7 +137,7 @@ record.balanceA + "," + record.balanceB + "," + record.profit + "," + - record.lastProfit + "," + + record.lastTradeProfitLoss + "," + record.stopLoss + "," + record.roundtrips + "," + record.hits + "," + @@ -148,7 +148,7 @@ record.days + "," + record.anualizedRateOfReturn + "," + record.positionRate + "," + - record.lastProfitPercent + "," + + record.lastTradeROI + "," + record.strategy + "," + record.strategyStageNumber + "," + record.takeProfit + "," + @@ -380,7 +380,7 @@ record.begin + "," + record.end + "," + record.status + "," + - record.lastProfitPercent + "," + + record.lastTradeROI + "," + record.beginRate + "," + record.endRate + "," + record.exitType + "," + From 28c6ea2c3efc2e96d34a9bcdd98b451b8fb8355c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 28 Jun 2019 15:28:58 +0200 Subject: [PATCH 152/244] minimuN for minimuM --- Commons.js | 72 ++++++++++++++++----------------- Multi-Period-Daily/User.Bot.js | 8 ++-- Multi-Period-Market/User.Bot.js | 8 ++-- 3 files changed, 44 insertions(+), 44 deletions(-) diff --git a/Commons.js b/Commons.js index 8dfc42d87..5faf1e137 100644 --- a/Commons.js +++ b/Commons.js @@ -80,11 +80,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { const DEFAULT_BASE_ASSET_MAXIMUN_BALANCE = 2 let initialBalanceA = DEFAULT_BASE_ASSET_BALANCE - let minimunBalanceA = DEFAULT_BASE_ASSET_MINIMUN_BALANCE - let maximunBalanceA = DEFAULT_BASE_ASSET_MAXIMUN_BALANCE + let minimumBalanceA = DEFAULT_BASE_ASSET_MINIMUN_BALANCE + let maximumBalanceA = DEFAULT_BASE_ASSET_MAXIMUN_BALANCE let initialBalanceB = 0 - let minimunBalanceB = 0 - let maximunBalanceB = 0 + let minimumBalanceB = 0 + let maximumBalanceB = 0 let baseAsset = 'BTC' /* Parameters Processing */ @@ -112,19 +112,19 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { initialBalanceA = DEFAULT_BASE_ASSET_BALANCE; initialBalanceB = 0 } - if (receivedParameters.minimunBalance !== undefined) { - minimunBalanceA = receivedParameters.minimunBalance; - minimunBalanceB = 0 + if (receivedParameters.minimumBalance !== undefined) { + minimumBalanceA = receivedParameters.minimumBalance; + minimumBalanceB = 0 } else { - minimunBalanceA = DEFAULT_BASE_ASSET_MINIMUN_BALANCE; - minimunBalanceB = 0 + minimumBalanceA = DEFAULT_BASE_ASSET_MINIMUN_BALANCE; + minimumBalanceB = 0 } - if (receivedParameters.maximunBalance !== undefined) { - maximunBalanceA = receivedParameters.maximunBalance; - maximunBalanceB = 0 + if (receivedParameters.maximumBalance !== undefined) { + maximumBalanceA = receivedParameters.maximumBalance; + maximumBalanceB = 0 } else { - maximunBalanceA = DEFAULT_BASE_ASSET_MAXIMUN_BALANCE; - maximunBalanceB = 0 + maximumBalanceA = DEFAULT_BASE_ASSET_MAXIMUN_BALANCE; + maximumBalanceB = 0 } } else { if (receivedParameters.initialBalance !== undefined) { @@ -134,19 +134,19 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { initialBalanceB = DEFAULT_BASE_ASSET_BALANCE; initialBalanceA = 0 } - if (receivedParameters.minimunBalance !== undefined) { - minimunBalanceB = receivedParameters.minimunBalance; - minimunBalanceA = 0 + if (receivedParameters.minimumBalance !== undefined) { + minimumBalanceB = receivedParameters.minimumBalance; + minimumBalanceA = 0 } else { - minimunBalanceB = DEFAULT_BASE_ASSET_MINIMUN_BALANCE; - minimunBalanceA = 0 + minimumBalanceB = DEFAULT_BASE_ASSET_MINIMUN_BALANCE; + minimumBalanceA = 0 } - if (receivedParameters.maximunBalance !== undefined) { - maximunBalanceB = receivedParameters.maximunBalance; - maximunBalanceA = 0 + if (receivedParameters.maximumBalance !== undefined) { + maximumBalanceB = receivedParameters.maximumBalance; + maximumBalanceA = 0 } else { - maximunBalanceB = DEFAULT_BASE_ASSET_MAXIMUN_BALANCE; - maximunBalanceA = 0 + maximumBalanceB = DEFAULT_BASE_ASSET_MAXIMUN_BALANCE; + maximumBalanceA = 0 } } } catch (err) { @@ -744,21 +744,21 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategyStage === 'No Stage' && currentStrategyIndex === -1 ) { - let minimunBalance - let maximunBalance + let minimumBalance + let maximumBalance let balance if (baseAsset === 'BTC') { balance = balanceAssetA - minimunBalance = minimunBalanceA - maximunBalance = maximunBalanceA + minimumBalance = minimumBalanceA + maximumBalance = maximumBalanceA } else { balance = balanceAssetB - minimunBalance = minimunBalanceB - maximunBalance = maximunBalanceB + minimumBalance = minimumBalanceB + maximumBalance = maximumBalanceB } - if (balance > minimunBalance && balance < maximunBalance) { + if (balance > minimumBalance && balance < maximumBalance) { /* Here we need to pick a strategy, or if there is not suitable strategy for the current @@ -813,7 +813,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } } else { - tradingSystem.error = "Balance below the minimun. No more strategies will be executed." + tradingSystem.error = "Balance below the minimum. No more strategies will be executed." } } @@ -1503,11 +1503,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { orderRecord: orderRecord, positionSize: positionSize, initialBalanceA: initialBalanceA, - minimunBalanceA: minimunBalanceA, - maximunBalanceA: maximunBalanceA, + minimumBalanceA: minimumBalanceA, + maximumBalanceA: maximumBalanceA, initialBalanceB: initialBalanceB, - minimunBalanceB: minimunBalanceB, - maximunBalanceB: maximunBalanceB + minimumBalanceB: minimumBalanceB, + maximumBalanceB: maximumBalanceB } recordsArray.push(simulationRecord); diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 905046f12..ab7cbff0a 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -161,11 +161,11 @@ JSON.stringify(record.orderRecord) + "," + record.positionSize + "," + record.initialBalanceA + "," + - record.minimunBalanceA + "," + - record.maximunBalanceA + "," + + record.minimumBalanceA + "," + + record.maximumBalanceA + "," + record.initialBalanceB + "," + - record.minimunBalanceB + "," + - record.maximunBalanceB + "]"; + record.minimumBalanceB + "," + + record.maximumBalanceB + "]"; if (separator === "") { separator = ","; } diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 7c3c96331..5a3f176a3 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -157,11 +157,11 @@ JSON.stringify(record.orderRecord) + "," + record.positionSize + "," + record.initialBalanceA + "," + - record.minimunBalanceA + "," + - record.maximunBalanceA + "," + + record.minimumBalanceA + "," + + record.maximumBalanceA + "," + record.initialBalanceB + "," + - record.minimunBalanceB + "," + - record.maximunBalanceB + "]"; + record.minimumBalanceB + "," + + record.maximumBalanceB + "]"; if (separator === "") { separator = ","; } From a6ceb4550ebf1e717dd8c86514bbe6f0e1cd6ebb Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 28 Jun 2019 15:58:37 +0200 Subject: [PATCH 153/244] position Rate at right place --- Commons.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/Commons.js b/Commons.js index 5faf1e137..137123eb2 100644 --- a/Commons.js +++ b/Commons.js @@ -398,14 +398,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let formulasErrors = []; // Here we store the errors produced by all phase formulas. let formulasValues = []; // Here we store the values produced by all phase formulas. - /* We set some variables that would be nice if they have a value before the formulas are calculated. */ - - if (strategyStage === 'Trigger Stage' || strategyStage === 'No Stage') { - - positionRate = candle.close; - - } - /* We define and evaluate all conditions to be used later during the simulation loop. */ conditionsArrayRecord.push(candle.begin); @@ -1247,6 +1239,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } marketRate = candle.close; + positionRate = candle.close; previousBalanceAssetA = balanceAssetA; previousBalanceAssetB = balanceAssetB; From ddbbf72f2481c5ccba6aed30bc72b11702f21063 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 28 Jun 2019 22:53:57 +0200 Subject: [PATCH 154/244] Improving error message --- Commons.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index 137123eb2..c9f62e8fe 100644 --- a/Commons.js +++ b/Commons.js @@ -805,7 +805,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } } else { - tradingSystem.error = "Balance below the minimum. No more strategies will be executed." + if (balance < minimumBalance) { + tradingSystem.error = "Balance below the minimum." + } + if (balance > maximumBalance) { + tradingSystem.error = "Balance above the maximum." + } } } From d821678c9ca5408949df185979acc51770c7c869 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 29 Jun 2019 00:15:47 +0200 Subject: [PATCH 155/244] Some Logs to trace BUG that records empty array files --- Commons.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index c9f62e8fe..575452cd3 100644 --- a/Commons.js +++ b/Commons.js @@ -73,7 +73,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Initial Default Values */ - let initialDate = startDate; + let initialDate = startDate; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> initialDate = " + initialDate); } const DEFAULT_BASE_ASSET_BALANCE = 1 const DEFAULT_BASE_ASSET_MINIMUN_BALANCE = 0.5 @@ -334,6 +335,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } /* Main Simulation Loop: We go thourgh all the candles at this time period. */ + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Main Simulation Loop -> candles.length = " + candles.length); } for (let i = 0; i < candles.length; i++) { @@ -1596,6 +1598,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> callback -> recordsArray.length = " + recordsArray.length); } + callback(tradingSystem); function getElement(pArray, begin, end) { From 47713820bb68bcae6f8d473901a23b074bd8cbb3 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 29 Jun 2019 10:04:22 +0200 Subject: [PATCH 156/244] BUG FIXED: Empty records files generated --- Commons.js | 16 +++++++++------- Multi-Period-Daily/User.Bot.js | 29 ++++++++++++++++------------- Multi-Period-Market/User.Bot.js | 27 +++++++++++++++------------ 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/Commons.js b/Commons.js index 575452cd3..22fd45e09 100644 --- a/Commons.js +++ b/Commons.js @@ -53,22 +53,24 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } async function runSimulation( - recordsArray, - conditionsArray, - strategiesArray, - tradesArray, - lastObjectsArray, timePeriod, currentDay, startDate, endDate, interExecutionMemory, - callback) { + callback, + callBackFunction) { try { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Entering function."); } + let recordsArray = []; + let conditionsArray = []; + let strategiesArray = []; + let tradesArray = []; + let lastObjectsArray = []; + let tradingSystem = await strategy.getStrategy(); /* Initial Default Values */ @@ -1600,7 +1602,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> callback -> recordsArray.length = " + recordsArray.length); } - callback(tradingSystem); + callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, tradesArray, lastObjectsArray); function getElement(pArray, begin, end) { diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index ab7cbff0a..62f56eaa9 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -51,14 +51,14 @@ let market = global.MARKET; let dataFile; - let recordsArray = []; - let conditionsArray = []; - let strategiesArray = []; - let tradesArray = []; + let recordsArray + let conditionsArray + let strategiesArray + let tradesArray + let lastObjectsArray let tradingSystem = {}; - let lastObjectsArray = []; - + commons.initializeData(); for (let i = 0; i < dataDependencies.config.length; i++) { @@ -96,20 +96,23 @@ } commons.runSimulation( - recordsArray, - conditionsArray, - strategiesArray, - tradesArray, - lastObjectsArray, timePeriod, currentDay, startDate, endDate, interExecutionMemory, - writeFiles) + writeFiles, + callBackFunction) + + function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) { - function writeFiles(pTradingSystem) { tradingSystem = pTradingSystem + recordsArray = pRecordsArray + conditionsArray = pConditionsArray + strategiesArray = pStrategiesArray + tradesArray = pTradesArray + lastObjectsArray = pLastObjectsArray + writeRecordsFile() } diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 5a3f176a3..cd9f46fcd 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -49,11 +49,11 @@ let market = global.MARKET; let dataFile; - let recordsArray = []; - let conditionsArray = []; - let strategiesArray = []; - let tradesArray = []; - let lastObjectsArray = []; + let recordsArray + let conditionsArray + let strategiesArray + let tradesArray + let lastObjectsArray let tradingSystem = {}; let interExecutionMemory = {}; @@ -96,20 +96,23 @@ } commons.runSimulation( - recordsArray, - conditionsArray, - strategiesArray, - tradesArray, - lastObjectsArray, timePeriod, currentDay, startDate, endDate, interExecutionMemory, - writeFiles) + writeFiles, + callBackFunction) + + function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) { - function writeFiles(pTradingSystem) { tradingSystem = pTradingSystem + recordsArray = pRecordsArray + conditionsArray = pConditionsArray + strategiesArray = pStrategiesArray + tradesArray = pTradesArray + lastObjectsArray = pLastObjectsArray + writeRecordsFile() } From 27b1af9ef447a6164775104f8074e42836e9f704 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 30 Jun 2019 11:56:16 +0200 Subject: [PATCH 157/244] sending baseasset to file --- Commons.js | 5 ++++- Multi-Period-Daily/User.Bot.js | 3 ++- Multi-Period-Market/User.Bot.js | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Commons.js b/Commons.js index 22fd45e09..d9a660921 100644 --- a/Commons.js +++ b/Commons.js @@ -1476,6 +1476,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { balanceAssetB = Number.MAX_SAFE_INTEGER } + let quotedBaseAsset = '"' + baseAsset + '"' + simulationRecord = { begin: candle.begin, end: candle.end, @@ -1509,7 +1511,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { maximumBalanceA: maximumBalanceA, initialBalanceB: initialBalanceB, minimumBalanceB: minimumBalanceB, - maximumBalanceB: maximumBalanceB + maximumBalanceB: maximumBalanceB, + baseAsset: quotedBaseAsset } recordsArray.push(simulationRecord); diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 62f56eaa9..2b249a0d0 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -168,7 +168,8 @@ record.maximumBalanceA + "," + record.initialBalanceB + "," + record.minimumBalanceB + "," + - record.maximumBalanceB + "]"; + record.maximumBalanceB + "," + + record.baseAsset + "]"; if (separator === "") { separator = ","; } diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index cd9f46fcd..2631be8e9 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -164,7 +164,8 @@ record.maximumBalanceA + "," + record.initialBalanceB + "," + record.minimumBalanceB + "," + - record.maximumBalanceB + "]"; + record.maximumBalanceB + "," + + record.baseAsset + "]"; if (separator === "") { separator = ","; } From 82294ff6ef00e5cfd1040efd3525e1e1aa1c1d0e Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 5 Jul 2019 18:32:23 +0200 Subject: [PATCH 158/244] File for Executor --- Commons.js | 75 +++++++++++++++++------------- Multi-Period-Daily/User.Bot.js | 82 +++++++++++++++++++++++++++++++-- Multi-Period-Market/User.Bot.js | 77 +++++++++++++++++++++++++++++-- 3 files changed, 197 insertions(+), 37 deletions(-) diff --git a/Commons.js b/Commons.js index d9a660921..d139ebd3e 100644 --- a/Commons.js +++ b/Commons.js @@ -65,6 +65,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Entering function."); } + let executionArray = []; let recordsArray = []; let conditionsArray = []; let strategiesArray = []; @@ -893,7 +894,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (passed) { - type = '"Sell"'; + type = '"Take Position"'; strategyStage = 'Open Stage'; stopLossStage = 'Open Stage'; @@ -1153,7 +1154,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } marketRate = stopLoss; - type = '"Buy@StopLoss"'; + type = '"Close@StopLoss"'; strategyStage = 'Close Stage'; stopLossStage = 'No Stage'; takeProfitStage = 'No Stage'; @@ -1189,7 +1190,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } marketRate = takeProfit; - type = '"Buy@TakeProfit"'; + type = '"Close@TakeProfit"'; strategyStage = 'Close Stage'; stopLossStage = 'No Stage'; takeProfitStage = 'No Stage'; @@ -1380,21 +1381,25 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let messageType; let message; let simulationRecord; - let orderRecord; + let executionRecord; + let executionMessage; messageId++; - if (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') { + if (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage' || type === '"Close@TakeProfit"' || type === '"Close@StopLoss"') { - if (strategyStage === 'Open Stage') { + if (type === '"Take Position"') { messageType = MESSAGE_TYPE.Order; orderId++; - } - if (strategyStage === 'Manage Stage') { - messageType = MESSAGE_TYPE.OrderUpdate; + } else { + if (type === '"Close@TakeProfit"' || type === '"Close@StopLoss"') { + messageType = MESSAGE_TYPE.OrderUpdate; + } else { + messageType = MESSAGE_TYPE.OrderUpdate; + } } - orderRecord = createMessage( + executionMessage = createMessage( messageId, MESSAGE_ENTITY.SimulationEngine, MESSAGE_ENTITY.SimulationExecutor, @@ -1420,7 +1425,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } else { - orderRecord = createMessage( + executionMessage = createMessage( messageId, MESSAGE_ENTITY.SimulationEngine, MESSAGE_ENTITY.SimulationExecutor, @@ -1444,6 +1449,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { "") } + executionRecord = { + begin: candle.begin, + end: candle.end, + executionRecord: executionMessage + } + + executionArray.push(executionRecord) + let strategyStageNumber switch (strategyStage) { case 'No Stage': { @@ -1504,7 +1517,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { takeProfit: takeProfit, stopLossPhase: stopLossPhase, takeProfitPhase: takeProfitPhase, - orderRecord: orderRecord, + executionRecord: executionMessage, positionSize: positionSize, initialBalanceA: initialBalanceA, minimumBalanceA: minimumBalanceA, @@ -1605,7 +1618,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> callback -> recordsArray.length = " + recordsArray.length); } - callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, tradesArray, lastObjectsArray); + callback(tradingSystem, executionArray, recordsArray, conditionsArray, strategiesArray, tradesArray, lastObjectsArray); function getElement(pArray, begin, end) { @@ -1653,17 +1666,17 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (previous !== undefined) { - if (previous._15 > LRC._15) { LRC.direction15 = 'down'; } - if (previous._15 < LRC._15) { LRC.direction15 = 'up'; } - if (previous._15 === LRC._15) { LRC.direction15 = 'side'; } + if (previous._15 > LRC._15) { LRC.direction15 = 'Down'; } + if (previous._15 < LRC._15) { LRC.direction15 = 'Up'; } + if (previous._15 === LRC._15) { LRC.direction15 = 'Side'; } - if (previous._30 > LRC._30) { LRC.direction30 = 'down'; } - if (previous._30 < LRC._30) { LRC.direction30 = 'up'; } - if (previous._30 === LRC._30) { LRC.direction30 = 'side'; } + if (previous._30 > LRC._30) { LRC.direction30 = 'Down'; } + if (previous._30 < LRC._30) { LRC.direction30 = 'Up'; } + if (previous._30 === LRC._30) { LRC.direction30 = 'Side'; } - if (previous._60 > LRC._60) { LRC.direction60 = 'down'; } - if (previous._60 < LRC._60) { LRC.direction60 = 'up'; } - if (previous._60 === LRC._60) { LRC.direction60 = 'side'; } + if (previous._60 > LRC._60) { LRC.direction60 = 'Down'; } + if (previous._60 < LRC._60) { LRC.direction60 = 'Up'; } + if (previous._60 === LRC._60) { LRC.direction60 = 'Side'; } } @@ -1700,9 +1713,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (previous !== undefined) { - if (previous.movingAverage > percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'down'; } - if (previous.movingAverage < percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'up'; } - if (previous.movingAverage === percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'side'; } + if (previous.movingAverage > percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'Down'; } + if (previous.movingAverage < percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'Up'; } + if (previous.movingAverage === percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'Side'; } } @@ -1739,9 +1752,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (previous !== undefined) { - if (previous.movingAverage > bollingerBand.movingAverage) { bollingerBand.direction = 'down'; } - if (previous.movingAverage < bollingerBand.movingAverage) { bollingerBand.direction = 'up'; } - if (previous.movingAverage === bollingerBand.movingAverage) { bollingerBand.direction = 'side'; } + if (previous.movingAverage > bollingerBand.movingAverage) { bollingerBand.direction = 'Down'; } + if (previous.movingAverage < bollingerBand.movingAverage) { bollingerBand.direction = 'Up'; } + if (previous.movingAverage === bollingerBand.movingAverage) { bollingerBand.direction = 'Side'; } } @@ -1856,9 +1869,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { candle.begin = dataFile[i][4]; candle.end = dataFile[i][5]; - if (candle.open > candle.close) { candle.direction = 'down'; } - if (candle.open < candle.close) { candle.direction = 'up'; } - if (candle.open === candle.close) { candle.direction = 'side'; } + if (candle.open > candle.close) { candle.direction = 'Down'; } + if (candle.open < candle.close) { candle.direction = 'Up'; } + if (candle.open === candle.close) { candle.direction = 'Side'; } candle.previous = previous; diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 2b249a0d0..94f18bbe3 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -5,6 +5,7 @@ const MODULE_NAME = "User Bot"; + const EXECUTION_FOLDER_NAME = "Trading-Execution"; const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; const STRATEGIES_FOLDER_NAME = "Simulation-Strategies"; @@ -104,16 +105,91 @@ writeFiles, callBackFunction) - function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) { + function writeFiles(pTradingSystem, pExecutionArray, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) { tradingSystem = pTradingSystem + executionArray = pExecutionArray recordsArray = pRecordsArray conditionsArray = pConditionsArray strategiesArray = pStrategiesArray tradesArray = pTradesArray lastObjectsArray = pLastObjectsArray - writeRecordsFile() + writeExecutionFile() + } + + function writeExecutionFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < executionArray.length; i++) { + + let record = executionArray[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 + "," + + JSON.stringify(record.executionRecord) + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + EXECUTION_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + filePath += '/' + fileName + + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + writeRecordsFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } } function writeRecordsFile() { @@ -161,7 +237,7 @@ record.takeProfit + "," + record.stopLossPhase + "," + record.takeProfitPhase + "," + - JSON.stringify(record.orderRecord) + "," + + JSON.stringify(record.executionRecord) + "," + record.positionSize + "," + record.initialBalanceA + "," + record.minimumBalanceA + "," + diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 2631be8e9..5e031fcb5 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -5,6 +5,7 @@ const MODULE_NAME = "User Bot"; + const EXECUTION_FOLDER_NAME = "Trading-Execution"; const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; const STRATEGIES_FOLDER_NAME = "Simulation-Strategies"; @@ -104,16 +105,86 @@ writeFiles, callBackFunction) - function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) { + function writeFiles(pTradingSystem, pExecutionArray, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) { tradingSystem = pTradingSystem + executionArray = pExecutionArray recordsArray = pRecordsArray conditionsArray = pConditionsArray strategiesArray = pStrategiesArray tradesArray = pTradesArray lastObjectsArray = pLastObjectsArray - writeRecordsFile() + writeExecutionFile() + } + + function writeExecutionFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < executionArray.length; i++) { + + let record = executionArray[i]; + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + JSON.stringify(record.executionRecord) + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + EXECUTION_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; + filePath += '/' + fileName + + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + writeRecordsFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } } function writeRecordsFile() { @@ -157,7 +228,7 @@ record.takeProfit + "," + record.stopLossPhase + "," + record.takeProfitPhase + "," + - JSON.stringify(record.orderRecord) + "," + + JSON.stringify(record.executionRecord) + "," + record.positionSize + "," + record.initialBalanceA + "," + record.minimumBalanceA + "," + From 329915fa1afefa4fdcfce794aa63865af0f87211 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 6 Jul 2019 10:45:08 +0200 Subject: [PATCH 159/244] Removing unneeded errors --- Commons.js | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/Commons.js b/Commons.js index d139ebd3e..4b127b3db 100644 --- a/Commons.js +++ b/Commons.js @@ -501,7 +501,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { formulaValue = MAX_STOP_LOSS_VALUE } } catch (err) { - formulaError = err.message + if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0 && i <= 5) { + /* + We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. + */ + } else { + formulaError = err.message + } } if (isNaN(formulaValue)) { formulaValue = 0; } if (formulaValue < MIN_STOP_LOSS_VALUE) { @@ -554,7 +560,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { formulaValue = MAX_TAKE_PROFIT_VALUE } } catch (err) { - formulaError = err.message + if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0 && i <= 5) { + /* + We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. + */ + } else { + formulaError = err.message + } } if (isNaN(formulaValue)) { formulaValue = 0; } if (formulaValue < MIN_TAKE_PROFIT_VALUE) { @@ -613,7 +625,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { formulaValue = MAX_STOP_LOSS_VALUE } } catch (err) { - formulaError = err.message + if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0 && i <= 5) { + /* + We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. + */ + } else { + formulaError = err.message + } } if (isNaN(formulaValue)) { formulaValue = 0; } if (formulaValue < MIN_STOP_LOSS_VALUE) { @@ -666,7 +684,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { formulaValue = MAX_TAKE_PROFIT_VALUE } } catch (err) { - formulaError = err.message + if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0 && i <= 5) { + /* + We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. + */ + } else { + formulaError = err.message + } } if (isNaN(formulaValue)) { formulaValue = 0; } if (formulaValue < MIN_TAKE_PROFIT_VALUE) { @@ -717,7 +741,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { reason and others, we will simply set the value to false. */ value = false - node.error = err.message + + if (node.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0 && i <= 5) { + /* + We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. + */ + } else { + node.error = err.message + } } condition = { @@ -810,11 +841,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } } else { + let stopRunningDate = new Date(candle.begin) if (balance < minimumBalance) { - tradingSystem.error = "Balance below the minimum." + tradingSystem.error = "Min Balance @ " + stopRunningDate.toUTCString() } if (balance > maximumBalance) { - tradingSystem.error = "Balance above the maximum." + tradingSystem.error = "Max Balance @ " + stopRunningDate.toUTCString() } } } From 27934d9f2ebf91ae093cc74531bf216ea032e31f Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 6 Jul 2019 11:13:09 +0200 Subject: [PATCH 160/244] Standarizing Variable Names --- Commons.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Commons.js b/Commons.js index 4b127b3db..7a1b97ae5 100644 --- a/Commons.js +++ b/Commons.js @@ -362,16 +362,16 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - let channel = getElement(bollingerChannelsArray, candle.begin, candle.end); - let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); + let bollingerChannel = getElement(bollingerChannelsArray, candle.begin, candle.end); + let bollingerSubChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); let lastObjects = { candle: clone(candle), //LRC: clone(LRC), bollingerBand: clone(bollingerBand), percentageBandwidth: clone(percentageBandwidth), - channel: clone(channel), - subChannel: clone(subChannel) + bollingerChannel: clone(bollingerChannel), + bollingerSubChannel: clone(bollingerSubChannel) } function clone(obj) { @@ -387,8 +387,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { //lastObjects.LRC.previous = undefined; lastObjects.bollingerBand.previous = undefined; lastObjects.percentageBandwidth.previous = undefined; - lastObjects.channel.previous = undefined; - lastObjects.subChannel.previous = undefined; + lastObjects.bollingerChannel.previous = undefined; + lastObjects.bollingerSubChannel.previous = undefined; lastObjectsArray.push(lastObjects); From 7c93c4d68e8ed3169b2434d87fef469b9c39f5f9 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 6 Jul 2019 11:54:06 +0200 Subject: [PATCH 161/244] Eliminating errors of previous --- Commons.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Commons.js b/Commons.js index 7a1b97ae5..722388405 100644 --- a/Commons.js +++ b/Commons.js @@ -501,7 +501,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { formulaValue = MAX_STOP_LOSS_VALUE } } catch (err) { - if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0 && i <= 5) { + if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { /* We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. */ @@ -560,7 +560,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { formulaValue = MAX_TAKE_PROFIT_VALUE } } catch (err) { - if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0 && i <= 5) { + if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { /* We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. */ @@ -625,7 +625,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { formulaValue = MAX_STOP_LOSS_VALUE } } catch (err) { - if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0 && i <= 5) { + if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { /* We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. */ @@ -684,7 +684,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { formulaValue = MAX_TAKE_PROFIT_VALUE } } catch (err) { - if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0 && i <= 5) { + if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { /* We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. */ @@ -742,7 +742,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { */ value = false - if (node.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0 && i <= 5) { + if (node.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { /* We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. */ From 1fb84584d06d8b92e01ea31a3a49fd82b0962e1b Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 7 Jul 2019 22:51:33 +0200 Subject: [PATCH 162/244] BUG FIX: Calculating over all indicators are present. TP and STOP at ORD --- Commons.js | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/Commons.js b/Commons.js index 722388405..9a81744f8 100644 --- a/Commons.js +++ b/Commons.js @@ -343,16 +343,25 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { for (let i = 0; i < candles.length; i++) { /* Update all the data objects available for the simulation. */ - + let candle = candles[i]; let percentageBandwidth = percentageBandwidthMap.get(candle.begin); let bollingerBand = bollingerBandsMap.get(candle.begin); + let bollingerChannel = getElement(bollingerChannelsArray, candle.begin, candle.end); + let bollingerSubChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); + //let LRC = LRCMap.get(candle.begin); - //if (LRC === undefined) { continue; } - if (percentageBandwidth === undefined) { continue; } // percentageBandwidth might start after the first few candles. - if (candle.begin < initialDate.valueOf()) { continue; } + /* If any of the needed indicators is missing, then that period is not calculated */ + if (candle.begin < initialDate.valueOf()) { continue; } + if (bollingerBand === undefined) { continue; } + if (percentageBandwidth === undefined) { continue; } // percentageBandwidth might start after the first few candles. + if (bollingerChannel === undefined) { continue; } + if (bollingerSubChannel === undefined) { continue; } + + //if (LRC === undefined) { continue; } + periods++; days = periods * timePeriod / ONE_DAY_IN_MILISECONDS; @@ -362,9 +371,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - let bollingerChannel = getElement(bollingerChannelsArray, candle.begin, candle.end); - let bollingerSubChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); - let lastObjects = { candle: clone(candle), //LRC: clone(LRC), @@ -1280,6 +1286,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } + calculateTakeProfit(); + calculateStopLoss(); + marketRate = candle.close; positionRate = candle.close; @@ -1664,12 +1673,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { return element } } - - element = { - direction: 'unknown', - slope: 'unknown' - }; - return element; } } catch (err) { From 5695c2515b18ff12bd0c9391800f9df84590bc2b Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 8 Jul 2019 17:08:56 +0200 Subject: [PATCH 163/244] positionRate from Formula Implemented --- Commons.js | 201 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 121 insertions(+), 80 deletions(-) diff --git a/Commons.js b/Commons.js index 9a81744f8..9e5352d8c 100644 --- a/Commons.js +++ b/Commons.js @@ -184,8 +184,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Simulation Records */ - let positionRate = 0; - let positionSize = 0; + let tradePositionRate = 0; + let tradePositionSize = 0; let positionInstant; let previousBalanceAssetA = 0; @@ -343,7 +343,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { for (let i = 0; i < candles.length; i++) { /* Update all the data objects available for the simulation. */ - + let candle = candles[i]; let percentageBandwidth = percentageBandwidthMap.get(candle.begin); let bollingerBand = bollingerBandsMap.get(candle.begin); @@ -361,7 +361,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (bollingerSubChannel === undefined) { continue; } //if (LRC === undefined) { continue; } - + periods++; days = periods * timePeriod / ONE_DAY_IN_MILISECONDS; @@ -422,6 +422,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let strategy = tradingSystem.strategies[j]; + let positionSize = 0 + let positionRate = 0 + + /* Continue with the rest of the formulas and conditions */ + let triggerStage = strategy.triggerStage if (triggerStage !== undefined) { @@ -485,10 +490,67 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (openStage !== undefined) { + /* Default Values*/ + if (baseAsset === 'BTC') { + positionSize = balanceAssetA; + positionRate = candle.close; + } else { + positionSize = balanceAssetB; + positionRate = candle.close; + } + let initialDefinition = openStage.initialDefinition if (initialDefinition !== undefined) { + if (tradePositionSize !== 0) { + positionSize = tradePositionSize + } else { + if (initialDefinition.positionSize !== undefined) { + if (initialDefinition.positionSize.formula !== undefined) { + try { + positionSize = eval(initialDefinition.positionSize.formula.code); + } catch (err) { + initialDefinition.positionSize.formula.error = err.message + } + if (isNaN(positionSize)) { + if (baseAsset === 'BTC') { + positionSize = balanceAssetA; + } else { + positionSize = balanceAssetB; + } + } else { + if (baseAsset === 'BTC') { + if (positionSize > balanceAssetA) { positionSize = balanceAssetA } + } else { + if (positionSize > balanceAssetB) { positionSize = balanceAssetB } + } + } + } + } + } + + if (tradePositionRate !== 0) { + positionRate = tradePositionRate + } else { + if (initialDefinition.positionRate !== undefined) { + if (initialDefinition.positionRate.formula !== undefined) { + try { + positionRate = eval(initialDefinition.positionRate.formula.code); + } catch (err) { + initialDefinition.positionRate.formula.error = err.message + } + if (isNaN(positionRate)) { + if (baseAsset === 'BTC') { + positionRate = candle.close; + } else { + positionRate = candle.close; + } + } + } + } + } + if (initialDefinition.stopLoss !== undefined) { for (let p = 0; p < initialDefinition.stopLoss.phases.length; p++) { @@ -607,6 +669,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } } + + strategy.positionSize = positionSize + strategy.positionRate = positionRate } let manageStage = strategy.manageStage @@ -731,46 +796,45 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } } - } - function newCondition(key, node) { + function newCondition(key, node) { - let condition; - let error = '' - let value + let condition; + let error = '' + let value - try { - value = eval(node.code); - } catch (err) { - /* - One possible error is that the conditions references a .previous that is undefined. For this - reason and others, we will simply set the value to false. - */ - value = false - - if (node.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { + try { + value = eval(node.code); + } catch (err) { /* - We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. + One possible error is that the conditions references a .previous that is undefined. For this + reason and others, we will simply set the value to false. */ + value = false + + if (node.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { + /* + We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. + */ + } else { + node.error = err.message + } + } + + condition = { + key: key, + value: value + }; + + conditions.set(condition.key, condition); + + if (condition.value) { + conditionsArrayValues.push(1); } else { - node.error = err.message + conditionsArrayValues.push(0); } } - - condition = { - key: key, - value: value - }; - - conditions.set(condition.key, condition); - - if (condition.value) { - conditionsArrayValues.push(1); - } else { - conditionsArrayValues.push(0); - } } - } /* Trigger On Conditions */ @@ -1250,47 +1314,24 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { ) { takePositionNow = false - /* positionSize default is the whole balance if no size was defined by the user */ + /* tradePositionSize default is the whole balance if no size was defined by the user */ if (baseAsset === 'BTC') { - positionSize = balanceAssetA; + tradePositionSize = balanceAssetA; } else { - positionSize = balanceAssetB; - } - - /* Check if the user defined a position size */ - let strategy = tradingSystem.strategies[currentStrategyIndex]; - let triggerStage = strategy.triggerStage - - if (triggerStage !== undefined) { - if (triggerStage.positionSize !== undefined) { - if (triggerStage.positionSize.formula !== undefined) { - try { - positionSize = eval(triggerStage.positionSize.formula.code); - } catch (err) { - triggerStage.positionSize.formula.error = err.message - } - if (isNaN(positionSize)) { - if (baseAsset === 'BTC') { - positionSize = balanceAssetA; - } else { - positionSize = balanceAssetB; - } - } else { - if (baseAsset === 'BTC') { - if (positionSize > balanceAssetA) { positionSize = balanceAssetA} - } else { - if (positionSize > balanceAssetB) { positionSize = balanceAssetB} - } - } - } - } + tradePositionSize = balanceAssetB; } + tradePositionRate = candle.close + + /* Check if the user defined a position size or rate */ + let strategy = tradingSystem.strategies[currentStrategyIndex]; + + tradePositionSize = strategy.positionSize; + tradePositionRate = strategy.positionRate; calculateTakeProfit(); calculateStopLoss(); - marketRate = candle.close; - positionRate = candle.close; + marketRate = candle.close; previousBalanceAssetA = balanceAssetA; previousBalanceAssetB = balanceAssetB; @@ -1299,11 +1340,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { lastTradeROI = 0; if (baseAsset === 'BTC') { - balanceAssetB = balanceAssetB + positionSize * positionRate; - balanceAssetA = balanceAssetA - positionSize; + balanceAssetB = balanceAssetB + tradePositionSize * tradePositionRate; + balanceAssetA = balanceAssetA - tradePositionSize; } else { - balanceAssetA = balanceAssetA + positionSize / positionRate; - balanceAssetB = balanceAssetB - positionSize; + balanceAssetA = balanceAssetA + tradePositionSize / tradePositionRate; + balanceAssetB = balanceAssetB - tradePositionSize; } positionInstant = candle.end; @@ -1335,12 +1376,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (baseAsset === 'BTC') { lastTradeProfitLoss = balanceAssetA - previousBalanceAssetA; - lastTradeROI = lastTradeProfitLoss * 100 / positionSize; + lastTradeROI = lastTradeProfitLoss * 100 / tradePositionSize; if (isNaN(lastTradeROI)) { lastTradeROI = 0; } profit = balanceAssetA - initialBalanceA; } else { lastTradeProfitLoss = balanceAssetB - previousBalanceAssetB; - lastTradeROI = lastTradeProfitLoss * 100 / positionSize; + lastTradeROI = lastTradeProfitLoss * 100 / tradePositionSize; if (isNaN(lastTradeROI)) { lastTradeROI = 0; } profit = balanceAssetB - initialBalanceB; } @@ -1398,8 +1439,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentStrategyIndex = -1; stopLoss = 0; - positionRate = 0; - positionSize = 0; + tradePositionRate = 0; + tradePositionSize = 0; positionInstant = undefined; takeProfit = 0; strategyStage = 'No Stage'; @@ -1454,7 +1495,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { "BTC_USDT", 0, ORDER_TYPE.Limit, - marketRate, + tradePositionRate, stopLoss, takeProfit, ORDER_DIRECTION.Sell, @@ -1551,7 +1592,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { periods: periods, days: days, anualizedRateOfReturn: anualizedRateOfReturn, - positionRate: positionRate, + positionRate: tradePositionRate, lastTradeROI: lastTradeROI, strategy: currentStrategyIndex, strategyStageNumber: strategyStageNumber, @@ -1559,7 +1600,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { stopLossPhase: stopLossPhase, takeProfitPhase: takeProfitPhase, executionRecord: executionMessage, - positionSize: positionSize, + positionSize: tradePositionSize, initialBalanceA: initialBalanceA, minimumBalanceA: minimumBalanceA, maximumBalanceA: maximumBalanceA, From 1e15007d00c6314c73cbe480389d117b7f828903 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 8 Jul 2019 19:09:16 +0200 Subject: [PATCH 164/244] Not considering the last candle at the head of the market --- Commons.js | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/Commons.js b/Commons.js index 9e5352d8c..192a9d495 100644 --- a/Commons.js +++ b/Commons.js @@ -342,8 +342,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { for (let i = 0; i < candles.length; i++) { - /* Update all the data objects available for the simulation. */ - + let candle = candles[i]; let percentageBandwidth = percentageBandwidthMap.get(candle.begin); let bollingerBand = bollingerBandsMap.get(candle.begin); @@ -365,10 +364,25 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { periods++; days = periods * timePeriod / ONE_DAY_IN_MILISECONDS; - if (currentDay !== undefined) { + if (currentDay !== undefined) { // This means that we are processing Daily Files if (candle.end < currentDay.valueOf()) { yesterday.Periods++; } + + /* We skip the candle at the head of the market because i has not closed yet. */ + let candlesPerDay = ONE_DAY_IN_MILISECONDS / timePeriod + if (i === candles.length - 1) { + if ((i > candlesPerDay && i < candlesPerDay * 2) || (i < candlesPerDay)) { + /*We are at the head of the market, thus we skip the last candle because it has not close yet. */ + continue; + /* Note here that in the last candle of the first day or the second day it will use an incomplete candle and partially calculated indicators. + if we skip these two periods, then there will be a hole in the file since the last period will be missing. */ + } + } + } else { // We are processing Market Files + if (i === candles.length - 1) { + continue; + } } let lastObjects = { @@ -1714,6 +1728,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { return element } } + + element = { + direction: 'unknown', + slope: 'unknown' + } + return element } } catch (err) { From c5b3f09e8f3430411adfcf6b250c07be2621a40b Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 8 Jul 2019 19:31:38 +0200 Subject: [PATCH 165/244] Bug Fixed : + 1 --- Commons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index 192a9d495..abdaf0911 100644 --- a/Commons.js +++ b/Commons.js @@ -372,7 +372,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* We skip the candle at the head of the market because i has not closed yet. */ let candlesPerDay = ONE_DAY_IN_MILISECONDS / timePeriod if (i === candles.length - 1) { - if ((i > candlesPerDay && i < candlesPerDay * 2) || (i < candlesPerDay)) { + if ((candles.length < candlesPerDay) || (candles.length > candlesPerDay && i < candlesPerDay * 2) ) { /*We are at the head of the market, thus we skip the last candle because it has not close yet. */ continue; /* Note here that in the last candle of the first day or the second day it will use an incomplete candle and partially calculated indicators. From 102ad903f262d4de3e055a33255ff89acc811dee Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 8 Jul 2019 19:53:44 +0200 Subject: [PATCH 166/244] Last Minute Fix --- Commons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index abdaf0911..ec4aaea2c 100644 --- a/Commons.js +++ b/Commons.js @@ -372,7 +372,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* We skip the candle at the head of the market because i has not closed yet. */ let candlesPerDay = ONE_DAY_IN_MILISECONDS / timePeriod if (i === candles.length - 1) { - if ((candles.length < candlesPerDay) || (candles.length > candlesPerDay && i < candlesPerDay * 2) ) { + if ((candles.length < candlesPerDay) || (candles.length > candlesPerDay && candles.length < candlesPerDay * 2) ) { /*We are at the head of the market, thus we skip the last candle because it has not close yet. */ continue; /* Note here that in the last candle of the first day or the second day it will use an incomplete candle and partially calculated indicators. From df39dbca8576561462f1a548117b1b4a68aa1e3a Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 9 Jul 2019 20:50:41 +0200 Subject: [PATCH 167/244] Bollinger Standard Channels --- Commons.js | 12 ++---------- this.bot.config.json | 16 ++++++++-------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/Commons.js b/Commons.js index ec4aaea2c..42812685f 100644 --- a/Commons.js +++ b/Commons.js @@ -1729,11 +1729,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - element = { - direction: 'unknown', - slope: 'unknown' - } - return element + return } } catch (err) { @@ -1881,11 +1877,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { begin: dataFile[i][0], end: dataFile[i][1], direction: dataFile[i][2], - period: dataFile[i][3], - firstMovingAverage: dataFile[i][4], - lastMovingAverage: dataFile[i][5], - firstDeviation: dataFile[i][6], - lastDeviation: dataFile[i][7] + period: dataFile[i][3] }; bollingerChannel.previous = previous; diff --git a/this.bot.config.json b/this.bot.config.json index b1043d5d8..6fdb8002c 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -79,7 +79,7 @@ "major": 1, "minor": 0 }, - "product": "Bollinger-Channels", + "product": "Bollinger-Standard-Channels", "dataSetVersion": "dataSet.V1", "dataSet": "Multi-Period-Market" }, @@ -166,7 +166,7 @@ }, "product": "LRC-Points", "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Market" + "dataSet": "Multi-Period-Daily" }, { "devTeam": "AAMasters", @@ -177,7 +177,7 @@ }, "product": "Percentage-Bandwidth", "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Market" + "dataSet": "Multi-Period-Daily" }, { "devTeam": "AAMasters", @@ -188,7 +188,7 @@ }, "product": "Bollinger-Bands", "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Market" + "dataSet": "Multi-Period-Daily" }, { "devTeam": "AAMasters", @@ -197,9 +197,9 @@ "major": 1, "minor": 0 }, - "product": "Bollinger-Channels", + "product": "Bollinger-Standard-Channels", "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Market" + "dataSet": "Multi-Period-Daily" }, { "devTeam": "AAMasters", @@ -210,7 +210,7 @@ }, "product": "Bollinger-Sub-Channels", "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Market" + "dataSet": "Multi-Period-Daily" }, { "devTeam": "AAMasters", @@ -221,7 +221,7 @@ }, "product": "Candles", "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Market" + "dataSet": "Multi-Period-Daily" } ] } From 2383729e1b5df4483f19e9c2316388638155cbd4 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 10 Jul 2019 16:47:52 +0200 Subject: [PATCH 168/244] Dependency on Standard Channels and SubChannels --- this.bot.config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/this.bot.config.json b/this.bot.config.json index 6fdb8002c..0a700ec08 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -90,7 +90,7 @@ "major": 1, "minor": 0 }, - "product": "Bollinger-Sub-Channels", + "product": "Bollinger-Standard-Sub-Channels", "dataSetVersion": "dataSet.V1", "dataSet": "Multi-Period-Market" }, @@ -208,7 +208,7 @@ "major": 1, "minor": 0 }, - "product": "Bollinger-Sub-Channels", + "product": "Bollinger-Standard-Sub-Channels", "dataSetVersion": "dataSet.V1", "dataSet": "Multi-Period-Daily" }, From 616c5e39e4b8b52edfb389ef5d901a4bca80d260 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 11 Jul 2019 18:10:19 +0200 Subject: [PATCH 169/244] Trade Close Signal to Executor --- Commons.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Commons.js b/Commons.js index 42812685f..89809d74e 100644 --- a/Commons.js +++ b/Commons.js @@ -1491,10 +1491,18 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (type === '"Close@TakeProfit"' || type === '"Close@StopLoss"') { messageType = MESSAGE_TYPE.OrderUpdate; } else { - messageType = MESSAGE_TYPE.OrderUpdate; + messageType = MESSAGE_TYPE.OrderClose; } } + let exitOutcome = "" + if (messageType === MESSAGE_TYPE.OrderClose && type === '"Close@TakeProfit"') { + exitOutcome = "TP" + } + if (messageType === MESSAGE_TYPE.OrderClose && type === '"Close@TakeProfit"') { + exitOutcome = "SL" + } + executionMessage = createMessage( messageId, MESSAGE_ENTITY.SimulationEngine, @@ -1516,7 +1524,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { -1, ORDER_STATUS.Signaled, 0, - "") + exitOutcome) } else { From 0ccf80353d83981c0fb3cd4b5b4aac5756ae8877 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 11 Jul 2019 18:43:43 +0200 Subject: [PATCH 170/244] FIX Message Type --- Commons.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Commons.js b/Commons.js index 89809d74e..e703c358c 100644 --- a/Commons.js +++ b/Commons.js @@ -1489,9 +1489,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { orderId++; } else { if (type === '"Close@TakeProfit"' || type === '"Close@StopLoss"') { - messageType = MESSAGE_TYPE.OrderUpdate; - } else { messageType = MESSAGE_TYPE.OrderClose; + } else { + messageType = MESSAGE_TYPE.OrderUpdate; } } From cb2ef8fe5ccb1e91e84fb79cd0793e5caf5124dc Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 11 Jul 2019 18:49:19 +0200 Subject: [PATCH 171/244] 2nd fix --- Commons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index e703c358c..0c1e7a24a 100644 --- a/Commons.js +++ b/Commons.js @@ -1499,7 +1499,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (messageType === MESSAGE_TYPE.OrderClose && type === '"Close@TakeProfit"') { exitOutcome = "TP" } - if (messageType === MESSAGE_TYPE.OrderClose && type === '"Close@TakeProfit"') { + if (messageType === MESSAGE_TYPE.OrderClose && type === '"Close@StopLoss"') { exitOutcome = "SL" } From 40a36c0cc976d44b01bd8c20f2ce6e0c72d5b763 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 13 Jul 2019 00:43:17 +0200 Subject: [PATCH 172/244] BUG FIX: remove null in output file --- Commons.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Commons.js b/Commons.js index 0c1e7a24a..17aeafada 100644 --- a/Commons.js +++ b/Commons.js @@ -1550,6 +1550,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { 0, "", 0, + "", "") } From 9252db640f8f129c084104b6eb00a2ebe484e549 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 14 Jul 2019 16:39:57 +0200 Subject: [PATCH 173/244] Fix log position --- Commons.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index 17aeafada..77aec81e5 100644 --- a/Commons.js +++ b/Commons.js @@ -1487,12 +1487,18 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (type === '"Take Position"') { messageType = MESSAGE_TYPE.Order; orderId++; + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> addRecord -> Taking Position Now. "); } + } else { if (type === '"Close@TakeProfit"' || type === '"Close@StopLoss"') { messageType = MESSAGE_TYPE.OrderClose; + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> addRecord -> Closing Position Now. "); } + } else { messageType = MESSAGE_TYPE.OrderUpdate; - } + } } let exitOutcome = "" From 299ef0ba60465b7c18feda967d205b0a347e8f21 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 22 Jul 2019 23:01:54 +0200 Subject: [PATCH 174/244] Taking Position puting order at exchange working --- Commons.js | 319 ++++++++++++++++++++++---------- Multi-Period-Daily/User.Bot.js | 5 +- Multi-Period-Market/User.Bot.js | 5 +- this.bot.config.json | 27 ++- 4 files changed, 256 insertions(+), 100 deletions(-) diff --git a/Commons.js b/Commons.js index 77aec81e5..dec6f5e1f 100644 --- a/Commons.js +++ b/Commons.js @@ -10,7 +10,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { createMessage, getMessage, getExpandedMessage } = orderMessage.newOrderMessage() - const FULL_LOG = true; const LOG_FILE_CONTENT = false; @@ -58,6 +57,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { startDate, endDate, interExecutionMemory, + assistant, callback, callBackFunction) { @@ -198,6 +198,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let marketRate = 0; let takePositionNow = false + /* Assistant Info */ + + let ticker = assistant.getTicker(); + /* In some cases we need to know if we are positioned at the last candle of the calendar day, for that we need thse variables. */ let lastInstantOfTheDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1; @@ -340,7 +344,18 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Main Simulation Loop: We go thourgh all the candles at this time period. */ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Main Simulation Loop -> candles.length = " + candles.length); } - for (let i = 0; i < candles.length; i++) { + let i + initializeLoop() + + function initializeLoop() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> initializeLoop -> Entering function."); } + i = 0 + loop() + } + + function loop() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> i = " + i); } let candle = candles[i]; @@ -353,13 +368,28 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* If any of the needed indicators is missing, then that period is not calculated */ - if (candle.begin < initialDate.valueOf()) { continue; } - if (bollingerBand === undefined) { continue; } - if (percentageBandwidth === undefined) { continue; } // percentageBandwidth might start after the first few candles. - if (bollingerChannel === undefined) { continue; } - if (bollingerSubChannel === undefined) { continue; } + if (candle.begin < initialDate.valueOf()) { + controlLoop(); + return + } + if (bollingerBand === undefined) { + controlLoop(); + return + } + if (percentageBandwidth === undefined) { + controlLoop(); + return + } // percentageBandwidth might start after the first few candles. + if (bollingerChannel === undefined) { + controlLoop(); + return + } + if (bollingerSubChannel === undefined) { + controlLoop(); + return + } - //if (LRC === undefined) { continue; } + //if (LRC === undefined) { controlLoop(); return} periods++; days = periods * timePeriod / ONE_DAY_IN_MILISECONDS; @@ -372,16 +402,18 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* We skip the candle at the head of the market because i has not closed yet. */ let candlesPerDay = ONE_DAY_IN_MILISECONDS / timePeriod if (i === candles.length - 1) { - if ((candles.length < candlesPerDay) || (candles.length > candlesPerDay && candles.length < candlesPerDay * 2) ) { + if ((candles.length < candlesPerDay) || (candles.length > candlesPerDay && candles.length < candlesPerDay * 2)) { /*We are at the head of the market, thus we skip the last candle because it has not close yet. */ - continue; + controlLoop(); + return /* Note here that in the last candle of the first day or the second day it will use an incomplete candle and partially calculated indicators. - if we skip these two periods, then there will be a hole in the file since the last period will be missing. */ + if we skip these two periods, then there will be a hole in the file since the last period will be missing. */ } } } else { // We are processing Market Files if (i === candles.length - 1) { - continue; + controlLoop(); + return } } @@ -413,7 +445,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { lastObjectsArray.push(lastObjects); if (lastObjectsArray.length > 5) { - lastObjectsArray.splice(0,1); + lastObjectsArray.splice(0, 1); } let conditions = new Map; // Here we store the conditions values that will be use in the simulator for decision making. @@ -430,14 +462,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { evaluateConditionsAndFormulas(tradingSystem, conditions); - function evaluateConditionsAndFormulas(tradingSystem, conditions) { + function evaluateConditionsAndFormulas(tradingSystem, conditions) { for (let j = 0; j < tradingSystem.strategies.length; j++) { let strategy = tradingSystem.strategies[j]; - let positionSize = 0 - let positionRate = 0 + let positionSize = 0 + let positionRate = 0 /* Continue with the rest of the formulas and conditions */ @@ -577,9 +609,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (phase.formula !== undefined) { try { - formulaValue = eval(phase.formula.code); + formulaValue = eval(phase.formula.code); if (formulaValue === Infinity) { - formulaError= "Formula evaluates to Infinity." + formulaError = "Formula evaluates to Infinity." formulaValue = MAX_STOP_LOSS_VALUE } } catch (err) { @@ -854,11 +886,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Trigger On Conditions */ if ( strategyStage === 'No Stage' && - currentStrategyIndex === -1 + currentStrategyIndex === -1 ) { let minimumBalance let maximumBalance - let balance + let balance if (baseAsset === 'BTC') { balance = balanceAssetA @@ -875,12 +907,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Here we need to pick a strategy, or if there is not suitable strategy for the current market conditions, we pass until the next period. - + To pick a new strategy we will evaluate what we call the trigger on. Once we enter into one strategy, we will ignore market conditions for others. However there is also a strategy trigger off which can be hit before taking a position. If hit, we would be outside a strategy again and looking for the condition to enter all over again. - + */ for (let j = 0; j < tradingSystem.strategies.length; j++) { @@ -931,7 +963,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } if (balance > maximumBalance) { tradingSystem.error = "Max Balance @ " + stopRunningDate.toUTCString() - } + } } } @@ -1044,7 +1076,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let openStage = strategy.openStage let manageStage = strategy.manageStage - let parentNode + let parentNode let j = currentStrategyIndex let stageKey let initialDefinitionKey = '' @@ -1057,7 +1089,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { initialDefinitionKey = '-' + 'initialDefinition' stageKey = 'openStage' p = stopLossPhase - 1 - } + } } } @@ -1066,7 +1098,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { parentNode = manageStage stageKey = 'manageStage' p = stopLossPhase - 2 - } + } } let phase = parentNode.stopLoss.phases[p]; @@ -1108,7 +1140,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let strategy = tradingSystem.strategies[currentStrategyIndex]; let openStage = strategy.openStage let manageStage = strategy.manageStage - let phase + let phase let key if (stopLossStage === 'Open Stage' && openStage !== undefined) { @@ -1328,53 +1360,127 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { ) { takePositionNow = false - /* tradePositionSize default is the whole balance if no size was defined by the user */ - if (baseAsset === 'BTC') { - tradePositionSize = balanceAssetA; - } else { - tradePositionSize = balanceAssetB; - } - tradePositionRate = candle.close - - /* Check if the user defined a position size or rate */ + /* Position size and rate */ let strategy = tradingSystem.strategies[currentStrategyIndex]; tradePositionSize = strategy.positionSize; tradePositionRate = strategy.positionRate; - calculateTakeProfit(); - calculateStopLoss(); + /* We see if we need to put the actual order at the exchange. */ - marketRate = candle.close; + if (interExecutionMemory.executionContext !== undefined) { + switch (interExecutionMemory.executionContext.status) { + case "Without a Position": { // We need to put the order because It was not put yet. - previousBalanceAssetA = balanceAssetA; - previousBalanceAssetB = balanceAssetB; + if (strategy.openStage !== undefined) { + if (strategy.openStage.openExecution !== undefined) { + putOrder() + return + } + } - lastTradeProfitLoss = 0; - lastTradeROI = 0; - - if (baseAsset === 'BTC') { - balanceAssetB = balanceAssetB + tradePositionSize * tradePositionRate; - balanceAssetA = balanceAssetA - tradePositionSize; - } else { - balanceAssetA = balanceAssetA + tradePositionSize / tradePositionRate; - balanceAssetB = balanceAssetB - tradePositionSize; - } - - positionInstant = candle.end; - - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { - yesterday.balanceAssetA = balanceAssetA; - yesterday.balanceAssetB = balanceAssetB; - - yesterday.lastTradeProfitLoss = lastTradeProfitLoss; - yesterday.lastTradeROI = lastTradeROI; + break + } + case "In a Position": { // This should mean that we already put the order at the exchange. + break + } + case "Taking Position": { // Waiting for a confirmation that the position was taken. + break + } + } + } else { // The context does not exist so it means we are not in a position. + if (strategy.openStage !== undefined) { + if (strategy.openStage.openExecution !== undefined) { + putOrder() + return + } } } - addRecord(); - continue; + takePositionAtSimulation() + + function putOrder() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOrder -> Entering function."); } + + let positionDirection + if (baseAsset === 'BTC') { + positionDirection = "sell" + } else { + positionDirection = "buy" + } + + interExecutionMemory.executionContext = { + status: "Taking Position" + } + + assistant.putPosition(positionDirection, tradePositionRate, tradePositionSize * tradePositionRate, tradePositionSize, onOrderPut) + + function onOrderPut(err) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOrder -> onOrderPut -> Entering function."); } + + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOrder -> onOrderPut -> DEFAULT_OK_RESPONSE "); } + interExecutionMemory.executionContext = { + status: "In a Position" + } + takePositionAtSimulation() + return; + } + case global.DEFAULT_FAIL_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOrder -> onOrderPut -> DEFAULT_FAIL_RESPONSE "); } + /* We will assume that the problem is temporary, and expect that it will work at the next execution.*/ + strategy.openStage.openExecution.error = err.message + takePositionAtSimulation() + return; + } + } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOrder -> onOrderPut -> Unexpected Response -> Message = " + err.message); } + strategy.openStage.openExecution.error = err.message + } + } + + function takePositionAtSimulation() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionAtSimulation -> Entering function."); } + + /* Continue with the simulation */ + + calculateTakeProfit(); + calculateStopLoss(); + + marketRate = candle.close; + + previousBalanceAssetA = balanceAssetA; + previousBalanceAssetB = balanceAssetB; + + lastTradeProfitLoss = 0; + lastTradeROI = 0; + + if (baseAsset === 'BTC') { + balanceAssetB = balanceAssetB + tradePositionSize * tradePositionRate; + balanceAssetA = balanceAssetA - tradePositionSize; + } else { + balanceAssetA = balanceAssetA + tradePositionSize / tradePositionRate; + balanceAssetB = balanceAssetB - tradePositionSize; + } + + positionInstant = candle.end; + + if (currentDay !== undefined) { + if (positionInstant < currentDay.valueOf()) { + yesterday.balanceAssetA = balanceAssetA; + yesterday.balanceAssetB = balanceAssetB; + + yesterday.lastTradeProfitLoss = lastTradeProfitLoss; + yesterday.lastTradeROI = lastTradeROI; + } + } + + addRecord(); + controlLoop(); + return + } } /* Closing a Position */ @@ -1385,7 +1491,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (currentDay !== undefined) { if (positionInstant < currentDay.valueOf()) { yesterday.Roundtrips++; - } + } } if (baseAsset === 'BTC') { @@ -1398,7 +1504,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { lastTradeROI = lastTradeProfitLoss * 100 / tradePositionSize; if (isNaN(lastTradeROI)) { lastTradeROI = 0; } profit = balanceAssetB - initialBalanceB; - } + } if (currentDay !== undefined) { if (positionInstant < currentDay.valueOf()) { @@ -1410,7 +1516,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentTrade.lastTradeROI = lastTradeROI; currentTrade.stopRate = stopLoss; - + if (lastTradeProfitLoss > 0) { hits++; @@ -1438,7 +1544,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { ROI = (initialBalanceB + profit) / initialBalanceB - 1; hitRatio = hits / roundtrips; anualizedRateOfReturn = ROI / days * 365; - } + } if (currentDay !== undefined) { if (positionInstant < currentDay.valueOf()) { @@ -1462,7 +1568,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { takeProfitStage = 'No Stage'; stopLossPhase = 0; takeProfitPhase = 0; - continue; + controlLoop(); + return } @@ -1470,8 +1577,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { marketRate = candle.close; addRecord(); + controlLoop(); + return function addRecord() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> addRecord -> Entering function."); } // Since we are going to write the message to a file that the Simulation Executor is going to read, we use the abbreviations. let messageType; @@ -1498,7 +1608,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } else { messageType = MESSAGE_TYPE.OrderUpdate; - } + } } let exitOutcome = "" @@ -1698,38 +1808,53 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - /* - Before returning we need to see if we have to record some of our counters at the interExecutionMemory. - To do that, the condition to be met is that this execution must include all candles of the currentDay. - */ - - if (currentDay !== undefined) { - - if (lastCandle.end === lastInstantOfTheDay) { - - interExecutionMemory.balanceAssetA = yesterday.balanceAssetA; - interExecutionMemory.balanceAssetB = yesterday.balanceAssetB; - interExecutionMemory.lastTradeProfitLoss = yesterday.lastTradeProfitLoss; - interExecutionMemory.profit = yesterday.profit; - interExecutionMemory.lastTradeROI = yesterday.lastTradeROI; - - interExecutionMemory.roundtrips = interExecutionMemory.roundtrips + yesterday.Roundtrips; - interExecutionMemory.fails = interExecutionMemory.fails + yesterday.fails; - interExecutionMemory.hits = interExecutionMemory.hits + yesterday.hits; - interExecutionMemory.periods = interExecutionMemory.periods + yesterday.Periods; - - interExecutionMemory.messageId = interExecutionMemory.messageId + yesterday.messageId; - interExecutionMemory.orderId = interExecutionMemory.orderId + yesterday.orderId; - - interExecutionMemory.hitRatio = yesterday.hitRatio; - interExecutionMemory.ROI = yesterday.ROI; - interExecutionMemory.anualizedRateOfReturn = yesterday.anualizedRateOfReturn; + function controlLoop() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> controlLoop -> Entering function."); } + i++ + if (i < candles.length) { + loop() + } else { + afterLoop() } } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> callback -> recordsArray.length = " + recordsArray.length); } + function afterLoop() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> afterLoop -> Entering function."); } + + /* + Before returning we need to see if we have to record some of our counters at the interExecutionMemory. + To do that, the condition to be met is that this execution must include all candles of the currentDay. + */ + + if (currentDay !== undefined) { + + if (lastCandle.end === lastInstantOfTheDay) { + + interExecutionMemory.balanceAssetA = yesterday.balanceAssetA; + interExecutionMemory.balanceAssetB = yesterday.balanceAssetB; + interExecutionMemory.lastTradeProfitLoss = yesterday.lastTradeProfitLoss; + interExecutionMemory.profit = yesterday.profit; + interExecutionMemory.lastTradeROI = yesterday.lastTradeROI; + + interExecutionMemory.roundtrips = interExecutionMemory.roundtrips + yesterday.Roundtrips; + interExecutionMemory.fails = interExecutionMemory.fails + yesterday.fails; + interExecutionMemory.hits = interExecutionMemory.hits + yesterday.hits; + interExecutionMemory.periods = interExecutionMemory.periods + yesterday.Periods; + + interExecutionMemory.messageId = interExecutionMemory.messageId + yesterday.messageId; + interExecutionMemory.orderId = interExecutionMemory.orderId + yesterday.orderId; + + interExecutionMemory.hitRatio = yesterday.hitRatio; + interExecutionMemory.ROI = yesterday.ROI; + interExecutionMemory.anualizedRateOfReturn = yesterday.anualizedRateOfReturn; + } + } + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> callback -> recordsArray.length = " + recordsArray.length); } + + callback(tradingSystem, executionArray, recordsArray, conditionsArray, strategiesArray, tradesArray, lastObjectsArray); + } - callback(tradingSystem, executionArray, recordsArray, conditionsArray, strategiesArray, tradesArray, lastObjectsArray); function getElement(pArray, begin, end) { diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 94f18bbe3..1e457f5a7 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -21,10 +21,11 @@ let utilities = UTILITIES.newCloudUtilities(bot, logger); let dataDependencies; + let assistant; return thisObject; - function initialize(pDataDependencies, callBackFunction) { + function initialize(pDataDependencies, callBackFunction, pAssistant) { try { @@ -34,6 +35,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } dataDependencies = pDataDependencies; + assistant = pAssistant; callBackFunction(global.DEFAULT_OK_RESPONSE); @@ -102,6 +104,7 @@ startDate, endDate, interExecutionMemory, + assistant, writeFiles, callBackFunction) diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 5e031fcb5..19a134dea 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -19,10 +19,11 @@ }; let dataDependencies; + let assistant; return thisObject; - function initialize(pDataDependencies, callBackFunction) { + function initialize(pDataDependencies, callBackFunction, pAssistant) { try { @@ -32,6 +33,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } dataDependencies = pDataDependencies; + assistant = pAssistant; callBackFunction(global.DEFAULT_OK_RESPONSE); @@ -102,6 +104,7 @@ startDate, endDate, interExecutionMemory, + assistant, writeFiles, callBackFunction) diff --git a/this.bot.config.json b/this.bot.config.json index 0a700ec08..d9d7926df 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -1,7 +1,7 @@ { "displayName": "Jason", "codeName": "AAJason", - "type": "Indicator", + "type": "Trading-Engine", "version": { "major": 1, "minor": 0, @@ -382,6 +382,31 @@ "codeName": "PlottersTradingSimulation", "moduleName": "Trades" } + }, + { + "codeName": "Live Trading History", + "displayName": "Live Trading History", + "shortDisplayName": "Live", + "description": "Live Trading Execution.", + "dataSets": [ + { + "codeName": "Oficial History", + "type": "File Sequence", + "validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs", "45-min", "40-min", "30-min", "20-min", "15-min", "10-min", "05-min", "04-min", "03-min", "02-min", "01-min" ], + "filePath": "@DevTeam/@Bot.1.0/AACloud.1.1/Poloniex/dataSet.V1/Output/Trading-Process", + "fileName": "Execution.History.Live.@Sequence.json" + } + ], + "exchangeList": [ + { + "name": "Poloniex" + } + ], + "plotter": { + "devTeam": "AAMasters", + "codeName": "PlottersTradingSimulation", + "moduleName": "SimulationExecution" + } } ] } From 0f26aabc9e2a8b87c3a2d341b2aec4bce11bd4cd Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 30 Jul 2019 22:11:52 +0200 Subject: [PATCH 175/244] definition introduced --- Commons.js | 253 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 176 insertions(+), 77 deletions(-) diff --git a/Commons.js b/Commons.js index dec6f5e1f..8024f9fd8 100644 --- a/Commons.js +++ b/Commons.js @@ -72,7 +72,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let tradesArray = []; let lastObjectsArray = []; - let tradingSystem = await strategy.getStrategy(); + let definition = await strategy.getStrategy(); + let tradingSystem = definition.tradingSystem; /* Initial Default Values */ @@ -357,7 +358,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Entering function."); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> i = " + i); } - let candle = candles[i]; let percentageBandwidth = percentageBandwidthMap.get(candle.begin); let bollingerBand = bollingerBandsMap.get(candle.begin); @@ -1278,6 +1278,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') && takePositionNow !== true ) { + let strategy = tradingSystem.strategies[currentStrategyIndex]; /* Checking what happened since the last execution. We need to know if the Stop Loss or our Take Profit were hit. */ @@ -1287,9 +1288,15 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if ((baseAsset === 'BTC' && candle.max >= stopLoss) || (baseAsset !== 'BTC' && candle.min <= stopLoss)) { if (baseAsset === 'BTC') { + strategy.positionSize = balanceAssetB / stopLoss; + strategy.positionRate = stopLoss; + balanceAssetA = balanceAssetA + balanceAssetB / stopLoss; balanceAssetB = 0; } else { + strategy.positionSize = balanceAssetA * stopLoss; + strategy.positionRate = stopLoss; + balanceAssetB = balanceAssetB + balanceAssetA * stopLoss; balanceAssetA = 0; } @@ -1322,9 +1329,15 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if ((baseAsset === 'BTC' && candle.min <= takeProfit) || (baseAsset !== 'BTC' && candle.max >= takeProfit)) { if (baseAsset === 'BTC') { + strategy.positionSize = balanceAssetB / takeProfit; + strategy.positionRate = takeProfit; + balanceAssetA = balanceAssetA + balanceAssetB / takeProfit; balanceAssetB = 0; } else { + strategy.positionSize = balanceAssetA * takeProfit; + strategy.positionRate = takeProfit; + balanceAssetB = balanceAssetB + balanceAssetA * takeProfit; balanceAssetA = 0; } @@ -1374,24 +1387,24 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (strategy.openStage !== undefined) { if (strategy.openStage.openExecution !== undefined) { - putOrder() + putOpeningOrder() return } } break } - case "In a Position": { // This should mean that we already put the order at the exchange. + case "Taking Position": { // Waiting for a confirmation that the position was taken. break } - case "Taking Position": { // Waiting for a confirmation that the position was taken. + case "In a Position": { // This should mean that we already put the order at the exchange. break } } } else { // The context does not exist so it means we are not in a position. if (strategy.openStage !== undefined) { if (strategy.openStage.openExecution !== undefined) { - putOrder() + putOpeningOrder() return } } @@ -1399,9 +1412,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { takePositionAtSimulation() - function putOrder() { + function putOpeningOrder() { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOrder -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Entering function."); } let positionDirection if (baseAsset === 'BTC') { @@ -1417,11 +1430,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { assistant.putPosition(positionDirection, tradePositionRate, tradePositionSize * tradePositionRate, tradePositionSize, onOrderPut) function onOrderPut(err) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOrder -> onOrderPut -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> Entering function."); } switch (err.result) { case global.DEFAULT_OK_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOrder -> onOrderPut -> DEFAULT_OK_RESPONSE "); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_OK_RESPONSE "); } interExecutionMemory.executionContext = { status: "In a Position" } @@ -1429,14 +1442,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { return; } case global.DEFAULT_FAIL_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOrder -> onOrderPut -> DEFAULT_FAIL_RESPONSE "); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_FAIL_RESPONSE "); } /* We will assume that the problem is temporary, and expect that it will work at the next execution.*/ strategy.openStage.openExecution.error = err.message takePositionAtSimulation() return; } } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOrder -> onOrderPut -> Unexpected Response -> Message = " + err.message); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> Unexpected Response -> Message = " + err.message); } strategy.openStage.openExecution.error = err.message } } @@ -1486,91 +1499,177 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Closing a Position */ if (strategyStage === 'Close Stage') { - roundtrips++; + /* Position size and rate */ + let strategy = tradingSystem.strategies[currentStrategyIndex]; - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { - yesterday.Roundtrips++; + tradePositionSize = strategy.positionSize; + tradePositionRate = strategy.positionRate; + + /* We see if we need to put the actual order at the exchange. */ + + if (interExecutionMemory.executionContext !== undefined) { + switch (interExecutionMemory.executionContext.status) { + case "Without a Position": { // No way to close anything at the exchange. + break + } + case "In a Position": { // This should mean that we already put the order at the exchange. + + if (strategy.closeStage !== undefined) { + if (strategy.closeStage.closeExecution !== undefined) { + putClosingOrder() + return + } + } + break + } + case "Taking Position": { // Waiting for a confirmation that the position was taken. + break + } + + case "Closing Position": { // Waiting for a confirmation that the position was closed. + break + } + + case "Position Closed": { // + break + } + } + } else { // The context does not exist so it means we are not in a position. + controlLoop(); + return + } + + closePositionAtSimulation() + + function putClosingOrder() { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> Entering function."); } + + let positionDirection + if (baseAsset === 'BTC') { + positionDirection = "buy" + } else { + positionDirection = "sell" + } + + interExecutionMemory.executionContext = { + status: "Closing Position" + } + + assistant.putPosition(positionDirection, tradePositionRate, tradePositionSize * tradePositionRate, tradePositionSize, onOrderPut) + + function onOrderPut(err) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> onOrderPut -> Entering function."); } + + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> onOrderPut -> DEFAULT_OK_RESPONSE "); } + interExecutionMemory.executionContext = { + status: "Position Closed" + } + closePositionAtSimulation() + return; + } + case global.DEFAULT_FAIL_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> onOrderPut -> DEFAULT_FAIL_RESPONSE "); } + /* We will assume that the problem is temporary, and expect that it will work at the next execution.*/ + strategy.openStage.openExecution.error = err.message + closePositionAtSimulation() + return; + } + } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> onOrderPut -> Unexpected Response -> Message = " + err.message); } + strategy.openStage.openExecution.error = err.message } } - if (baseAsset === 'BTC') { - lastTradeProfitLoss = balanceAssetA - previousBalanceAssetA; - lastTradeROI = lastTradeProfitLoss * 100 / tradePositionSize; - if (isNaN(lastTradeROI)) { lastTradeROI = 0; } - profit = balanceAssetA - initialBalanceA; - } else { - lastTradeProfitLoss = balanceAssetB - previousBalanceAssetB; - lastTradeROI = lastTradeProfitLoss * 100 / tradePositionSize; - if (isNaN(lastTradeROI)) { lastTradeROI = 0; } - profit = balanceAssetB - initialBalanceB; - } + function closePositionAtSimulation() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> closePositionAtSimulation -> Entering function."); } - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { - yesterday.lastTradeProfitLoss = lastTradeProfitLoss; - yesterday.profit = profit; - yesterday.lastTradeROI = lastTradeROI; - } - } - - currentTrade.lastTradeROI = lastTradeROI; - currentTrade.stopRate = stopLoss; - - if (lastTradeProfitLoss > 0) { - hits++; + roundtrips++; if (currentDay !== undefined) { if (positionInstant < currentDay.valueOf()) { - yesterday.hits++; + yesterday.Roundtrips++; } } - } else { - fails++; + if (baseAsset === 'BTC') { + lastTradeProfitLoss = balanceAssetA - previousBalanceAssetA; + lastTradeROI = lastTradeProfitLoss * 100 / tradePositionSize; + if (isNaN(lastTradeROI)) { lastTradeROI = 0; } + profit = balanceAssetA - initialBalanceA; + } else { + lastTradeProfitLoss = balanceAssetB - previousBalanceAssetB; + lastTradeROI = lastTradeProfitLoss * 100 / tradePositionSize; + if (isNaN(lastTradeROI)) { lastTradeROI = 0; } + profit = balanceAssetB - initialBalanceB; + } if (currentDay !== undefined) { if (positionInstant < currentDay.valueOf()) { - yesterday.fails++; + yesterday.lastTradeProfitLoss = lastTradeProfitLoss; + yesterday.profit = profit; + yesterday.lastTradeROI = lastTradeROI; } } - } - if (baseAsset === 'BTC') { - ROI = (initialBalanceA + profit) / initialBalanceA - 1; - hitRatio = hits / roundtrips; - anualizedRateOfReturn = ROI / days * 365; - } else { - ROI = (initialBalanceB + profit) / initialBalanceB - 1; - hitRatio = hits / roundtrips; - anualizedRateOfReturn = ROI / days * 365; - } + currentTrade.lastTradeROI = lastTradeROI; + currentTrade.stopRate = stopLoss; - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { - yesterday.ROI = ROI; - yesterday.hitRatio = hitRatio; - yesterday.anualizedRateOfReturn = anualizedRateOfReturn; + if (lastTradeProfitLoss > 0) { + hits++; + + if (currentDay !== undefined) { + if (positionInstant < currentDay.valueOf()) { + yesterday.hits++; + } + } + + } else { + fails++; + + if (currentDay !== undefined) { + if (positionInstant < currentDay.valueOf()) { + yesterday.fails++; + } + } } + + if (baseAsset === 'BTC') { + ROI = (initialBalanceA + profit) / initialBalanceA - 1; + hitRatio = hits / roundtrips; + anualizedRateOfReturn = ROI / days * 365; + } else { + ROI = (initialBalanceB + profit) / initialBalanceB - 1; + hitRatio = hits / roundtrips; + anualizedRateOfReturn = ROI / days * 365; + } + + if (currentDay !== undefined) { + if (positionInstant < currentDay.valueOf()) { + yesterday.ROI = ROI; + yesterday.hitRatio = hitRatio; + yesterday.anualizedRateOfReturn = anualizedRateOfReturn; + } + } + + addRecord(); + + currentStrategyIndex = -1; + stopLoss = 0; + tradePositionRate = 0; + tradePositionSize = 0; + positionInstant = undefined; + takeProfit = 0; + strategyStage = 'No Stage'; + stopLossStage = 'No Stage'; + takeProfitStage = 'No Stage'; + stopLossPhase = 0; + takeProfitPhase = 0; + controlLoop(); + return } - - - addRecord(); - - currentStrategyIndex = -1; - stopLoss = 0; - tradePositionRate = 0; - tradePositionSize = 0; - positionInstant = undefined; - takeProfit = 0; - strategyStage = 'No Stage'; - stopLossStage = 'No Stage'; - takeProfitStage = 'No Stage'; - stopLossPhase = 0; - takeProfitPhase = 0; - controlLoop(); - return - } /* Not a buy or sell condition */ From 1ce159720bbb51e0436db78260791becf68d3967 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 31 Jul 2019 09:02:21 +0200 Subject: [PATCH 176/244] Dealing with errors comming from the assistant --- Commons.js | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/Commons.js b/Commons.js index 8024f9fd8..bf4d2c1cf 100644 --- a/Commons.js +++ b/Commons.js @@ -1384,14 +1384,21 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (interExecutionMemory.executionContext !== undefined) { switch (interExecutionMemory.executionContext.status) { case "Without a Position": { // We need to put the order because It was not put yet. - if (strategy.openStage !== undefined) { if (strategy.openStage.openExecution !== undefined) { putOpeningOrder() return } } - + break + } + case "Closing Position": { // Waiting for a confirmation that the position was closed. + if (strategy.openStage !== undefined) { + if (strategy.openStage.openExecution !== undefined) { + putOpeningOrder() + return + } + } break } case "Taking Position": { // Waiting for a confirmation that the position was taken. @@ -1411,6 +1418,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } takePositionAtSimulation() + return function putOpeningOrder() { @@ -1443,9 +1451,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } case global.DEFAULT_FAIL_RESPONSE.result: { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_FAIL_RESPONSE "); } - /* We will assume that the problem is temporary, and expect that it will work at the next execution.*/ strategy.openStage.openExecution.error = err.message - takePositionAtSimulation() + afterLoop() + return; + } + case global.DEFAULT_RETRY_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_RETRY_RESPONSE "); } + strategy.openStage.openExecution.error = err.message + afterLoop() return; } } @@ -1513,7 +1526,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { break } case "In a Position": { // This should mean that we already put the order at the exchange. - if (strategy.closeStage !== undefined) { if (strategy.closeStage.closeExecution !== undefined) { putClosingOrder() @@ -1523,6 +1535,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { break } case "Taking Position": { // Waiting for a confirmation that the position was taken. + if (strategy.closeStage !== undefined) { + if (strategy.closeStage.closeExecution !== undefined) { + putClosingOrder() + return + } + } break } @@ -1534,12 +1552,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { break } } - } else { // The context does not exist so it means we are not in a position. - controlLoop(); - return } closePositionAtSimulation() + return function putClosingOrder() { @@ -1574,7 +1590,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> onOrderPut -> DEFAULT_FAIL_RESPONSE "); } /* We will assume that the problem is temporary, and expect that it will work at the next execution.*/ strategy.openStage.openExecution.error = err.message - closePositionAtSimulation() + afterLoop() + return; + } + case global.DEFAULT_RETRY_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_RETRY_RESPONSE "); } + strategy.openStage.openExecution.error = err.message + afterLoop() return; } } @@ -1739,7 +1761,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { -1, ORDER_STATUS.Signaled, 0, - exitOutcome) + exitOutcome, + "") } else { From 60bf73e8ac7b9b60ee8f09ba651231312b77a7dd Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 9 Aug 2019 01:36:09 +0200 Subject: [PATCH 177/244] Buying and Selling working. --- Commons.js | 54 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/Commons.js b/Commons.js index bf4d2c1cf..c37bc1bd3 100644 --- a/Commons.js +++ b/Commons.js @@ -1392,7 +1392,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } break } - case "Closing Position": { // Waiting for a confirmation that the position was closed. + case "Position Closed": { // Waiting for a confirmation that the position was closed. if (strategy.openStage !== undefined) { if (strategy.openStage.openExecution !== undefined) { putOpeningOrder() @@ -1424,6 +1424,23 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Entering function."); } + /* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */ + + if (interExecutionMemory.executionContext.period !== undefined) { + if (period <= interExecutionMemory.executionContext.period) { + takePositionAtSimulation() + return; + } + } + + /* We are not going to place orders based on outdated information. The next filter prevents firing orders when backtesting. */ + let today = new Date(Math.trunc((new Date().valueOf()) / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) + let processDay = new Date(Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) + if (today !== processDay) { + //takePositionAtSimulation() + //return; + } + let positionDirection if (baseAsset === 'BTC') { positionDirection = "sell" @@ -1444,7 +1461,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { case global.DEFAULT_OK_RESPONSE.result: { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_OK_RESPONSE "); } interExecutionMemory.executionContext = { - status: "In a Position" + status: "In a Position", + period: period } takePositionAtSimulation() return; @@ -1534,7 +1552,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } break } - case "Taking Position": { // Waiting for a confirmation that the position was taken. + case "Closing Position": { // Waiting for a confirmation that the position was taken. if (strategy.closeStage !== undefined) { if (strategy.closeStage.closeExecution !== undefined) { putClosingOrder() @@ -1544,10 +1562,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { break } - case "Closing Position": { // Waiting for a confirmation that the position was closed. - break - } - case "Position Closed": { // break } @@ -1561,6 +1575,25 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> Entering function."); } + /* Checking the status of current positions */ + let positions = assistant.getPositions(); + if (positions.length > 0) { + let position = positions[0] + if (position.status === 'open') { + afterLoop(); + return + } + } + + /* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */ + + if (interExecutionMemory.executionContext.period !== undefined) { + if (period <= interExecutionMemory.executionContext.period) { + closePositionAtSimulation() + return; + } + } + let positionDirection if (baseAsset === 'BTC') { positionDirection = "buy" @@ -1581,7 +1614,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { case global.DEFAULT_OK_RESPONSE.result: { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> onOrderPut -> DEFAULT_OK_RESPONSE "); } interExecutionMemory.executionContext = { - status: "Position Closed" + status: "Position Closed", + period: period } closePositionAtSimulation() return; @@ -1589,13 +1623,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { case global.DEFAULT_FAIL_RESPONSE.result: { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> onOrderPut -> DEFAULT_FAIL_RESPONSE "); } /* We will assume that the problem is temporary, and expect that it will work at the next execution.*/ - strategy.openStage.openExecution.error = err.message + strategy.closeStage.closeExecution.error = err.message afterLoop() return; } case global.DEFAULT_RETRY_RESPONSE.result: { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_RETRY_RESPONSE "); } - strategy.openStage.openExecution.error = err.message + strategy.closeStage.closeExecution.error = err.message afterLoop() return; } From a1ecaafd2f9a60590579a8d44c9ac615058dd50e Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 10 Aug 2019 11:16:46 +0200 Subject: [PATCH 178/244] All Working --- Commons.js | 198 ++++++++++++++++++++++---------- Multi-Period-Daily/User.Bot.js | 14 +-- Multi-Period-Market/User.Bot.js | 13 ++- this.bot.config.json | 22 ---- 4 files changed, 150 insertions(+), 97 deletions(-) diff --git a/Commons.js b/Commons.js index c37bc1bd3..c03e873f7 100644 --- a/Commons.js +++ b/Commons.js @@ -1424,64 +1424,115 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Entering function."); } - /* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */ - - if (interExecutionMemory.executionContext.period !== undefined) { - if (period <= interExecutionMemory.executionContext.period) { + /* We wont take a position unless we are withing the startDate and the endDate range */ + if (startDate !== undefined) { + if (candle.begin < startDate.valueOf()) { takePositionAtSimulation() return; } } + if (endDate !== undefined) { + if (candle.begin > endDate.valueOf()) { + takePositionAtSimulation() + return; + } + } + + /* Checking the status of current positions */ + let positions = assistant.getPositions(); + if (positions.length > 0) { + let position = positions[positions.length - 1] // We are allways checking the the last position is not open. + if (position.status === 'open') { + afterLoop(); + return + } + } + + /* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */ + + if (interExecutionMemory.executionContext !== undefined) { + if (interExecutionMemory.executionContext.periods !== undefined) { + if (periods <= interExecutionMemory.executionContext.periods) { + takePositionAtSimulation() + return; + } + } + } + /* We are not going to place orders based on outdated information. The next filter prevents firing orders when backtesting. */ let today = new Date(Math.trunc((new Date().valueOf()) / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) let processDay = new Date(Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) - if (today !== processDay) { - //takePositionAtSimulation() - //return; + if (today.valueOf() !== processDay.valueOf()) { + takePositionAtSimulation() + return; } + let openPositionRate + let amountA + let amountB let positionDirection + if (baseAsset === 'BTC') { positionDirection = "sell" + + openPositionRate = tradePositionRate - 100 // Provisional stuff to simulate a market order. Put the price lower to get it executed quickly + + amountA = tradePositionSize * openPositionRate + amountB = tradePositionSize } else { positionDirection = "buy" + + openPositionRate = tradePositionRate + 100 // Provisional stuff to simulate a market order. Put the price higher to get it executed quickly + + amountA = tradePositionSize + amountB = tradePositionSize / openPositionRate } interExecutionMemory.executionContext = { status: "Taking Position" } - assistant.putPosition(positionDirection, tradePositionRate, tradePositionSize * tradePositionRate, tradePositionSize, onOrderPut) + assistant.putPosition(positionDirection, openPositionRate, amountA, amountB, onOrderPut) function onOrderPut(err) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> Entering function."); } - switch (err.result) { - case global.DEFAULT_OK_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_OK_RESPONSE "); } - interExecutionMemory.executionContext = { - status: "In a Position", - period: period + try { + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_OK_RESPONSE "); } + interExecutionMemory.executionContext = { + status: "In a Position", + periods: periods, + amountA: amountA, + amountB: amountB + } + takePositionAtSimulation() + return; + } + case global.DEFAULT_FAIL_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_FAIL_RESPONSE "); } + strategy.openStage.openExecution.error = err.message + afterLoop() + return; + } + case global.DEFAULT_RETRY_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_RETRY_RESPONSE "); } + strategy.openStage.openExecution.error = err.message + afterLoop() + return; } - takePositionAtSimulation() - return; - } - case global.DEFAULT_FAIL_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_FAIL_RESPONSE "); } - strategy.openStage.openExecution.error = err.message - afterLoop() - return; - } - case global.DEFAULT_RETRY_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_RETRY_RESPONSE "); } - strategy.openStage.openExecution.error = err.message - afterLoop() - return; } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[ERROR] runSimulation -> putOpeningOrder -> onOrderPut -> Unexpected Response -> Message = " + err.message); } + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] runSimulation -> putOpeningOrder -> onOrderPut -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> Unexpected Response -> Message = " + err.message); } - strategy.openStage.openExecution.error = err.message } } @@ -1533,9 +1584,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Position size and rate */ let strategy = tradingSystem.strategies[currentStrategyIndex]; - tradePositionSize = strategy.positionSize; - tradePositionRate = strategy.positionRate; - /* We see if we need to put the actual order at the exchange. */ if (interExecutionMemory.executionContext !== undefined) { @@ -1578,7 +1626,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Checking the status of current positions */ let positions = assistant.getPositions(); if (positions.length > 0) { - let position = positions[0] + let position = positions[positions.length - 1] // We are allways checking the the last position is not open. if (position.status === 'open') { afterLoop(); return @@ -1587,55 +1635,81 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Mechanism to avoid putting the same order over and over again at different executions of the simulation engine. */ - if (interExecutionMemory.executionContext.period !== undefined) { - if (period <= interExecutionMemory.executionContext.period) { - closePositionAtSimulation() - return; + if (interExecutionMemory.executionContext !== undefined) { + if (interExecutionMemory.executionContext.periods !== undefined) { + if (periods <= interExecutionMemory.executionContext.periods) { + closePositionAtSimulation() + return; + } } } + let closePositionRate + let amountA + let amountB let positionDirection + if (baseAsset === 'BTC') { positionDirection = "buy" + + closePositionRate = ticker.last + 100; // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. + + amountA = interExecutionMemory.executionContext.amountA + amountB = interExecutionMemory.executionContext.amountA / closePositionRate } else { positionDirection = "sell" + + closePositionRate = ticker.last - 100; // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. + + amountA = interExecutionMemory.executionContext.amountB * closePositionRate + amountB = interExecutionMemory.executionContext.amountB } interExecutionMemory.executionContext = { status: "Closing Position" } - assistant.putPosition(positionDirection, tradePositionRate, tradePositionSize * tradePositionRate, tradePositionSize, onOrderPut) + assistant.putPosition(positionDirection, closePositionRate, amountA, amountB, onOrderPut) function onOrderPut(err) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> onOrderPut -> Entering function."); } - switch (err.result) { - case global.DEFAULT_OK_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> onOrderPut -> DEFAULT_OK_RESPONSE "); } - interExecutionMemory.executionContext = { - status: "Position Closed", - period: period + try { + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> onOrderPut -> DEFAULT_OK_RESPONSE "); } + interExecutionMemory.executionContext = { + status: "Position Closed", + periods: periods, + amountA: amountA, + amountB: amountB + } + closePositionAtSimulation() + return; + } + case global.DEFAULT_FAIL_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> onOrderPut -> DEFAULT_FAIL_RESPONSE "); } + /* We will assume that the problem is temporary, and expect that it will work at the next execution.*/ + strategy.closeStage.closeExecution.error = err.message + afterLoop() + return; + } + case global.DEFAULT_RETRY_RESPONSE.result: { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_RETRY_RESPONSE "); } + strategy.closeStage.closeExecution.error = err.message + afterLoop() + return; } - closePositionAtSimulation() - return; - } - case global.DEFAULT_FAIL_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> onOrderPut -> DEFAULT_FAIL_RESPONSE "); } - /* We will assume that the problem is temporary, and expect that it will work at the next execution.*/ - strategy.closeStage.closeExecution.error = err.message - afterLoop() - return; - } - case global.DEFAULT_RETRY_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_RETRY_RESPONSE "); } - strategy.closeStage.closeExecution.error = err.message - afterLoop() - return; } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[ERROR] runSimulation -> putClosingOrder -> onOrderPut -> Unexpected Response -> Message = " + err.message); } + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] runSimulation -> putClosingOrder -> onOrderPut -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> onOrderPut -> Unexpected Response -> Message = " + err.message); } - strategy.openStage.openExecution.error = err.message } } diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 1e457f5a7..ca0130408 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -70,28 +70,28 @@ dataFile = dataFiles[i]; switch (i) { - + /* case 0: { commons.buildLRC(dataFile, callBackFunction); break; - } - case 1: { + }*/ + case 0: { commons.buildPercentageBandwidthMap(dataFile, callBackFunction); break; } - case 2: { + case 1: { commons.buildBollingerBandsMap(dataFile, callBackFunction); break; } - case 3: { + case 2: { commons.buildBollingerChannelsArray(dataFile, callBackFunction); break; } - case 4: { + case 3: { commons.buildBollingerSubChannelsArray(dataFile, callBackFunction); break; } - case 5: { + case 4: { commons.buildCandles(dataFile, callBackFunction); break; } diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 19a134dea..5bac69a1f 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -71,27 +71,28 @@ switch (i) { + /* case 0: { commons.buildLRC(dataFile, callBackFunction); break; - } - case 1: { + }*/ + case 0: { commons.buildPercentageBandwidthMap(dataFile, callBackFunction); break; } - case 2: { + case 1: { commons.buildBollingerBandsMap(dataFile, callBackFunction); break; } - case 3: { + case 2: { commons.buildBollingerChannelsArray(dataFile, callBackFunction); break; } - case 4: { + case 3: { commons.buildBollingerSubChannelsArray(dataFile, callBackFunction); break; } - case 5: { + case 4: { commons.buildCandles(dataFile, callBackFunction); break; } diff --git a/this.bot.config.json b/this.bot.config.json index d9d7926df..a7d7de407 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -39,17 +39,6 @@ } ], "dataDependencies": [ - { - "devTeam": "AAVikings", - "bot": "AAGauss", - "botVersion": { - "major": 1, - "minor": 0 - }, - "product": "LRC-Points", - "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Market" - }, { "devTeam": "AAMasters", "bot": "AAChris", @@ -157,17 +146,6 @@ } ], "dataDependencies": [ - { - "devTeam": "AAVikings", - "bot": "AAGauss", - "botVersion": { - "major": 1, - "minor": 0 - }, - "product": "LRC-Points", - "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Daily" - }, { "devTeam": "AAMasters", "bot": "AAChris", From 232cc0c0460cb39a0a41b7bae7354a29cf5ed0a4 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 10 Aug 2019 12:40:22 +0200 Subject: [PATCH 179/244] BUG FIXED: Conect has its own status report --- this.bot.config.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/this.bot.config.json b/this.bot.config.json index a7d7de407..9b67a024b 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -36,6 +36,16 @@ }, "process": "Multi-Period-Market", "dataSetVersion": "dataSet.V1" + }, + { + "devTeam": "AAMasters", + "bot": "AAJason", + "botVersion": { + "major": 1, + "minor": 0 + }, + "process": "Context", + "dataSetVersion": "dataSet.V1" } ], "dataDependencies": [ @@ -143,6 +153,16 @@ }, "process": "Multi-Period-Daily", "dataSetVersion": "dataSet.V1" + }, + { + "devTeam": "AAMasters", + "bot": "AAJason", + "botVersion": { + "major": 1, + "minor": 0 + }, + "process": "Context", + "dataSetVersion": "dataSet.V1" } ], "dataDependencies": [ From 97d1203bb0d2734df5e2b001769991837328036f Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 12 Aug 2019 13:02:26 +0200 Subject: [PATCH 180/244] BUG FIXED: Call stack full in 1 hr --- Commons.js | 4 +- this.bot.config.json | 145 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 130 insertions(+), 19 deletions(-) diff --git a/Commons.js b/Commons.js index c03e873f7..8bbb55daa 100644 --- a/Commons.js +++ b/Commons.js @@ -354,7 +354,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { loop() } - function loop() { + function loop() { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Entering function."); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> i = " + i); } @@ -2042,7 +2042,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> controlLoop -> Entering function."); } i++ if (i < candles.length) { - loop() + process.nextTick(loop) } else { afterLoop() } diff --git a/this.bot.config.json b/this.bot.config.json index 9b67a024b..5f8b5b17c 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -23,8 +23,7 @@ "startDate": { "fixedDate": "2018-07-01" }, - "endDate": { - } + "endDate": {} }, "statusDependencies": [ { @@ -103,6 +102,17 @@ "product": "Candles", "dataSetVersion": "dataSet.V1", "dataSet": "Multi-Period-Market" + }, + { + "devTeam": "AAMasters", + "bot": "AABruce", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Candles", + "dataSetVersion": "dataSet.V1", + "dataSet": "One-Min" } ] }, @@ -115,7 +125,11 @@ "comaWaitTime": 86400000, "framework": { "name": "Multi-Period-Daily", - "validPeriods": [ "15-min", "10-min", "05-min"], + "validPeriods": [ + "15-min", + "10-min", + "05-min" + ], "startDate": { "fixedDate": "2018-07-01" }, @@ -220,6 +234,17 @@ "product": "Candles", "dataSetVersion": "dataSet.V1", "dataSet": "Multi-Period-Daily" + }, + { + "devTeam": "AAMasters", + "bot": "AABruce", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Candles", + "dataSetVersion": "dataSet.V1", + "dataSet": "One-Min" } ] } @@ -234,14 +259,27 @@ { "codeName": "Multi-Period-Market", "type": "Market Files", - "validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs" ], + "validPeriods": [ + "24-hs", + "12-hs", + "08-hs", + "06-hs", + "04-hs", + "03-hs", + "02-hs", + "01-hs" + ], "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Trading-Simulation/Multi-Period-Market/@Period", "fileName": "@AssetA_@AssetB.json" }, { "codeName": "Multi-Period-Daily", "type": "Daily Files", - "validPeriods": [ "15-min", "10-min", "05-min" ], + "validPeriods": [ + "15-min", + "10-min", + "05-min" + ], "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Trading-Simulation/Multi-Period-Daily/@Period/@Year/@Month/@Day", "fileName": "@AssetA_@AssetB.json", "dataRange": { @@ -273,14 +311,27 @@ { "codeName": "Multi-Period-Market", "type": "Market Files", - "validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs" ], + "validPeriods": [ + "24-hs", + "12-hs", + "08-hs", + "06-hs", + "04-hs", + "03-hs", + "02-hs", + "01-hs" + ], "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Conditions/Multi-Period-Market/@Period", "fileName": "@AssetA_@AssetB.json" }, { "codeName": "Multi-Period-Daily", "type": "Daily Files", - "validPeriods": [ "15-min", "10-min", "05-min" ], + "validPeriods": [ + "15-min", + "10-min", + "05-min" + ], "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Conditions/Multi-Period-Daily/@Period/@Year/@Month/@Day", "fileName": "@AssetA_@AssetB.json", "dataRange": { @@ -312,14 +363,27 @@ { "codeName": "Multi-Period-Market", "type": "Market Files", - "validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs" ], + "validPeriods": [ + "24-hs", + "12-hs", + "08-hs", + "06-hs", + "04-hs", + "03-hs", + "02-hs", + "01-hs" + ], "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Strategies/Multi-Period-Market/@Period", "fileName": "@AssetA_@AssetB.json" }, { "codeName": "Multi-Period-Daily", "type": "Daily Files", - "validPeriods": [ "15-min", "10-min", "05-min" ], + "validPeriods": [ + "15-min", + "10-min", + "05-min" + ], "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Strategies/Multi-Period-Daily/@Period/@Year/@Month/@Day", "fileName": "@AssetA_@AssetB.json", "dataRange": { @@ -351,14 +415,27 @@ { "codeName": "Multi-Period-Market", "type": "Market Files", - "validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs" ], + "validPeriods": [ + "24-hs", + "12-hs", + "08-hs", + "06-hs", + "04-hs", + "03-hs", + "02-hs", + "01-hs" + ], "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Trades/Multi-Period-Market/@Period", "fileName": "@AssetA_@AssetB.json" }, { "codeName": "Multi-Period-Daily", "type": "Daily Files", - "validPeriods": [ "15-min", "10-min", "05-min" ], + "validPeriods": [ + "15-min", + "10-min", + "05-min" + ], "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Trades/Multi-Period-Daily/@Period/@Year/@Month/@Day", "fileName": "@AssetA_@AssetB.json", "dataRange": { @@ -390,7 +467,27 @@ { "codeName": "Oficial History", "type": "File Sequence", - "validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs", "45-min", "40-min", "30-min", "20-min", "15-min", "10-min", "05-min", "04-min", "03-min", "02-min", "01-min" ], + "validPeriods": [ + "24-hs", + "12-hs", + "08-hs", + "06-hs", + "04-hs", + "03-hs", + "02-hs", + "01-hs", + "45-min", + "40-min", + "30-min", + "20-min", + "15-min", + "10-min", + "05-min", + "04-min", + "03-min", + "02-min", + "01-min" + ], "filePath": "@DevTeam/@Bot.1.0/AACloud.1.1/Poloniex/dataSet.V1/Output/Trading-Process", "fileName": "Execution.History.Live.@Sequence.json" } @@ -406,8 +503,22 @@ "moduleName": "SimulationExecution" } } - ] -} - - - + ], + "marketRateProvider": { + "devTeam": "AAMasters", + "bot": "AABruce", + "host": { + "url": "https://demo-dev.superalgos.org/", + "storage": "localStorage", + "container": "aamasters", + "accessKey": "" + }, + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Candles", + "dataSet": "One-Min", + "dataSetVersion": "dataSet.V1" + } +} \ No newline at end of file From 4a0e62cd95cb27ec115d55a12c59287f977c145a Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 13 Aug 2019 11:47:30 +0200 Subject: [PATCH 181/244] Better Logging experience --- Commons.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Commons.js b/Commons.js index 8bbb55daa..9ada6529f 100644 --- a/Commons.js +++ b/Commons.js @@ -1372,6 +1372,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { takePositionNow === true ) { takePositionNow = false + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> takePositionNow -> Entering code block."); } /* Position size and rate */ let strategy = tradingSystem.strategies[currentStrategyIndex]; @@ -1402,9 +1403,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { break } case "Taking Position": { // Waiting for a confirmation that the position was taken. + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> takePositionNow -> Exiting code block because status is Taking Position."); } break } case "In a Position": { // This should mean that we already put the order at the exchange. + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> takePositionNow -> Exiting code block because status is In a Position."); } break } } @@ -1427,23 +1430,28 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* We wont take a position unless we are withing the startDate and the endDate range */ if (startDate !== undefined) { if (candle.begin < startDate.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because current candle begins before the start date. -> startDate = " + startDate); } takePositionAtSimulation() return; } } + /* This validation is disbled for now because we do not have the correct end date at this point. if (endDate !== undefined) { if (candle.begin > endDate.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because current candle begins after the end date. -> endDate = " + endDate); } takePositionAtSimulation() return; } } + */ /* Checking the status of current positions */ let positions = assistant.getPositions(); if (positions.length > 0) { let position = positions[positions.length - 1] // We are allways checking the the last position is not open. if (position.status === 'open') { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because the last position is still open. "); } afterLoop(); return } @@ -1454,6 +1462,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (interExecutionMemory.executionContext !== undefined) { if (interExecutionMemory.executionContext.periods !== undefined) { if (periods <= interExecutionMemory.executionContext.periods) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because it was already placed at a previous execution." ); } takePositionAtSimulation() return; } @@ -1464,6 +1473,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let today = new Date(Math.trunc((new Date().valueOf()) / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) let processDay = new Date(Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) if (today.valueOf() !== processDay.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because the current candle belongs to the previous day and that is considered simulation and not live trading."); } takePositionAtSimulation() return; } @@ -1493,6 +1503,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { status: "Taking Position" } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Ready to put order."); } assistant.putPosition(positionDirection, openPositionRate, amountA, amountB, onOrderPut) function onOrderPut(err) { @@ -1581,6 +1592,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Closing a Position */ if (strategyStage === 'Close Stage') { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Closing a Position -> Entering code block."); } + /* Position size and rate */ let strategy = tradingSystem.strategies[currentStrategyIndex]; @@ -1589,6 +1602,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (interExecutionMemory.executionContext !== undefined) { switch (interExecutionMemory.executionContext.status) { case "Without a Position": { // No way to close anything at the exchange. + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Closing a Position -> Exiting code block because status is Without a Position."); } break } case "In a Position": { // This should mean that we already put the order at the exchange. @@ -1611,6 +1625,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } case "Position Closed": { // + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Closing a Position -> Exiting code block because status is Position Closed."); } break } } @@ -1628,6 +1643,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (positions.length > 0) { let position = positions[positions.length - 1] // We are allways checking the the last position is not open. if (position.status === 'open') { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> Exiting function because status of last position is Open."); } afterLoop(); return } @@ -1638,6 +1654,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (interExecutionMemory.executionContext !== undefined) { if (interExecutionMemory.executionContext.periods !== undefined) { if (periods <= interExecutionMemory.executionContext.periods) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> Exiting function because this closing was already submited at a previous execution."); } closePositionAtSimulation() return; } @@ -1669,6 +1686,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { status: "Closing Position" } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> About to close position at the exchange."); } assistant.putPosition(positionDirection, closePositionRate, amountA, amountB, onOrderPut) function onOrderPut(err) { From 4a9819a3c0d440bff45792760577fd1db538078c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 14 Aug 2019 19:12:42 +0200 Subject: [PATCH 182/244] Better Logging --- Commons.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Commons.js b/Commons.js index 9ada6529f..b49271578 100644 --- a/Commons.js +++ b/Commons.js @@ -369,22 +369,27 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* If any of the needed indicators is missing, then that period is not calculated */ if (candle.begin < initialDate.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Record before the initialDate."); } controlLoop(); return } if (bollingerBand === undefined) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Record because Bollinger Band is undefined."); } controlLoop(); return } if (percentageBandwidth === undefined) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Record because %B is undefined."); } controlLoop(); return } // percentageBandwidth might start after the first few candles. if (bollingerChannel === undefined) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Record because Bollingeer Channel is undefined."); } controlLoop(); return } if (bollingerSubChannel === undefined) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Record because Bollingeer Sub Channel is undefined."); } controlLoop(); return } From 4934a2eb2ce018350be41da56be4343182aecc45 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 16 Aug 2019 17:51:01 +0200 Subject: [PATCH 183/244] Preventing exchage trades on Backtest --- Commons.js | 200 +++++++++++++++++++++++++++++------------------------ 1 file changed, 109 insertions(+), 91 deletions(-) diff --git a/Commons.js b/Commons.js index b49271578..536197b36 100644 --- a/Commons.js +++ b/Commons.js @@ -368,7 +368,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* If any of the needed indicators is missing, then that period is not calculated */ - if (candle.begin < initialDate.valueOf()) { + if (candle.end < initialDate.valueOf()) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Record before the initialDate."); } controlLoop(); return @@ -405,16 +405,16 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } /* We skip the candle at the head of the market because i has not closed yet. */ - let candlesPerDay = ONE_DAY_IN_MILISECONDS / timePeriod - if (i === candles.length - 1) { - if ((candles.length < candlesPerDay) || (candles.length > candlesPerDay && candles.length < candlesPerDay * 2)) { + //let candlesPerDay = ONE_DAY_IN_MILISECONDS / timePeriod + //if (i === candles.length - 1) { + // if ((candles.length < candlesPerDay) || (candles.length > candlesPerDay && candles.length < candlesPerDay * 2)) { /*We are at the head of the market, thus we skip the last candle because it has not close yet. */ - controlLoop(); - return + // controlLoop(); + // return /* Note here that in the last candle of the first day or the second day it will use an incomplete candle and partially calculated indicators. if we skip these two periods, then there will be a hole in the file since the last period will be missing. */ - } - } + // } + //} } else { // We are processing Market Files if (i === candles.length - 1) { controlLoop(); @@ -955,6 +955,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentStrategy.begin = candle.begin; currentStrategy.beginRate = candle.min; currentStrategy.endRate = candle.min; // In case the strategy does not get exited + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Switching to Trigger Stage because conditions at Trigger On Event were met."); } break; } } @@ -1009,6 +1011,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentStrategy.status = 1; strategyStage = 'No Stage'; currentStrategyIndex = -1; + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Switching to No Stage because conditions at the Trigger Off Event were met."); } break; } } @@ -1057,6 +1061,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentTrade.begin = candle.begin; currentTrade.beginRate = candle.close; takePositionNow = true + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Conditions at the Take Position Event were met."); } break; } } @@ -1377,7 +1383,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { takePositionNow === true ) { takePositionNow = false - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> takePositionNow -> Entering code block."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionNow -> Entering code block."); } /* Position size and rate */ let strategy = tradingSystem.strategies[currentStrategyIndex]; @@ -1385,42 +1391,44 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { tradePositionSize = strategy.positionSize; tradePositionRate = strategy.positionRate; - /* We see if we need to put the actual order at the exchange. */ - - if (interExecutionMemory.executionContext !== undefined) { - switch (interExecutionMemory.executionContext.status) { - case "Without a Position": { // We need to put the order because It was not put yet. - if (strategy.openStage !== undefined) { - if (strategy.openStage.openExecution !== undefined) { - putOpeningOrder() - return + /* Check that we are in LIVE MODE */ + if (process.env.START_MODE === "live") { + /* We see if we need to put the actual order at the exchange. */ + if (interExecutionMemory.executionContext !== undefined) { + switch (interExecutionMemory.executionContext.status) { + case "Without a Position": { // We need to put the order because It was not put yet. + if (strategy.openStage !== undefined) { + if (strategy.openStage.openExecution !== undefined) { + putOpeningOrder() + return + } } + break } - break - } - case "Position Closed": { // Waiting for a confirmation that the position was closed. - if (strategy.openStage !== undefined) { - if (strategy.openStage.openExecution !== undefined) { - putOpeningOrder() - return + case "Position Closed": { // Waiting for a confirmation that the position was closed. + if (strategy.openStage !== undefined) { + if (strategy.openStage.openExecution !== undefined) { + putOpeningOrder() + return + } } + break + } + case "Taking Position": { // Waiting for a confirmation that the position was taken. + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionNow -> Exiting code block because status is Taking Position."); } + break + } + case "In a Position": { // This should mean that we already put the order at the exchange. + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionNow -> Exiting code block because status is In a Position."); } + break } - break } - case "Taking Position": { // Waiting for a confirmation that the position was taken. - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> takePositionNow -> Exiting code block because status is Taking Position."); } - break - } - case "In a Position": { // This should mean that we already put the order at the exchange. - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> takePositionNow -> Exiting code block because status is In a Position."); } - break - } - } - } else { // The context does not exist so it means we are not in a position. - if (strategy.openStage !== undefined) { - if (strategy.openStage.openExecution !== undefined) { - putOpeningOrder() - return + } else { // The context does not exist so it means we are not in a position. + if (strategy.openStage !== undefined) { + if (strategy.openStage.openExecution !== undefined) { + putOpeningOrder() + return + } } } } @@ -1430,12 +1438,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function putOpeningOrder() { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Entering function."); } /* We wont take a position unless we are withing the startDate and the endDate range */ if (startDate !== undefined) { - if (candle.begin < startDate.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because current candle begins before the start date. -> startDate = " + startDate); } + if (candle.end < startDate.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because current candle ends before the start date. -> startDate = " + startDate); } takePositionAtSimulation() return; } @@ -1456,7 +1464,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (positions.length > 0) { let position = positions[positions.length - 1] // We are allways checking the the last position is not open. if (position.status === 'open') { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because the last position is still open. "); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because the last position is still open. "); } afterLoop(); return } @@ -1467,7 +1475,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (interExecutionMemory.executionContext !== undefined) { if (interExecutionMemory.executionContext.periods !== undefined) { if (periods <= interExecutionMemory.executionContext.periods) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because it was already placed at a previous execution." ); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because it was already placed at a previous execution." ); } takePositionAtSimulation() return; } @@ -1478,7 +1486,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let today = new Date(Math.trunc((new Date().valueOf()) / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) let processDay = new Date(Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) if (today.valueOf() !== processDay.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because the current candle belongs to the previous day and that is considered simulation and not live trading."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because the current candle belongs to the previous day and that is considered simulation and not live trading."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> today = " + today); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> processDay = " + processDay); } takePositionAtSimulation() return; } @@ -1508,16 +1518,16 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { status: "Taking Position" } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Ready to put order."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Ready to put order."); } assistant.putPosition(positionDirection, openPositionRate, amountA, amountB, onOrderPut) function onOrderPut(err) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderPut -> Entering function."); } try { switch (err.result) { case global.DEFAULT_OK_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_OK_RESPONSE "); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderPut -> DEFAULT_OK_RESPONSE "); } interExecutionMemory.executionContext = { status: "In a Position", periods: periods, @@ -1528,24 +1538,26 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { return; } case global.DEFAULT_FAIL_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_FAIL_RESPONSE "); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderPut -> DEFAULT_FAIL_RESPONSE "); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[ERROR] runSimulation -> loop -> putOpeningOrder -> onOrderPut -> Message = " + err.message); } strategy.openStage.openExecution.error = err.message afterLoop() return; } case global.DEFAULT_RETRY_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_RETRY_RESPONSE "); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderPut -> DEFAULT_RETRY_RESPONSE "); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[ERROR] runSimulation -> loop -> putOpeningOrder -> onOrderPut -> Message = " + err.message); } strategy.openStage.openExecution.error = err.message afterLoop() return; } } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[ERROR] runSimulation -> putOpeningOrder -> onOrderPut -> Unexpected Response -> Message = " + err.message); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[ERROR] runSimulation -> loop -> putOpeningOrder -> onOrderPut -> Unexpected Response -> Message = " + err.message); } callBackFunction(global.DEFAULT_FAIL_RESPONSE); return } catch (err) { - logger.write(MODULE_NAME, "[ERROR] runSimulation -> putOpeningOrder -> onOrderPut -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] runSimulation -> loop -> putOpeningOrder -> onOrderPut -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return } @@ -1589,6 +1601,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } addRecord(); + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionAtSimulation -> Exiting Loop Body after taking position at simulation."); } controlLoop(); return } @@ -1597,41 +1610,43 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Closing a Position */ if (strategyStage === 'Close Stage') { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Closing a Position -> Entering code block."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing a Position -> Entering code block."); } /* Position size and rate */ let strategy = tradingSystem.strategies[currentStrategyIndex]; - /* We see if we need to put the actual order at the exchange. */ - - if (interExecutionMemory.executionContext !== undefined) { - switch (interExecutionMemory.executionContext.status) { - case "Without a Position": { // No way to close anything at the exchange. - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Closing a Position -> Exiting code block because status is Without a Position."); } - break - } - case "In a Position": { // This should mean that we already put the order at the exchange. - if (strategy.closeStage !== undefined) { - if (strategy.closeStage.closeExecution !== undefined) { - putClosingOrder() - return - } + /* Check that we are in LIVE MODE */ + if (process.env.START_MODE === "live") { + /* We see if we need to put the actual order at the exchange. */ + if (interExecutionMemory.executionContext !== undefined) { + switch (interExecutionMemory.executionContext.status) { + case "Without a Position": { // No way to close anything at the exchange. + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing a Position -> Exiting code block because status is Without a Position."); } + break } - break - } - case "Closing Position": { // Waiting for a confirmation that the position was taken. - if (strategy.closeStage !== undefined) { - if (strategy.closeStage.closeExecution !== undefined) { - putClosingOrder() - return + case "In a Position": { // This should mean that we already put the order at the exchange. + if (strategy.closeStage !== undefined) { + if (strategy.closeStage.closeExecution !== undefined) { + putClosingOrder() + return + } } + break + } + case "Closing Position": { // Waiting for a confirmation that the position was taken. + if (strategy.closeStage !== undefined) { + if (strategy.closeStage.closeExecution !== undefined) { + putClosingOrder() + return + } + } + break } - break - } - case "Position Closed": { // - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Closing a Position -> Exiting code block because status is Position Closed."); } - break + case "Position Closed": { // + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing a Position -> Exiting code block because status is Position Closed."); } + break + } } } } @@ -1648,7 +1663,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (positions.length > 0) { let position = positions[positions.length - 1] // We are allways checking the the last position is not open. if (position.status === 'open') { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> Exiting function because status of last position is Open."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> Exiting function because status of last position is Open."); } afterLoop(); return } @@ -1659,7 +1674,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (interExecutionMemory.executionContext !== undefined) { if (interExecutionMemory.executionContext.periods !== undefined) { if (periods <= interExecutionMemory.executionContext.periods) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> Exiting function because this closing was already submited at a previous execution."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> Exiting function because this closing was already submited at a previous execution."); } closePositionAtSimulation() return; } @@ -1691,16 +1706,16 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { status: "Closing Position" } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> About to close position at the exchange."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> About to close position at the exchange."); } assistant.putPosition(positionDirection, closePositionRate, amountA, amountB, onOrderPut) function onOrderPut(err) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> onOrderPut -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> onOrderPut -> Entering function."); } try { switch (err.result) { case global.DEFAULT_OK_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> onOrderPut -> DEFAULT_OK_RESPONSE "); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> onOrderPut -> DEFAULT_OK_RESPONSE "); } interExecutionMemory.executionContext = { status: "Position Closed", periods: periods, @@ -1711,25 +1726,25 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { return; } case global.DEFAULT_FAIL_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putClosingOrder -> onOrderPut -> DEFAULT_FAIL_RESPONSE "); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> onOrderPut -> DEFAULT_FAIL_RESPONSE "); } /* We will assume that the problem is temporary, and expect that it will work at the next execution.*/ strategy.closeStage.closeExecution.error = err.message afterLoop() return; } case global.DEFAULT_RETRY_RESPONSE.result: { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> onOrderPut -> DEFAULT_RETRY_RESPONSE "); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> onOrderPut -> DEFAULT_RETRY_RESPONSE "); } strategy.closeStage.closeExecution.error = err.message afterLoop() return; } } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[ERROR] runSimulation -> putClosingOrder -> onOrderPut -> Unexpected Response -> Message = " + err.message); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[ERROR] runSimulation -> loop -> putClosingOrder -> onOrderPut -> Unexpected Response -> Message = " + err.message); } callBackFunction(global.DEFAULT_FAIL_RESPONSE); return } catch (err) { - logger.write(MODULE_NAME, "[ERROR] runSimulation -> putClosingOrder -> onOrderPut -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] runSimulation -> loop -> putClosingOrder -> onOrderPut -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); return } @@ -1820,6 +1835,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { takeProfitStage = 'No Stage'; stopLossPhase = 0; takeProfitPhase = 0; + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> closePositionAtSimulation -> Exiting Loop Body after closing position at simulation."); } controlLoop(); return } @@ -1829,6 +1846,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { marketRate = candle.close; addRecord(); + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Exiting Loop Body after adding a record."); } controlLoop(); return @@ -1850,13 +1868,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { messageType = MESSAGE_TYPE.Order; orderId++; - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> addRecord -> Taking Position Now. "); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> addRecord -> Taking Position Now. "); } } else { if (type === '"Close@TakeProfit"' || type === '"Close@StopLoss"') { messageType = MESSAGE_TYPE.OrderClose; - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> addRecord -> Closing Position Now. "); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> addRecord -> Closing Position Now. "); } } else { messageType = MESSAGE_TYPE.OrderUpdate; From ee53848cd8811d701123e04993c692d16f9304b3 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 17 Aug 2019 09:57:10 +0200 Subject: [PATCH 184/244] All time periods enabled --- this.bot.config.json | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/this.bot.config.json b/this.bot.config.json index 5f8b5b17c..f3e9d543f 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -276,9 +276,16 @@ "codeName": "Multi-Period-Daily", "type": "Daily Files", "validPeriods": [ + "45-min", + "30-min", + "20-min", "15-min", "10-min", - "05-min" + "05-min", + "04-min", + "03-min", + "02-min", + "01-min" ], "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Trading-Simulation/Multi-Period-Daily/@Period/@Year/@Month/@Day", "fileName": "@AssetA_@AssetB.json", @@ -328,9 +335,16 @@ "codeName": "Multi-Period-Daily", "type": "Daily Files", "validPeriods": [ + "45-min", + "30-min", + "20-min", "15-min", "10-min", - "05-min" + "05-min", + "04-min", + "03-min", + "02-min", + "01-min" ], "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Conditions/Multi-Period-Daily/@Period/@Year/@Month/@Day", "fileName": "@AssetA_@AssetB.json", @@ -380,9 +394,16 @@ "codeName": "Multi-Period-Daily", "type": "Daily Files", "validPeriods": [ + "45-min", + "30-min", + "20-min", "15-min", "10-min", - "05-min" + "05-min", + "04-min", + "03-min", + "02-min", + "01-min" ], "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Strategies/Multi-Period-Daily/@Period/@Year/@Month/@Day", "fileName": "@AssetA_@AssetB.json", @@ -432,9 +453,16 @@ "codeName": "Multi-Period-Daily", "type": "Daily Files", "validPeriods": [ + "45-min", + "30-min", + "20-min", "15-min", "10-min", - "05-min" + "05-min", + "04-min", + "03-min", + "02-min", + "01-min" ], "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Trades/Multi-Period-Daily/@Period/@Year/@Month/@Day", "fileName": "@AssetA_@AssetB.json", From 64349d4cfdc25be09753d20f6c95d8e5ccc6bc3d Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 17 Aug 2019 12:23:06 +0200 Subject: [PATCH 185/244] All Periods --- Commons.js | 50 +++++++++++++++++++++++++-------- Multi-Period-Daily/User.Bot.js | 4 ++- Multi-Period-Market/User.Bot.js | 4 ++- this.bot.config.json | 9 +++++- 4 files changed, 53 insertions(+), 14 deletions(-) diff --git a/Commons.js b/Commons.js index 536197b36..0c2964ef1 100644 --- a/Commons.js +++ b/Commons.js @@ -194,6 +194,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let hitRatio = 0; let ROI = 0; let days = 0; + let positionDays = 0; let anualizedRateOfReturn = 0; let type = '""'; let marketRate = 0; @@ -256,6 +257,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let fails = 0; let hits = 0; let periods = 0; + let positionPeriods = 0; /* Message to the Simulation Executor */ @@ -275,6 +277,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { yesterday.fails = 0; yesterday.hits = 0; yesterday.Periods = 0; + yesterday.positionPeriods = 0; yesterday.orderId = 0; yesterday.messageId = 0; @@ -298,6 +301,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { interExecutionMemory.fails = 0; interExecutionMemory.hits = 0; interExecutionMemory.periods = 0; + interExecutionMemory.positionPeriods = 0; interExecutionMemory.orderId = 0; interExecutionMemory.messageId = 0; @@ -328,6 +332,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { fails = interExecutionMemory.fails; hits = interExecutionMemory.hits; periods = interExecutionMemory.periods; + positionPeriods = interExecutionMemory.positionPeriods; orderId = interExecutionMemory.orderId; messageId = interExecutionMemory.messageId; @@ -405,16 +410,17 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } /* We skip the candle at the head of the market because i has not closed yet. */ - //let candlesPerDay = ONE_DAY_IN_MILISECONDS / timePeriod - //if (i === candles.length - 1) { - // if ((candles.length < candlesPerDay) || (candles.length > candlesPerDay && candles.length < candlesPerDay * 2)) { + let candlesPerDay = ONE_DAY_IN_MILISECONDS / timePeriod + if (i === candles.length - 1) { + if ((candles.length < candlesPerDay) || (candles.length > candlesPerDay && candles.length < candlesPerDay * 2)) { /*We are at the head of the market, thus we skip the last candle because it has not close yet. */ - // controlLoop(); - // return + controlLoop(); + return /* Note here that in the last candle of the first day or the second day it will use an incomplete candle and partially calculated indicators. if we skip these two periods, then there will be a hole in the file since the last period will be missing. */ - // } - //} + } + } + } else { // We are processing Market Files if (i === candles.length - 1) { controlLoop(); @@ -1284,6 +1290,26 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } + /* Keeping Position Counters Up-to-date */ + if ( + (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') + ) { + + if (takePositionNow === true) { + positionPeriods = 0 + yesterday.positionPeriods = 0 + } + + positionPeriods++; + positionDays = positionPeriods * timePeriod / ONE_DAY_IN_MILISECONDS; + + if (currentDay !== undefined) { // This means that we are processing Daily Files + if (candle.end < currentDay.valueOf()) { + yesterday.positionPeriods++; + } + } + } + /* Checking if Stop or Take Profit were hit */ if ( (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') && @@ -1501,14 +1527,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (baseAsset === 'BTC') { positionDirection = "sell" - openPositionRate = tradePositionRate - 100 // Provisional stuff to simulate a market order. Put the price lower to get it executed quickly + openPositionRate = tradePositionRate amountA = tradePositionSize * openPositionRate amountB = tradePositionSize } else { positionDirection = "buy" - openPositionRate = tradePositionRate + 100 // Provisional stuff to simulate a market order. Put the price higher to get it executed quickly + openPositionRate = tradePositionRate amountA = tradePositionSize amountB = tradePositionSize / openPositionRate @@ -1568,7 +1594,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionAtSimulation -> Entering function."); } /* Continue with the simulation */ - calculateTakeProfit(); calculateStopLoss(); @@ -2017,7 +2042,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { initialBalanceB: initialBalanceB, minimumBalanceB: minimumBalanceB, maximumBalanceB: maximumBalanceB, - baseAsset: quotedBaseAsset + baseAsset: quotedBaseAsset, + positionPeriods: positionPeriods, + positionDays: positionDays } recordsArray.push(simulationRecord); @@ -2111,6 +2138,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { interExecutionMemory.fails = interExecutionMemory.fails + yesterday.fails; interExecutionMemory.hits = interExecutionMemory.hits + yesterday.hits; interExecutionMemory.periods = interExecutionMemory.periods + yesterday.Periods; + interExecutionMemory.positionPeriods = interExecutionMemory.positionPeriods + yesterday.positionPeriods; interExecutionMemory.messageId = interExecutionMemory.messageId + yesterday.messageId; interExecutionMemory.orderId = interExecutionMemory.orderId + yesterday.orderId; diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index ca0130408..89b84fe38 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -248,7 +248,9 @@ record.initialBalanceB + "," + record.minimumBalanceB + "," + record.maximumBalanceB + "," + - record.baseAsset + "]"; + record.baseAsset + "," + + record.positionPeriods + "," + + record.positionDays + "]"; if (separator === "") { separator = ","; } diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 5bac69a1f..5b8d6ca62 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -240,7 +240,9 @@ record.initialBalanceB + "," + record.minimumBalanceB + "," + record.maximumBalanceB + "," + - record.baseAsset + "]"; + record.baseAsset + "," + + record.positionPeriods + "," + + record.positionDays + "]"; if (separator === "") { separator = ","; } diff --git a/this.bot.config.json b/this.bot.config.json index f3e9d543f..447906e76 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -126,9 +126,16 @@ "framework": { "name": "Multi-Period-Daily", "validPeriods": [ + "45-min", + "30-min", + "20-min", "15-min", "10-min", - "05-min" + "05-min", + "04-min", + "03-min", + "02-min", + "01-min" ], "startDate": { "fixedDate": "2018-07-01" From 63fb05feecb8d0d477de2413d19d87233b90ebb2 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 17 Aug 2019 12:32:00 +0200 Subject: [PATCH 186/244] Reseting new counters --- Commons.js | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/Commons.js b/Commons.js index 0c2964ef1..d9e3dc07f 100644 --- a/Commons.js +++ b/Commons.js @@ -5,9 +5,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { const { orderMessage } = require("@superalgos/mqservice") const { - MESSAGE_ENTITY, MESSAGE_TYPE, ORDER_CREATOR, ORDER_TYPE, - ORDER_OWNER, ORDER_DIRECTION, ORDER_STATUS, ORDER_EXIT_OUTCOME, - createMessage, getMessage, getExpandedMessage + MESSAGE_ENTITY, MESSAGE_TYPE, ORDER_CREATOR, ORDER_TYPE, + ORDER_OWNER, ORDER_DIRECTION, ORDER_STATUS, ORDER_EXIT_OUTCOME, + createMessage, getMessage, getExpandedMessage } = orderMessage.newOrderMessage() const FULL_LOG = true; @@ -97,7 +97,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (tradingSystem.parameters !== undefined) { if (tradingSystem.parameters.baseAsset !== undefined) { if (tradingSystem.parameters.baseAsset.formula !== undefined) { - let receivedParameters + let receivedParameters try { receivedParameters = JSON.parse(tradingSystem.parameters.baseAsset.formula.code); @@ -164,7 +164,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Strategy and Phases */ let currentStrategyIndex = -1; - let strategyStage = 'No Stage'; + let strategyStage = 'No Stage'; /* Stop Loss Management */ @@ -172,7 +172,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { const MAX_STOP_LOSS_VALUE = Number.MAX_SAFE_INTEGER let stopLoss = 0; let stopLossPhase = 0; - let stopLossStage = 'No Stage'; + let stopLossStage = 'No Stage'; /* Take Profit Management */ @@ -181,7 +181,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let previousTakeProfit = 0; let takeProfit = 0; let takeProfitPhase = 0; - let takeProfitStage = 'No Stage'; + let takeProfitStage = 'No Stage'; /* Simulation Records */ @@ -322,8 +322,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { yesterday.balanceAssetA = balanceAssetA; yesterday.balanceAssetB = balanceAssetB; - } - + } + lastTradeProfitLoss = interExecutionMemory.lastTradeProfitLoss; profit = interExecutionMemory.profit; lastTradeROI = interExecutionMemory.lastTradeROI; @@ -344,9 +344,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { yesterday.hitRatio = hitRatio; yesterday.ROI = ROI; yesterday.anualizedRateOfReturn = anualizedRateOfReturn; - + } - + /* Main Simulation Loop: We go thourgh all the candles at this time period. */ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Main Simulation Loop -> candles.length = " + candles.length); } @@ -359,7 +359,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { loop() } - function loop() { + function loop() { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Entering function."); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> i = " + i); } @@ -1292,7 +1292,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Keeping Position Counters Up-to-date */ if ( - (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') + (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') ) { if (takePositionNow === true) { @@ -1308,6 +1308,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { yesterday.positionPeriods++; } } + } else { + positionPeriods = 0 + yesterday.positionPeriods = 0 + positionDays = 0 } /* Checking if Stop or Take Profit were hit */ @@ -1501,7 +1505,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (interExecutionMemory.executionContext !== undefined) { if (interExecutionMemory.executionContext.periods !== undefined) { if (periods <= interExecutionMemory.executionContext.periods) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because it was already placed at a previous execution." ); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because it was already placed at a previous execution."); } takePositionAtSimulation() return; } @@ -1509,7 +1513,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } /* We are not going to place orders based on outdated information. The next filter prevents firing orders when backtesting. */ - let today = new Date(Math.trunc((new Date().valueOf()) / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) + let today = new Date(Math.trunc((new Date().valueOf()) / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) let processDay = new Date(Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) if (today.valueOf() !== processDay.valueOf()) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because the current candle belongs to the previous day and that is considered simulation and not live trading."); } @@ -1527,7 +1531,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (baseAsset === 'BTC') { positionDirection = "sell" - openPositionRate = tradePositionRate + openPositionRate = tradePositionRate amountA = tradePositionSize * openPositionRate amountB = tradePositionSize @@ -1536,7 +1540,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { openPositionRate = tradePositionRate - amountA = tradePositionSize + amountA = tradePositionSize amountB = tradePositionSize / openPositionRate } @@ -1677,7 +1681,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } closePositionAtSimulation() - return + return function putClosingOrder() { @@ -2168,7 +2172,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - return + return } } catch (err) { From 410c89cadedb75662ae521f24d3e1c88ecb46a55 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 18 Aug 2019 16:15:26 +0200 Subject: [PATCH 187/244] Multiple Fixes including Multi Day Trades --- Commons.js | 530 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 446 insertions(+), 84 deletions(-) diff --git a/Commons.js b/Commons.js index d9e3dc07f..dd6a6a7da 100644 --- a/Commons.js +++ b/Commons.js @@ -65,6 +65,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Entering function."); } + let processingDailyFiles = (currentDay !== undefined) + let executionArray = []; let recordsArray = []; let conditionsArray = []; @@ -161,18 +163,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - /* Strategy and Phases */ - - let currentStrategyIndex = -1; - let strategyStage = 'No Stage'; - /* Stop Loss Management */ const MIN_STOP_LOSS_VALUE = 1 // We can not let the stop be zero to avoid division by 0 error or infinity numbers as a result. const MAX_STOP_LOSS_VALUE = Number.MAX_SAFE_INTEGER let stopLoss = 0; - let stopLossPhase = 0; - let stopLossStage = 'No Stage'; /* Take Profit Management */ @@ -180,17 +175,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { const MAX_TAKE_PROFIT_VALUE = Number.MAX_SAFE_INTEGER let previousTakeProfit = 0; let takeProfit = 0; - let takeProfitPhase = 0; - let takeProfitStage = 'No Stage'; /* Simulation Records */ - let tradePositionRate = 0; - let tradePositionSize = 0; - let positionInstant; - - let previousBalanceAssetA = 0; - let previousBalanceAssetB = 0; let hitRatio = 0; let ROI = 0; let days = 0; @@ -200,34 +187,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let marketRate = 0; let takePositionNow = false - /* Assistant Info */ - - let ticker = assistant.getTicker(); - - /* In some cases we need to know if we are positioned at the last candle of the calendar day, for that we need thse variables. */ + /* In some cases we need to know if we are positioned at the last candle of the calendar day, for that we need these variables. */ let lastInstantOfTheDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1; let lastCandle = candles[candles.length - 1]; - /* These 2 objects will allow us to create separate files for each one of them. */ - - let currentStrategy = { - begin: 0, - end: 0, - status: 0, - number: 0 - } - - let currentTrade = { - begin: 0, - end: 0, - status: 0, - profit: 0, - exitType: 0, - beginRate: 0, - endRate: 0 - } - /* The following counters need to survive multiple executions of the similator and keep themselves reliable. This is challenging when the simulation is executed using Daily Files, since each execution means a new @@ -246,6 +210,45 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { interExecutionMemory. */ + /*Needed for statistics */ + let previousBalanceAssetA = 0; + let previousBalanceAssetB = 0; + + /* Position Management */ + let tradePositionRate = 0; + let tradePositionSize = 0; + + /* Strategy and Phase Management */ + let currentStrategyIndex = -1; + let strategyStage = 'No Stage'; + + let stopLossPhase = 0; + let stopLossStage = 'No Stage'; + + let takeProfitPhase = 0; + let takeProfitStage = 'No Stage'; + + /* These 2 objects will allow us to create separate files for each one of them. */ + + let currentStrategy = { + begin: 0, + end: 0, + status: 0, + number: 0, + beginRate: 0, + endRate: 0 + } + + let currentTrade = { + begin: 0, + end: 0, + status: 0, + profit: 0, + exitType: 0, + beginRate: 0, + endRate: 0 + } + let balanceAssetA = initialBalanceA; let balanceAssetB = initialBalanceB; @@ -266,6 +269,42 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let yesterday = {}; + /* Initialization */ + + yesterday.previousBalanceAssetA = previousBalanceAssetA + yesterday.previousBalanceAssetB = previousBalanceAssetB + + yesterday.tradePositionRate = tradePositionRate + yesterday.tradePositionSize = tradePositionSize + + yesterday.currentStrategyIndex = currentStrategyIndex + yesterday.strategyStage = strategyStage + + yesterday.stopLossPhase = stopLossPhase + yesterday.stopLossStage = stopLossStage + + yesterday.takeProfitPhase = takeProfitPhase + yesterday.takeProfitStage = takeProfitStage + + yesterday.currentStrategy = { + begin: 0, + end: 0, + status: 0, + number: 0, + beginRate: 0, + endRate: 0 + } + + yesterday.currentTrade = { + begin: 0, + end: 0, + status: 0, + profit: 0, + exitType: 0, + beginRate: 0, + endRate: 0 + } + yesterday.balanceAssetA = balanceAssetA; yesterday.balanceAssetB = balanceAssetB; @@ -273,10 +312,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { yesterday.profit = 0; yesterday.lastTradeROI = 0; - yesterday.Roundtrips = 0; + yesterday.roundtrips = 0; yesterday.fails = 0; yesterday.hits = 0; - yesterday.Periods = 0; + yesterday.periods = 0; yesterday.positionPeriods = 0; yesterday.orderId = 0; @@ -290,6 +329,40 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Initialize the data structure we will use inter execution. */ + interExecutionMemory.previousBalanceAssetA = previousBalanceAssetA + interExecutionMemory.previousBalanceAssetB = previousBalanceAssetB + + interExecutionMemory.tradePositionRate = tradePositionRate + interExecutionMemory.tradePositionSize = tradePositionSize + + interExecutionMemory.currentStrategyIndex = currentStrategyIndex + interExecutionMemory.strategyStage = strategyStage + + interExecutionMemory.stopLossPhase = stopLossPhase + interExecutionMemory.stopLossStage = stopLossStage + + interExecutionMemory.takeProfitPhase = takeProfitPhase + interExecutionMemory.takeProfitStage = takeProfitStage + + interExecutionMemory.currentStrategy = { + begin: 0, + end: 0, + status: 0, + number: 0, + beginRate: 0, + endRate: 0 + } + + interExecutionMemory.currentTrade = { + begin: 0, + end: 0, + status: 0, + profit: 0, + exitType: 0, + beginRate: 0, + endRate: 0 + } + interExecutionMemory.balanceAssetA = balanceAssetA; interExecutionMemory.balanceAssetB = balanceAssetB; @@ -314,6 +387,40 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* We get the initial values from the day previous to the candles we receive at the current execution */ + previousBalanceAssetA = interExecutionMemory.previousBalanceAssetA + previousBalanceAssetB = interExecutionMemory.previousBalanceAssetB + + tradePositionRate = interExecutionMemory.tradePositionRate + tradePositionSize = interExecutionMemory.tradePositionSize + + currentStrategyIndex = interExecutionMemory.currentStrategyIndex + strategyStage = interExecutionMemory.strategyStage + + stopLossPhase = interExecutionMemory.stopLossPhase + stopLossStage = interExecutionMemory.stopLossStage + + takeProfitPhase = interExecutionMemory.takeProfitPhase + takeProfitStage = interExecutionMemory.takeProfitStage + + currentStrategy = { + begin: interExecutionMemory.currentStrategy.begin, + end: interExecutionMemory.currentStrategy.end, + status: interExecutionMemory.currentStrategy.status, + number: interExecutionMemory.currentStrategy.number, + beginRate: interExecutionMemory.currentStrategy.beginRate, + endRate: interExecutionMemory.currentStrategy.endRate + } + + currentTrade = { + begin: interExecutionMemory.currentTrade.begin, + end: interExecutionMemory.currentTrade.end, + status: interExecutionMemory.currentTrade.status, + profit: interExecutionMemory.currentTrade.profit, + exitType: interExecutionMemory.currentTrade.exitType, + beginRate: interExecutionMemory.currentTrade.beginRate, + endRate: interExecutionMemory.currentTrade.endRate + } + if (currentDay.valueOf() >= startDate.valueOf() + ONE_DAY_IN_MILISECONDS) { // Only after the first day we start grabbing the balance from this memory. balanceAssetA = interExecutionMemory.balanceAssetA; @@ -334,17 +441,62 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { periods = interExecutionMemory.periods; positionPeriods = interExecutionMemory.positionPeriods; - orderId = interExecutionMemory.orderId; - messageId = interExecutionMemory.messageId; + orderId = interExecutionMemory.orderId; // to be deprecated + messageId = interExecutionMemory.messageId; // to be deprecated hitRatio = interExecutionMemory.hitRatio; ROI = interExecutionMemory.ROI; anualizedRateOfReturn = interExecutionMemory.anualizedRateOfReturn; + /* For the case that any of these variables are not updated during the main loop, we need to store their value at the yesterday structure, otherwise it would be lost. */ + + yesterday.previousBalanceAssetA = previousBalanceAssetA + yesterday.previousBalanceAssetB = previousBalanceAssetB + + yesterday.tradePositionRate = tradePositionRate + yesterday.tradePositionSize = tradePositionSize + + yesterday.currentStrategyIndex = currentStrategyIndex; + yesterday.strategyStage = strategyStage; + + yesterday.stopLossPhase = stopLossPhase; + yesterday.stopLossStage = stopLossStage; + + yesterday.takeProfitPhase = takeProfitPhase; + yesterday.takeProfitStage = takeProfitStage; + + yesterday.currentStrategy = { + begin: currentStrategy.begin, + end: currentStrategy.end, + status: currentStrategy.status, + number: currentStrategy.number, + beginRate: currentStrategy.beginRate, + endRate: currentStrategy.endRate + } + + yesterday.currentTrade = { + begin: currentTrade.begin, + end: currentTrade.end, + status: currentTrade.status, + profit: currentTrade.profit, + exitType: currentTrade.exitType, + beginRate: currentTrade.beginRate, + endRate: currentTrade.endRate + } + + yesterday.lastTradeProfitLoss = lastTradeProfitLoss; + yesterday.profit = profit; + yesterday.lastTradeROI = lastTradeROI; + + yesterday.roundtrips = roundtrips; + yesterday.fails = fails; + yesterday.hits = hits; + yesterday.periods = periods; + yesterday.positionPeriods = positionPeriods; + yesterday.hitRatio = hitRatio; yesterday.ROI = ROI; yesterday.anualizedRateOfReturn = anualizedRateOfReturn; - } /* Main Simulation Loop: We go thourgh all the candles at this time period. */ @@ -360,6 +512,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } function loop() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Entering function."); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> i = " + i); } @@ -368,6 +521,21 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let bollingerBand = bollingerBandsMap.get(candle.begin); let bollingerChannel = getElement(bollingerChannelsArray, candle.begin, candle.end); let bollingerSubChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); + let positionedAtYesterday = (candle.end < currentDay.valueOf()) + + /* Assistant Info */ + + let ticker + + if (process.env.START_MODE === "live") { + ticker = assistant.getTicker() + } else { + ticker = { + bid: candle.close, + ask: candle.close, + last: candle.close + } + } //let LRC = LRCMap.get(candle.begin); @@ -404,9 +572,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { periods++; days = periods * timePeriod / ONE_DAY_IN_MILISECONDS; - if (currentDay !== undefined) { // This means that we are processing Daily Files - if (candle.end < currentDay.valueOf()) { - yesterday.Periods++; + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.periods = periods } /* We skip the candle at the head of the market because i has not closed yet. */ @@ -962,6 +1130,16 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentStrategy.beginRate = candle.min; currentStrategy.endRate = candle.min; // In case the strategy does not get exited + 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; + } + } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Switching to Trigger Stage because conditions at Trigger On Event were met."); } break; } @@ -1018,6 +1196,17 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategyStage = 'No Stage'; currentStrategyIndex = -1; + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.currentStrategy.number = currentStrategy.number; + yesterday.currentStrategy.end = currentStrategy.end; + yesterday.currentStrategy.endRate = currentStrategy.endRate; + yesterday.currentStrategy.status = currentStrategy.status; + yesterday.strategyStage = strategyStage; + yesterday.currentStrategyIndex = currentStrategyIndex; + } + } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Switching to No Stage because conditions at the Trigger Off Event were met."); } break; } @@ -1065,7 +1254,20 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { stopLossPhase = 1; takeProfitPhase = 1; currentTrade.begin = candle.begin; - currentTrade.beginRate = candle.close; + currentTrade.beginRate = strategy.positionRate; + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.strategyStage = strategyStage; + yesterday.stopLossStage = stopLossStage; + yesterday.takeProfitStage = takeProfitStage; + yesterday.stopLossPhase = stopLossPhase; + yesterday.takeProfitPhase = takeProfitPhase; + yesterday.currentTrade.begin = currentTrade.begin; + yesterday.currentTrade.beginRate = currentTrade.beginRate; + } + } + takePositionNow = true if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Conditions at the Take Position Event were met."); } @@ -1146,6 +1348,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { stopLossPhase++; stopLossStage = 'Manage Stage' if (takeProfitPhase > 1) { strategyStage = 'Manage Stage' } + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.stopLossPhase = stopLossPhase; + yesterday.stopLossStage = stopLossStage; + yesterday.strategyStage = strategyStage; + } + } return; } } @@ -1253,6 +1463,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { takeProfitPhase++; takeProfitStage = 'Manage Stage' if (stopLossPhase > 1) { strategyStage = 'Manage Stage' } + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.takeProfitPhase = takeProfitPhase; + yesterday.takeProfitStage = takeProfitStage; + yesterday.strategyStage = strategyStage; + } + } return; } } @@ -1297,21 +1515,31 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (takePositionNow === true) { positionPeriods = 0 - yesterday.positionPeriods = 0 + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.positionPeriods = 0 + } + } } positionPeriods++; positionDays = positionPeriods * timePeriod / ONE_DAY_IN_MILISECONDS; - if (currentDay !== undefined) { // This means that we are processing Daily Files - if (candle.end < currentDay.valueOf()) { - yesterday.positionPeriods++; + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.positionPeriods = positionPeriods } } } else { positionPeriods = 0 - yesterday.positionPeriods = 0 positionDays = 0 + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.positionPeriods = 0 + } + } } /* Checking if Stop or Take Profit were hit */ @@ -1342,8 +1570,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { balanceAssetA = 0; } - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { + if (processingDailyFiles) { + if (positionedAtYesterday) { yesterday.balanceAssetA = balanceAssetA; yesterday.balanceAssetB = balanceAssetB; } @@ -1363,9 +1591,25 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentStrategy.end = candle.end; currentStrategy.endRate = candle.min; currentStrategy.status = 1; + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.strategyStage = strategyStage; + yesterday.stopLossStage = stopLossStage; + yesterday.takeProfitStage = takeProfitStage; + yesterday.currentTrade.end = currentTrade.end; + yesterday.currentTrade.status = currentTrade.status; + yesterday.currentTrade.exitType = currentTrade.exitType; + yesterday.currentTrade.endRate = currentTrade.endRate; + yesterday.currentStrategy.number = currentStrategy.number; + yesterday.currentStrategy.end = currentStrategy.end; + yesterday.currentStrategy.endRate = currentStrategy.endRate; + yesterday.currentStrategy.status = currentStrategy.status; + } + } } - /* Take Profit condition: Here we verify if the Take Profit was filled or not. */ + /* Take Profit condition: Here we verify if the Take Profit was hit or not. */ if ((baseAsset === 'BTC' && candle.min <= takeProfit) || (baseAsset !== 'BTC' && candle.max >= takeProfit)) { @@ -1383,8 +1627,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { balanceAssetA = 0; } - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { + if (processingDailyFiles) { + if (positionedAtYesterday) { yesterday.balanceAssetA = balanceAssetA; yesterday.balanceAssetB = balanceAssetB; @@ -1396,6 +1640,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategyStage = 'Close Stage'; stopLossStage = 'No Stage'; takeProfitStage = 'No Stage'; + currentTrade.end = candle.end; currentTrade.status = 1; currentTrade.exitType = 2; @@ -1405,6 +1650,24 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentStrategy.end = candle.end; currentStrategy.endRate = candle.min; currentStrategy.status = 1; + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.strategyStage = strategyStage; + yesterday.stopLossStage = stopLossStage; + yesterday.takeProfitStage = takeProfitStage; + + yesterday.currentTrade.end = currentTrade.end; + yesterday.currentTrade.status = currentTrade.status; + yesterday.currentTrade.exitType = currentTrade.exitType; + yesterday.currentTrade.endRate = currentTrade.endRate; + + yesterday.currentStrategy.number = currentStrategy.number; + yesterday.currentStrategy.end = currentStrategy.end; + yesterday.currentStrategy.endRate = currentStrategy.endRate; + yesterday.currentStrategy.status = currentStrategy.status; + } + } } } @@ -1421,6 +1684,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { tradePositionSize = strategy.positionSize; tradePositionRate = strategy.positionRate; + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.tradePositionSize = tradePositionSize; + yesterday.tradePositionRate = tradePositionRate; + } + } + /* Check that we are in LIVE MODE */ if (process.env.START_MODE === "live") { /* We see if we need to put the actual order at the exchange. */ @@ -1606,6 +1876,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { previousBalanceAssetA = balanceAssetA; previousBalanceAssetB = balanceAssetB; + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.previousBalanceAssetA = previousBalanceAssetA; + yesterday.previousBalanceAssetB = previousBalanceAssetB; + } + } + lastTradeProfitLoss = 0; lastTradeROI = 0; @@ -1617,10 +1894,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { balanceAssetB = balanceAssetB - tradePositionSize; } - positionInstant = candle.end; - - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { + if (processingDailyFiles) { + if (positionedAtYesterday) { yesterday.balanceAssetA = balanceAssetA; yesterday.balanceAssetB = balanceAssetB; @@ -1785,9 +2060,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { roundtrips++; - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { - yesterday.Roundtrips++; + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.roundtrips = roundtrips } } @@ -1803,8 +2078,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { profit = balanceAssetB - initialBalanceB; } - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { + if (processingDailyFiles) { + if (positionedAtYesterday) { yesterday.lastTradeProfitLoss = lastTradeProfitLoss; yesterday.profit = profit; yesterday.lastTradeROI = lastTradeROI; @@ -1814,21 +2089,28 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentTrade.lastTradeROI = lastTradeROI; currentTrade.stopRate = stopLoss; + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.currentTrade.lastTradeROI = currentTrade.lastTradeROI; + yesterday.currentTrade.stopRate = currentTrade.stopRate; + } + } + if (lastTradeProfitLoss > 0) { hits++; - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { - yesterday.hits++; + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.hits = hits } } } else { fails++; - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { - yesterday.fails++; + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.fails = fails } } } @@ -1843,8 +2125,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { anualizedRateOfReturn = ROI / days * 365; } - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { + if (processingDailyFiles) { + if (positionedAtYesterday) { yesterday.ROI = ROI; yesterday.hitRatio = hitRatio; yesterday.anualizedRateOfReturn = anualizedRateOfReturn; @@ -1853,18 +2135,37 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { addRecord(); - currentStrategyIndex = -1; stopLoss = 0; + takeProfit = 0; + tradePositionRate = 0; tradePositionSize = 0; - positionInstant = undefined; - takeProfit = 0; + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.tradePositionSize = tradePositionSize; + yesterday.tradePositionRate = tradePositionRate; + } + } + + currentStrategyIndex = -1; strategyStage = 'No Stage'; stopLossStage = 'No Stage'; takeProfitStage = 'No Stage'; stopLossPhase = 0; takeProfitPhase = 0; + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.currentStrategyIndex = currentStrategyIndex; + yesterday.strategyStage = strategyStage; + yesterday.stopLossStage = stopLossStage; + yesterday.takeProfitStage = takeProfitStage; + yesterday.stopLossPhase = stopLossPhase; + yesterday.takeProfitPhase = takeProfitPhase; + } + } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> closePositionAtSimulation -> Exiting Loop Body after closing position at simulation."); } controlLoop(); return @@ -2084,6 +2385,19 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { beginRate: 0, endRate: 0 } + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.currentStrategy = { + begin: 0, + end: 0, + status: 0, + number: 0, + beginRate: 0, + endRate: 0 + } + } + } } /* Prepare the information for the Trades File */ @@ -2106,6 +2420,20 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { beginRate: 0, endRate: 0 } + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.currentTrade = { + begin: 0, + end: 0, + status: 0, + lastTradeROI: 0, + exitType: 0, + beginRate: 0, + endRate: 0 + } + } + } } } } @@ -2128,21 +2456,55 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { To do that, the condition to be met is that this execution must include all candles of the currentDay. */ - if (currentDay !== undefined) { + if (processingDailyFiles) { if (lastCandle.end === lastInstantOfTheDay) { + interExecutionMemory.previousBalanceAssetA = yesterday.previousBalanceAssetA + interExecutionMemory.previousBalanceAssetB = yesterday.previousBalanceAssetB + + interExecutionMemory.tradePositionRate = yesterday.tradePositionRate + interExecutionMemory.tradePositionSize = yesterday.tradePositionSize + + interExecutionMemory.currentStrategyIndex = yesterday.currentStrategyIndex + interExecutionMemory.strategyStage = yesterday.strategyStage + + interExecutionMemory.stopLossPhase = yesterday.stopLossPhase + interExecutionMemory.stopLossStage = yesterday.stopLossStage + + interExecutionMemory.takeProfitPhase = yesterday.takeProfitPhase + interExecutionMemory.takeProfitStage = yesterday.takeProfitStage + + interExecutionMemory.currentStrategy = { + begin: yesterday.currentStrategy.begin, + end: yesterday.currentStrategy.end, + status: yesterday.currentStrategy.status, + number: yesterday.currentStrategy.number, + beginRate: yesterday.currentStrategy.beginRate, + endRate: yesterday.currentStrategy.endRate + } + + interExecutionMemory.currentTrade = { + begin: yesterday.currentTrade.begin, + end: yesterday.currentTrade.end, + status: yesterday.currentTrade.status, + profit: yesterday.currentTrade.profit, + exitType: yesterday.currentTrade.exitType, + beginRate: yesterday.currentTrade.beginRate, + endRate: yesterday.currentTrade.endRate + } + interExecutionMemory.balanceAssetA = yesterday.balanceAssetA; interExecutionMemory.balanceAssetB = yesterday.balanceAssetB; interExecutionMemory.lastTradeProfitLoss = yesterday.lastTradeProfitLoss; interExecutionMemory.profit = yesterday.profit; interExecutionMemory.lastTradeROI = yesterday.lastTradeROI; - interExecutionMemory.roundtrips = interExecutionMemory.roundtrips + yesterday.Roundtrips; - interExecutionMemory.fails = interExecutionMemory.fails + yesterday.fails; - interExecutionMemory.hits = interExecutionMemory.hits + yesterday.hits; - interExecutionMemory.periods = interExecutionMemory.periods + yesterday.Periods; - interExecutionMemory.positionPeriods = interExecutionMemory.positionPeriods + yesterday.positionPeriods; + interExecutionMemory.roundtrips = yesterday.roundtrips; + interExecutionMemory.fails = yesterday.fails; + interExecutionMemory.hits = yesterday.hits; + interExecutionMemory.periods = yesterday.periods; + interExecutionMemory.positionPeriods = yesterday.positionPeriods; interExecutionMemory.messageId = interExecutionMemory.messageId + yesterday.messageId; interExecutionMemory.orderId = interExecutionMemory.orderId + yesterday.orderId; From d60b03296136a20dec7fb693aa0fd7658cd79c7d Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 20 Aug 2019 10:44:25 +0200 Subject: [PATCH 188/244] New File with Final Reults added at Daily --- Commons.js | 6 +- Multi-Period-Daily/User.Bot.js | 119 ++++++++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/Commons.js b/Commons.js index dd6a6a7da..0a81b6709 100644 --- a/Commons.js +++ b/Commons.js @@ -514,9 +514,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { function loop() { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Entering function."); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> i = " + i); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Processing candle # " + i); } let candle = candles[i]; + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Candle Begin @ " + (new Date(candle.begin)).toLocaleString()) } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Candle End @ " + (new Date(candle.end)).toLocaleString()) } + let percentageBandwidth = percentageBandwidthMap.get(candle.begin); let bollingerBand = bollingerBandsMap.get(candle.begin); let bollingerChannel = getElement(bollingerChannelsArray, candle.begin, candle.end); diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index 89b84fe38..d646dd02a 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -11,6 +11,8 @@ const STRATEGIES_FOLDER_NAME = "Simulation-Strategies"; const TRADES_FOLDER_NAME = "Simulation-Trades"; + const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; + const commons = COMMONS.newCommons(bot, logger, UTILITIES); thisObject = { @@ -180,7 +182,7 @@ } - writeRecordsFile(); + writeFinalResults(); } catch (err) { @@ -195,6 +197,121 @@ } } + function writeFinalResults() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFinalResults -> Entering function."); } + + if ( // We only write this file if we are at the head of the market. + Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS + !== + Math.trunc((new Date()).valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS + ) { + writeRecordsFile(); + return; + } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < recordsArray.length; i++) { + + let record = recordsArray[i]; + + /* Will only add to the file the records of the current day */ + + if (record.begin < currentDay.valueOf()) { continue; } + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.type + "," + + record.marketRate + "," + + record.amount + "," + + record.balanceA + "," + + record.balanceB + "," + + record.profit + "," + + record.lastTradeProfitLoss + "," + + record.stopLoss + "," + + record.roundtrips + "," + + record.hits + "," + + record.fails + "," + + record.hitRatio + "," + + record.ROI + "," + + record.periods + "," + + record.days + "," + + record.anualizedRateOfReturn + "," + + record.positionRate + "," + + record.lastTradeROI + "," + + record.strategy + "," + + record.strategyStageNumber + "," + + record.takeProfit + "," + + record.stopLossPhase + "," + + record.takeProfitPhase + "," + + JSON.stringify(record.executionRecord) + "," + + record.positionSize + "," + + record.initialBalanceA + "," + + record.minimumBalanceA + "," + + record.maximumBalanceA + "," + + record.initialBalanceB + "," + + record.minimumBalanceB + "," + + record.maximumBalanceB + "," + + record.baseAsset + "," + + record.positionPeriods + "," + + record.positionDays + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel; + filePath += '/' + fileName + + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFinalResults -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFinalResults -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + writeRecordsFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + function writeRecordsFile() { try { From 0d776fe75a15e84ef86f32f5e22fdd2d127761da Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 20 Aug 2019 21:54:49 +0200 Subject: [PATCH 189/244] Fixing Many problems with live execution --- Commons.js | 343 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 234 insertions(+), 109 deletions(-) diff --git a/Commons.js b/Commons.js index 0a81b6709..2fad1c1cc 100644 --- a/Commons.js +++ b/Commons.js @@ -163,6 +163,26 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } + /* Slippage */ + + let slippage = 0 + if (definition.tradingSystem !== undefined) { + if (definition.tradingSystem.parameters !== undefined) { + if (definition.tradingSystem.parameters.baseAsset !== undefined) { + if (definition.tradingSystem.parameters.baseAsset.formula !== undefined) { + if (definition.tradingSystem.parameters.baseAsset.formula.code !== undefined) { + let code = JSON.parse(definition.tradingSystem.parameters.baseAsset.formula.code) + if (code.initialDatetime !== undefined) { + slippage = code.slippage + } + } + } + } + } + } + + let timerToCloseStage = 0 + /* Stop Loss Management */ const MIN_STOP_LOSS_VALUE = 1 // We can not let the stop be zero to avoid division by 0 error or infinity numbers as a result. @@ -186,6 +206,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let type = '""'; let marketRate = 0; let takePositionNow = false + let closePositionNow = false /* In some cases we need to know if we are positioned at the last candle of the calendar day, for that we need these variables. */ @@ -531,7 +552,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let ticker - if (process.env.START_MODE === "live") { + if (process.env.START_MODE === "live" && i === candles.length - 2) { ticker = assistant.getTicker() } else { ticker = { @@ -546,27 +567,27 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* If any of the needed indicators is missing, then that period is not calculated */ if (candle.end < initialDate.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Record before the initialDate."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Candle before the initialDate."); } controlLoop(); return } if (bollingerBand === undefined) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Record because Bollinger Band is undefined."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Candle because Bollinger Band is undefined."); } controlLoop(); return } if (percentageBandwidth === undefined) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Record because %B is undefined."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Candle because %B is undefined."); } controlLoop(); return } // percentageBandwidth might start after the first few candles. if (bollingerChannel === undefined) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Record because Bollingeer Channel is undefined."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Candle because Bollingeer Channel is undefined."); } controlLoop(); return } if (bollingerSubChannel === undefined) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Record because Bollingeer Sub Channel is undefined."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Candle because Bollingeer Sub Channel is undefined."); } controlLoop(); return } @@ -586,6 +607,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (i === candles.length - 1) { if ((candles.length < candlesPerDay) || (candles.length > candlesPerDay && candles.length < candlesPerDay * 2)) { /*We are at the head of the market, thus we skip the last candle because it has not close yet. */ + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Candle because it is the last one and has not been closed yet."); } controlLoop(); return /* Note here that in the last candle of the first day or the second day it will use an incomplete candle and partially calculated indicators. @@ -595,6 +617,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } else { // We are processing Market Files if (i === candles.length - 1) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Candle because it is the last one and has not been closed yet."); } controlLoop(); return } @@ -1560,17 +1583,38 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if ((baseAsset === 'BTC' && candle.max >= stopLoss) || (baseAsset !== 'BTC' && candle.min <= stopLoss)) { - if (baseAsset === 'BTC') { - strategy.positionSize = balanceAssetB / stopLoss; - strategy.positionRate = stopLoss; + /* Check the Slipagge */ - balanceAssetA = balanceAssetA + balanceAssetB / stopLoss; + let stopLossHitPoint = stopLoss + + if (baseAsset === 'BTC') { + if (stopLossHitPoint < candle.open) { stopLossHitPoint = candle.open} + if (stopLossHitPoint < candle.close) { stopLossHitPoint = candle.close } + } else { + if (stopLossHitPoint > candle.open) { stopLossHitPoint = candle.open } + if (stopLossHitPoint > candle.close) { stopLossHitPoint = candle.close } + } + + let slippedStopLoss = stopLossHitPoint + let slippageAmount = stopLossHitPoint * slippage / 100 + + if (baseAsset === 'BTC') { + slippedStopLoss = slippedStopLoss + slippageAmount + } else { + slippedStopLoss = slippedStopLoss - slippageAmount + } + + if (baseAsset === 'BTC') { + strategy.positionSize = balanceAssetB / slippedStopLoss; + strategy.positionRate = slippedStopLoss; + + balanceAssetA = balanceAssetA + balanceAssetB / slippedStopLoss; balanceAssetB = 0; } else { - strategy.positionSize = balanceAssetA * stopLoss; - strategy.positionRate = stopLoss; + strategy.positionSize = balanceAssetA * slippedStopLoss; + strategy.positionRate = slippedStopLoss; - balanceAssetB = balanceAssetB + balanceAssetA * stopLoss; + balanceAssetB = balanceAssetB + balanceAssetA * slippedStopLoss; balanceAssetA = 0; } @@ -1581,7 +1625,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - marketRate = stopLoss; + marketRate = slippedStopLoss; type = '"Close@StopLoss"'; strategyStage = 'Close Stage'; stopLossStage = 'No Stage'; @@ -1589,12 +1633,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentTrade.end = candle.end; currentTrade.status = 1; currentTrade.exitType = 1; - currentTrade.endRate = stopLoss; + currentTrade.endRate = slippedStopLoss; - currentStrategy.number = currentStrategyIndex - currentStrategy.end = candle.end; - currentStrategy.endRate = candle.min; - currentStrategy.status = 1; + closePositionNow = true; if (processingDailyFiles) { if (positionedAtYesterday) { @@ -1605,10 +1646,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { yesterday.currentTrade.status = currentTrade.status; yesterday.currentTrade.exitType = currentTrade.exitType; yesterday.currentTrade.endRate = currentTrade.endRate; - yesterday.currentStrategy.number = currentStrategy.number; - yesterday.currentStrategy.end = currentStrategy.end; - yesterday.currentStrategy.endRate = currentStrategy.endRate; - yesterday.currentStrategy.status = currentStrategy.status; } } } @@ -1617,17 +1654,38 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if ((baseAsset === 'BTC' && candle.min <= takeProfit) || (baseAsset !== 'BTC' && candle.max >= takeProfit)) { - if (baseAsset === 'BTC') { - strategy.positionSize = balanceAssetB / takeProfit; - strategy.positionRate = takeProfit; + /* Check the Slipagge */ - balanceAssetA = balanceAssetA + balanceAssetB / takeProfit; + let takeProfitHitPoint = stopLoss + + if (baseAsset === 'BTC') { + if (takeProfitHitPoint > candle.open) { takeProfitHitPoint = candle.open } + if (takeProfitHitPoint > candle.close) { takeProfitHitPoint = candle.close } + } else { + if (takeProfitHitPoint < candle.open) { takeProfitHitPoint = candle.open } + if (takeProfitHitPoint < candle.close) { takeProfitHitPoint = candle.close } + } + + let slippedTakeProfit = takeProfit + let slippageAmount = stopLoss * slippage / 100 + + if (baseAsset === 'BTC') { + slippedTakeProfit = slippedTakeProfit - slippageAmount + } else { + slippedTakeProfit = slippedTakeProfit + slippageAmount + } + + if (baseAsset === 'BTC') { + strategy.positionSize = balanceAssetB / slippedTakeProfit; + strategy.positionRate = slippedTakeProfit; + + balanceAssetA = balanceAssetA + balanceAssetB / slippedTakeProfit; balanceAssetB = 0; } else { - strategy.positionSize = balanceAssetA * takeProfit; - strategy.positionRate = takeProfit; + strategy.positionSize = balanceAssetA * slippedTakeProfit; + strategy.positionRate = slippedTakeProfit; - balanceAssetB = balanceAssetB + balanceAssetA * takeProfit; + balanceAssetB = balanceAssetB + balanceAssetA * slippedTakeProfit; balanceAssetA = 0; } @@ -1639,7 +1697,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - marketRate = takeProfit; + marketRate = slippedTakeProfit; type = '"Close@TakeProfit"'; strategyStage = 'Close Stage'; stopLossStage = 'No Stage'; @@ -1648,12 +1706,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentTrade.end = candle.end; currentTrade.status = 1; currentTrade.exitType = 2; - currentTrade.endRate = takeProfit; + currentTrade.endRate = slippedTakeProfit; - currentStrategy.number = currentStrategyIndex - currentStrategy.end = candle.end; - currentStrategy.endRate = candle.min; - currentStrategy.status = 1; + closePositionNow = true; if (processingDailyFiles) { if (positionedAtYesterday) { @@ -1665,11 +1720,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { yesterday.currentTrade.status = currentTrade.status; yesterday.currentTrade.exitType = currentTrade.exitType; yesterday.currentTrade.endRate = currentTrade.endRate; - - yesterday.currentStrategy.number = currentStrategy.number; - yesterday.currentStrategy.end = currentStrategy.end; - yesterday.currentStrategy.endRate = currentStrategy.endRate; - yesterday.currentStrategy.status = currentStrategy.status; } } } @@ -1686,7 +1736,23 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let strategy = tradingSystem.strategies[currentStrategyIndex]; tradePositionSize = strategy.positionSize; - tradePositionRate = strategy.positionRate; + + if (i === candles.length - 2) { /* Only at the last closed candle I can take the value from the formula, since the use of ticker could alter the value at previous candles.*/ + tradePositionRate = strategy.positionRate; + } else { + + /* Check the Slipagge */ + + tradePositionRate = candle.close; + + let slippageAmount = tradePositionRate * slippage / 100 + + if (baseAsset === 'BTC') { + tradePositionRate = tradePositionRate - slippageAmount + } else { + tradePositionRate = tradePositionRate + slippageAmount + } + } if (processingDailyFiles) { if (positionedAtYesterday) { @@ -1695,46 +1761,52 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - /* Check that we are in LIVE MODE */ - if (process.env.START_MODE === "live") { - /* We see if we need to put the actual order at the exchange. */ - if (interExecutionMemory.executionContext !== undefined) { - switch (interExecutionMemory.executionContext.status) { - case "Without a Position": { // We need to put the order because It was not put yet. - if (strategy.openStage !== undefined) { - if (strategy.openStage.openExecution !== undefined) { - putOpeningOrder() - return + if (i > candles.length - 10) { /* Only at the last candles makes sense to check if we are in live mode or not.*/ + /* Check that we are in LIVE MODE */ + if (process.env.START_MODE === "live") { + /* We see if we need to put the actual order at the exchange. */ + if (interExecutionMemory.executionContext !== undefined) { + switch (interExecutionMemory.executionContext.status) { + case "Without a Position": { // We need to put the order because It was not put yet. + if (strategy.openStage !== undefined) { + if (strategy.openStage.openExecution !== undefined) { + putOpeningOrder() + return + } } + break } - break - } - case "Position Closed": { // Waiting for a confirmation that the position was closed. - if (strategy.openStage !== undefined) { - if (strategy.openStage.openExecution !== undefined) { - putOpeningOrder() - return + case "Position Closed": { // Waiting for a confirmation that the position was closed. + if (strategy.openStage !== undefined) { + if (strategy.openStage.openExecution !== undefined) { + putOpeningOrder() + return + } } + break + } + case "Taking Position": { // Waiting for a confirmation that the position was taken. + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionNow -> Exiting code block because status is Taking Position."); } + break + } + case "In a Position": { // This should mean that we already put the order at the exchange. + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionNow -> Exiting code block because status is In a Position."); } + break } - break } - case "Taking Position": { // Waiting for a confirmation that the position was taken. - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionNow -> Exiting code block because status is Taking Position."); } - break - } - case "In a Position": { // This should mean that we already put the order at the exchange. - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionNow -> Exiting code block because status is In a Position."); } - break - } - } - } else { // The context does not exist so it means we are not in a position. - if (strategy.openStage !== undefined) { - if (strategy.openStage.openExecution !== undefined) { - putOpeningOrder() - return + } else { // The context does not exist so it means we are not in a position. + if (strategy.openStage !== undefined) { + if (strategy.openStage.openExecution !== undefined) { + putOpeningOrder() + return + } } } + } else { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionNow -> Not trading live."); } } + } else { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionNow -> Not the last closed candle."); } } takePositionAtSimulation() @@ -1801,25 +1873,35 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let amountA let amountB let positionDirection + let availableBalance = assistant.getAvailableBalance() if (baseAsset === 'BTC') { positionDirection = "sell" - openPositionRate = tradePositionRate + openPositionRate = tradePositionRate - 100 // 100 is Provisional since we do have management of orders yet amountA = tradePositionSize * openPositionRate amountB = tradePositionSize + + if (amountB > availableBalance.assetB) { // The assistant know what fees were paid. + amountB = availableBalance.assetB + } } else { positionDirection = "buy" - openPositionRate = tradePositionRate + openPositionRate = tradePositionRate + 100 // 100 is Provisional since we do have management of orders yet amountA = tradePositionSize amountB = tradePositionSize / openPositionRate + + if (amountA > availableBalance.assetA) { // The assistant know what fees were paid. + amountA = availableBalance.assetA + } } interExecutionMemory.executionContext = { - status: "Taking Position" + status: "Taking Position", + periods: periods, } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Ready to put order."); } @@ -1915,48 +1997,53 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - /* Closing a Position */ - if (strategyStage === 'Close Stage') { + if (closePositionNow === true) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing a Position -> Entering code block."); } + closePositionNow = false + /* Position size and rate */ let strategy = tradingSystem.strategies[currentStrategyIndex]; - /* Check that we are in LIVE MODE */ - if (process.env.START_MODE === "live") { - /* We see if we need to put the actual order at the exchange. */ - if (interExecutionMemory.executionContext !== undefined) { - switch (interExecutionMemory.executionContext.status) { - case "Without a Position": { // No way to close anything at the exchange. - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing a Position -> Exiting code block because status is Without a Position."); } - break - } - case "In a Position": { // This should mean that we already put the order at the exchange. - if (strategy.closeStage !== undefined) { - if (strategy.closeStage.closeExecution !== undefined) { - putClosingOrder() - return - } + if (i > candles.length - 10) { /* Only at the last candles makes sense to check if we are in live mode or not.*/ + /* Check that we are in LIVE MODE */ + if (process.env.START_MODE === "live") { + /* We see if we need to put the actual order at the exchange. */ + if (interExecutionMemory.executionContext !== undefined) { + switch (interExecutionMemory.executionContext.status) { + case "Without a Position": { // No way to close anything at the exchange. + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing a Position -> Exiting code block because status is Without a Position."); } + break } - break - } - case "Closing Position": { // Waiting for a confirmation that the position was taken. - if (strategy.closeStage !== undefined) { - if (strategy.closeStage.closeExecution !== undefined) { - putClosingOrder() - return + case "In a Position": { // This should mean that we already put the order at the exchange. + if (strategy.closeStage !== undefined) { + if (strategy.closeStage.closeExecution !== undefined) { + putClosingOrder() + return + } } + break + } + case "Closing Position": { // Waiting for a confirmation that the position was taken. + if (strategy.closeStage !== undefined) { + if (strategy.closeStage.closeExecution !== undefined) { + putClosingOrder() + return + } + } + break } - break - } - case "Position Closed": { // - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing a Position -> Exiting code block because status is Position Closed."); } - break + case "Position Closed": { // + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing a Position -> Exiting code block because status is Position Closed."); } + break + } } } } + } else { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing a Position -> Not within the last 10 candles."); } } closePositionAtSimulation() @@ -1993,6 +2080,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let amountA let amountB let positionDirection + let availableBalance = assistant.getAvailableBalance() if (baseAsset === 'BTC') { positionDirection = "buy" @@ -2001,6 +2089,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { amountA = interExecutionMemory.executionContext.amountA amountB = interExecutionMemory.executionContext.amountA / closePositionRate + + if (amountA > availableBalance.assetA) { // The assistant know what fees were paid. + amountA = availableBalance.assetA + } } else { positionDirection = "sell" @@ -2008,10 +2100,15 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { amountA = interExecutionMemory.executionContext.amountB * closePositionRate amountB = interExecutionMemory.executionContext.amountB + + if (amountB > availableBalance.assetB) { // The assistant know what fees were paid. + amountB = availableBalance.assetB + } } interExecutionMemory.executionContext = { - status: "Closing Position" + status: "Closing Position", + periods: periods, } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putClosingOrder -> About to close position at the exchange."); } @@ -2152,8 +2249,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - currentStrategyIndex = -1; - strategyStage = 'No Stage'; + timerToCloseStage = candle.begin stopLossStage = 'No Stage'; takeProfitStage = 'No Stage'; stopLossPhase = 0; @@ -2176,6 +2272,35 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } + /* Closing the Closing Stage */ + if (strategyStage === 'Close Stage') { + if (candle.begin - 5 * 60 * 1000 > timerToCloseStage) { + + currentStrategy.number = currentStrategyIndex + currentStrategy.end = candle.end; + currentStrategy.endRate = candle.min; + currentStrategy.status = 1; + + if (processingDailyFiles) { + if (positionedAtYesterday) { + + yesterday.currentStrategy.number = currentStrategy.number; + yesterday.currentStrategy.end = currentStrategy.end; + yesterday.currentStrategy.endRate = currentStrategy.endRate; + yesterday.currentStrategy.status = currentStrategy.status; + } + } + + currentStrategyIndex = -1; + strategyStage = 'No Stage'; + timerToCloseStage = 0 + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing the Closing Stage -> Exiting Close Stage."); } + } else { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing the Closing Stage -> Waiting for timer."); } + } + } + /* Not a buy or sell condition */ marketRate = candle.close; From 6cb83b664fc222a242da78d5fa3fc325204caf26 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 21 Aug 2019 11:23:48 +0200 Subject: [PATCH 190/244] Bug Fix --- Commons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index 2fad1c1cc..722b4990b 100644 --- a/Commons.js +++ b/Commons.js @@ -172,7 +172,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (definition.tradingSystem.parameters.baseAsset.formula !== undefined) { if (definition.tradingSystem.parameters.baseAsset.formula.code !== undefined) { let code = JSON.parse(definition.tradingSystem.parameters.baseAsset.formula.code) - if (code.initialDatetime !== undefined) { + if (code.slippage !== undefined) { slippage = code.slippage } } From 1b09f2af24e118e12b4d736bcdd86f3962b9dee5 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 22 Aug 2019 20:27:19 +0200 Subject: [PATCH 191/244] Slippage implementation --- Commons.js | 155 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 87 insertions(+), 68 deletions(-) diff --git a/Commons.js b/Commons.js index 722b4990b..87f553b61 100644 --- a/Commons.js +++ b/Commons.js @@ -164,16 +164,31 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } /* Slippage */ - - let slippage = 0 + let slippage = { // Default Values + positionRate: 0, + stopLoss: 0, + takeProfit: 0 + } if (definition.tradingSystem !== undefined) { if (definition.tradingSystem.parameters !== undefined) { if (definition.tradingSystem.parameters.baseAsset !== undefined) { if (definition.tradingSystem.parameters.baseAsset.formula !== undefined) { if (definition.tradingSystem.parameters.baseAsset.formula.code !== undefined) { - let code = JSON.parse(definition.tradingSystem.parameters.baseAsset.formula.code) - if (code.slippage !== undefined) { - slippage = code.slippage + try { + let code = JSON.parse(definition.tradingSystem.parameters.baseAsset.formula.code) + if (code.slippage !== undefined) { + if (code.slippage.positionRate !== undefined) { + slippage.positionRate = code.slippage.positionRate + } + if (code.slippage.stopLoss !== undefined) { + slippage.stopLoss = code.slippage.stopLoss + } + if (code.slippage.takeProfit !== undefined) { + slippage.takeProfit = code.slippage.takeProfit + } + } + } catch (err) { + tradingSystem.parameters.baseAsset.formula.error = "Slippage Error: " + err.message } } } @@ -550,16 +565,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { /* Assistant Info */ - let ticker - - if (process.env.START_MODE === "live" && i === candles.length - 2) { - ticker = assistant.getTicker() - } else { - ticker = { - bid: candle.close, - ask: candle.close, - last: candle.close - } + let ticker = { + bid: candle.close, + ask: candle.close, + last: candle.close } //let LRC = LRCMap.get(candle.begin); @@ -1280,8 +1289,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { takeProfitStage = 'Open Stage'; stopLossPhase = 1; takeProfitPhase = 1; - currentTrade.begin = candle.begin; - currentTrade.beginRate = strategy.positionRate; if (processingDailyFiles) { if (positionedAtYesterday) { @@ -1290,8 +1297,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { yesterday.takeProfitStage = takeProfitStage; yesterday.stopLossPhase = stopLossPhase; yesterday.takeProfitPhase = takeProfitPhase; - yesterday.currentTrade.begin = currentTrade.begin; - yesterday.currentTrade.beginRate = currentTrade.beginRate; } } @@ -1583,20 +1588,23 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if ((baseAsset === 'BTC' && candle.max >= stopLoss) || (baseAsset !== 'BTC' && candle.min <= stopLoss)) { - /* Check the Slipagge */ + /* + Hit Point Validation - let stopLossHitPoint = stopLoss + This prevents misscalculations when a formula places the stop loss in this case way beyond the market price. + If we take the stop loss value at those situation would be a huge distortion of facts. + */ if (baseAsset === 'BTC') { - if (stopLossHitPoint < candle.open) { stopLossHitPoint = candle.open} - if (stopLossHitPoint < candle.close) { stopLossHitPoint = candle.close } + if (stopLoss < candle.min) { stopLoss = candle.min } } else { - if (stopLossHitPoint > candle.open) { stopLossHitPoint = candle.open } - if (stopLossHitPoint > candle.close) { stopLossHitPoint = candle.close } + if (stopLoss > candle.max) { stopLoss = candle.max } } - let slippedStopLoss = stopLossHitPoint - let slippageAmount = stopLossHitPoint * slippage / 100 + let slippedStopLoss = stopLoss + + /* Apply the Slippage */ + let slippageAmount = slippedStopLoss * slippage.stopLoss / 100 if (baseAsset === 'BTC') { slippedStopLoss = slippedStopLoss + slippageAmount @@ -1604,17 +1612,19 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { slippedStopLoss = slippedStopLoss - slippageAmount } - if (baseAsset === 'BTC') { - strategy.positionSize = balanceAssetB / slippedStopLoss; - strategy.positionRate = slippedStopLoss; + let finalStopLoss = slippedStopLoss; - balanceAssetA = balanceAssetA + balanceAssetB / slippedStopLoss; + if (baseAsset === 'BTC') { + strategy.positionSize = balanceAssetB / finalStopLoss; + strategy.positionRate = finalStopLoss; + + balanceAssetA = balanceAssetA + balanceAssetB / finalStopLoss; balanceAssetB = 0; } else { - strategy.positionSize = balanceAssetA * slippedStopLoss; - strategy.positionRate = slippedStopLoss; + strategy.positionSize = balanceAssetA * finalStopLoss; + strategy.positionRate = finalStopLoss; - balanceAssetB = balanceAssetB + balanceAssetA * slippedStopLoss; + balanceAssetB = balanceAssetB + balanceAssetA * finalStopLoss; balanceAssetA = 0; } @@ -1625,7 +1635,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - marketRate = slippedStopLoss; + marketRate = finalStopLoss; type = '"Close@StopLoss"'; strategyStage = 'Close Stage'; stopLossStage = 'No Stage'; @@ -1633,8 +1643,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentTrade.end = candle.end; currentTrade.status = 1; currentTrade.exitType = 1; - currentTrade.endRate = slippedStopLoss; - + currentTrade.endRate = finalStopLoss; + closePositionNow = true; if (processingDailyFiles) { @@ -1654,20 +1664,22 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if ((baseAsset === 'BTC' && candle.min <= takeProfit) || (baseAsset !== 'BTC' && candle.max >= takeProfit)) { - /* Check the Slipagge */ + /* + Hit Point Validation: - let takeProfitHitPoint = stopLoss + This prevents misscalculations when a formula places the take profit in this case way beyond the market price. + If we take the stop loss value at those situation would be a huge distortion of facts. + */ if (baseAsset === 'BTC') { - if (takeProfitHitPoint > candle.open) { takeProfitHitPoint = candle.open } - if (takeProfitHitPoint > candle.close) { takeProfitHitPoint = candle.close } + if (takeProfit > candle.max) { takeProfit = candle.max } } else { - if (takeProfitHitPoint < candle.open) { takeProfitHitPoint = candle.open } - if (takeProfitHitPoint < candle.close) { takeProfitHitPoint = candle.close } + if (takeProfit < candle.min) { takeProfit = candle.min } } let slippedTakeProfit = takeProfit - let slippageAmount = stopLoss * slippage / 100 + /* Apply the Slippage */ + let slippageAmount = slippedTakeProfit * slippage.takeProfit / 100 if (baseAsset === 'BTC') { slippedTakeProfit = slippedTakeProfit - slippageAmount @@ -1675,17 +1687,19 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { slippedTakeProfit = slippedTakeProfit + slippageAmount } - if (baseAsset === 'BTC') { - strategy.positionSize = balanceAssetB / slippedTakeProfit; - strategy.positionRate = slippedTakeProfit; + let finalTakeProfit = slippedTakeProfit; - balanceAssetA = balanceAssetA + balanceAssetB / slippedTakeProfit; + if (baseAsset === 'BTC') { + strategy.positionSize = balanceAssetB / finalTakeProfit; + strategy.positionRate = finalTakeProfit; + + balanceAssetA = balanceAssetA + balanceAssetB / finalTakeProfit; balanceAssetB = 0; } else { - strategy.positionSize = balanceAssetA * slippedTakeProfit; - strategy.positionRate = slippedTakeProfit; + strategy.positionSize = balanceAssetA * finalTakeProfit; + strategy.positionRate = finalTakeProfit; - balanceAssetB = balanceAssetB + balanceAssetA * slippedTakeProfit; + balanceAssetB = balanceAssetB + balanceAssetA * finalTakeProfit; balanceAssetA = 0; } @@ -1697,7 +1711,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } - marketRate = slippedTakeProfit; + marketRate = finalTakeProfit; type = '"Close@TakeProfit"'; strategyStage = 'Close Stage'; stopLossStage = 'No Stage'; @@ -1706,8 +1720,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentTrade.end = candle.end; currentTrade.status = 1; currentTrade.exitType = 2; - currentTrade.endRate = slippedTakeProfit; - + currentTrade.endRate = finalTakeProfit; + closePositionNow = true; if (processingDailyFiles) { @@ -1736,22 +1750,15 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let strategy = tradingSystem.strategies[currentStrategyIndex]; tradePositionSize = strategy.positionSize; + tradePositionRate = strategy.positionRate; - if (i === candles.length - 2) { /* Only at the last closed candle I can take the value from the formula, since the use of ticker could alter the value at previous candles.*/ - tradePositionRate = strategy.positionRate; + /* We take what was calculated at the formula and apply the slippage. */ + let slippageAmount = tradePositionRate * slippage.positionRate / 100 + + if (baseAsset === 'BTC') { + tradePositionRate = tradePositionRate - slippageAmount } else { - - /* Check the Slipagge */ - - tradePositionRate = candle.close; - - let slippageAmount = tradePositionRate * slippage / 100 - - if (baseAsset === 'BTC') { - tradePositionRate = tradePositionRate - slippageAmount - } else { - tradePositionRate = tradePositionRate + slippageAmount - } + tradePositionRate = tradePositionRate + slippageAmount } if (processingDailyFiles) { @@ -1761,6 +1768,18 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } + /* Update the trade record information. */ + currentTrade.begin = candle.begin; + currentTrade.beginRate = tradePositionRate; + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.currentTrade.begin = currentTrade.begin; + yesterday.currentTrade.beginRate = currentTrade.beginRate; + } + } + + /* Check if we need to execute. */ if (i > candles.length - 10) { /* Only at the last candles makes sense to check if we are in live mode or not.*/ /* Check that we are in LIVE MODE */ if (process.env.START_MODE === "live") { From b35e78d74791b5725bd4d0babe1ffb7fa3d6d015 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 23 Aug 2019 08:42:07 +0200 Subject: [PATCH 192/244] Bug Fixes: slippage at take profit and strategies at yesterday --- Commons.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Commons.js b/Commons.js index 87f553b61..50cf1e38a 100644 --- a/Commons.js +++ b/Commons.js @@ -1682,9 +1682,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let slippageAmount = slippedTakeProfit * slippage.takeProfit / 100 if (baseAsset === 'BTC') { - slippedTakeProfit = slippedTakeProfit - slippageAmount - } else { slippedTakeProfit = slippedTakeProfit + slippageAmount + } else { + slippedTakeProfit = slippedTakeProfit - slippageAmount } let finalTakeProfit = slippedTakeProfit; @@ -2276,8 +2276,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (processingDailyFiles) { if (positionedAtYesterday) { - yesterday.currentStrategyIndex = currentStrategyIndex; - yesterday.strategyStage = strategyStage; yesterday.stopLossStage = stopLossStage; yesterday.takeProfitStage = takeProfitStage; yesterday.stopLossPhase = stopLossPhase; @@ -2312,6 +2310,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { currentStrategyIndex = -1; strategyStage = 'No Stage'; + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.currentStrategyIndex = currentStrategyIndex; + yesterday.strategyStage = strategyStage; + } + } + timerToCloseStage = 0 if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing the Closing Stage -> Exiting Close Stage."); } @@ -2525,6 +2531,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategiesArray.push(currentStrategy); + if (currentStrategy.begin < currentStrategy.end) { + console.log("ES MENOR:" + i) + } else { + console.log("ES MAYOR:" + i) + } + currentStrategy = { begin: 0, end: 0, From dbfe48bf1bf389686f8e545d975b483013ec412e Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 23 Aug 2019 18:13:24 +0200 Subject: [PATCH 193/244] feeStructure implementation --- Commons.js | 62 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/Commons.js b/Commons.js index 50cf1e38a..32212af1e 100644 --- a/Commons.js +++ b/Commons.js @@ -196,6 +196,36 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } } + /* Fee Structure */ + let feeStructure = { // Default Values + maker: 0, + taker: 0 + } + + if (definition.tradingSystem !== undefined) { + if (definition.tradingSystem.parameters !== undefined) { + if (definition.tradingSystem.parameters.baseAsset !== undefined) { + if (definition.tradingSystem.parameters.baseAsset.formula !== undefined) { + if (definition.tradingSystem.parameters.baseAsset.formula.code !== undefined) { + try { + let code = JSON.parse(definition.tradingSystem.parameters.baseAsset.formula.code) + if (code.feeStructure !== undefined) { + if (code.feeStructure.maker !== undefined) { + feeStructure.maker = code.feeStructure.maker + } + if (code.feeStructure.taker !== undefined) { + feeStructure.taker = code.feeStructure.taker + } + } + } catch (err) { + tradingSystem.parameters.baseAsset.formula.error = "Fee Structure Error: " + err.message + } + } + } + } + } + } + let timerToCloseStage = 0 /* Stop Loss Management */ @@ -1614,17 +1644,23 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let finalStopLoss = slippedStopLoss; + let feePaid = 0 + if (baseAsset === 'BTC') { strategy.positionSize = balanceAssetB / finalStopLoss; strategy.positionRate = finalStopLoss; - balanceAssetA = balanceAssetA + balanceAssetB / finalStopLoss; + feePaid = balanceAssetB / finalStopLoss * feeStructure.taker / 100 + + balanceAssetA = balanceAssetA + balanceAssetB / finalStopLoss - feePaid; balanceAssetB = 0; } else { strategy.positionSize = balanceAssetA * finalStopLoss; strategy.positionRate = finalStopLoss; - balanceAssetB = balanceAssetB + balanceAssetA * finalStopLoss; + feePaid = balanceAssetA * finalStopLoss * feeStructure.taker / 100 + + balanceAssetB = balanceAssetB + balanceAssetA * finalStopLoss - feePaid; balanceAssetA = 0; } @@ -1689,17 +1725,23 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let finalTakeProfit = slippedTakeProfit; + let feePaid = 0 + if (baseAsset === 'BTC') { strategy.positionSize = balanceAssetB / finalTakeProfit; strategy.positionRate = finalTakeProfit; - balanceAssetA = balanceAssetA + balanceAssetB / finalTakeProfit; + feePaid = balanceAssetB / finalTakeProfit * feeStructure.taker / 100 + + balanceAssetA = balanceAssetA + balanceAssetB / finalTakeProfit - feePaid; balanceAssetB = 0; } else { strategy.positionSize = balanceAssetA * finalTakeProfit; strategy.positionRate = finalTakeProfit; - balanceAssetB = balanceAssetB + balanceAssetA * finalTakeProfit; + feePaid = balanceAssetA * finalTakeProfit * feeStructure.taker / 100 + + balanceAssetB = balanceAssetB + balanceAssetA * finalTakeProfit - feePaid; balanceAssetA = 0; } @@ -1991,11 +2033,19 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { lastTradeProfitLoss = 0; lastTradeROI = 0; + let feePaid = 0 + if (baseAsset === 'BTC') { - balanceAssetB = balanceAssetB + tradePositionSize * tradePositionRate; + + feePaid = tradePositionSize * tradePositionRate * feeStructure.taker / 100 + + balanceAssetB = balanceAssetB + tradePositionSize * tradePositionRate - feePaid; balanceAssetA = balanceAssetA - tradePositionSize; } else { - balanceAssetA = balanceAssetA + tradePositionSize / tradePositionRate; + + feePaid = tradePositionSize / tradePositionRate * feeStructure.taker / 100 + + balanceAssetA = balanceAssetA + tradePositionSize / tradePositionRate - feePaid; balanceAssetB = balanceAssetB - tradePositionSize; } From 772da41dff726d0491da40677b3191fc3ff9b723 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 24 Aug 2019 14:53:23 +0200 Subject: [PATCH 194/244] Parameters splitted in 4 pieces --- Commons.js | 84 +++++++++++++-------------------- Multi-Period-Daily/User.Bot.js | 3 +- Multi-Period-Market/User.Bot.js | 3 +- 3 files changed, 35 insertions(+), 55 deletions(-) diff --git a/Commons.js b/Commons.js index 32212af1e..2e6c26b92 100644 --- a/Commons.js +++ b/Commons.js @@ -171,25 +171,23 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } if (definition.tradingSystem !== undefined) { if (definition.tradingSystem.parameters !== undefined) { - if (definition.tradingSystem.parameters.baseAsset !== undefined) { - if (definition.tradingSystem.parameters.baseAsset.formula !== undefined) { - if (definition.tradingSystem.parameters.baseAsset.formula.code !== undefined) { - try { - let code = JSON.parse(definition.tradingSystem.parameters.baseAsset.formula.code) - if (code.slippage !== undefined) { - if (code.slippage.positionRate !== undefined) { - slippage.positionRate = code.slippage.positionRate - } - if (code.slippage.stopLoss !== undefined) { - slippage.stopLoss = code.slippage.stopLoss - } - if (code.slippage.takeProfit !== undefined) { - slippage.takeProfit = code.slippage.takeProfit - } - } - } catch (err) { - tradingSystem.parameters.baseAsset.formula.error = "Slippage Error: " + err.message + if (definition.tradingSystem.parameters.slippage !== undefined) { + if (definition.tradingSystem.parameters.slippage.code !== undefined) { + try { + let code = JSON.parse(definition.tradingSystem.parameters.slippage.code) + + if (code.positionRate !== undefined) { + slippage.positionRate = code.positionRate } + if (code.stopLoss !== undefined) { + slippage.stopLoss = code.stopLoss + } + if (code.takeProfit !== undefined) { + slippage.takeProfit = code.takeProfit + } + + } catch (err) { + tradingSystem.parameters.slippage.error = err.message } } } @@ -204,22 +202,20 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { if (definition.tradingSystem !== undefined) { if (definition.tradingSystem.parameters !== undefined) { - if (definition.tradingSystem.parameters.baseAsset !== undefined) { - if (definition.tradingSystem.parameters.baseAsset.formula !== undefined) { - if (definition.tradingSystem.parameters.baseAsset.formula.code !== undefined) { - try { - let code = JSON.parse(definition.tradingSystem.parameters.baseAsset.formula.code) - if (code.feeStructure !== undefined) { - if (code.feeStructure.maker !== undefined) { - feeStructure.maker = code.feeStructure.maker - } - if (code.feeStructure.taker !== undefined) { - feeStructure.taker = code.feeStructure.taker - } - } - } catch (err) { - tradingSystem.parameters.baseAsset.formula.error = "Fee Structure Error: " + err.message + if (definition.tradingSystem.parameters.feeStructure !== undefined) { + if (definition.tradingSystem.parameters.feeStructure.code !== undefined) { + try { + let code = JSON.parse(definition.tradingSystem.parameters.feeStructure.code) + + if (code.maker !== undefined) { + feeStructure.maker = code.maker } + if (code.taker !== undefined) { + feeStructure.taker = code.taker + } + + } catch (err) { + tradingSystem.parameters.feeStructure.error = err.message } } } @@ -2156,23 +2152,17 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { closePositionRate = ticker.last + 100; // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. - amountA = interExecutionMemory.executionContext.amountA - amountB = interExecutionMemory.executionContext.amountA / closePositionRate + amountA = availableBalance.assetA + amountB = availableBalance.assetA / closePositionRate - if (amountA > availableBalance.assetA) { // The assistant know what fees were paid. - amountA = availableBalance.assetA - } } else { positionDirection = "sell" closePositionRate = ticker.last - 100; // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. - amountA = interExecutionMemory.executionContext.amountB * closePositionRate - amountB = interExecutionMemory.executionContext.amountB + amountA = availableBalance.assetB * closePositionRate + amountB = availableBalance.assetB - if (amountB > availableBalance.assetB) { // The assistant know what fees were paid. - amountB = availableBalance.assetB - } } interExecutionMemory.executionContext = { @@ -2257,12 +2247,10 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { } currentTrade.lastTradeROI = lastTradeROI; - currentTrade.stopRate = stopLoss; if (processingDailyFiles) { if (positionedAtYesterday) { yesterday.currentTrade.lastTradeROI = currentTrade.lastTradeROI; - yesterday.currentTrade.stopRate = currentTrade.stopRate; } } @@ -2581,12 +2569,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { strategiesArray.push(currentStrategy); - if (currentStrategy.begin < currentStrategy.end) { - console.log("ES MENOR:" + i) - } else { - console.log("ES MAYOR:" + i) - } - currentStrategy = { begin: 0, end: 0, diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js index d646dd02a..88ddebd50 100644 --- a/Multi-Period-Daily/User.Bot.js +++ b/Multi-Period-Daily/User.Bot.js @@ -612,8 +612,7 @@ record.lastTradeROI + "," + record.beginRate + "," + record.endRate + "," + - record.exitType + "," + - record.stopRate + "]"; + record.exitType + "]"; if (separator === "") { separator = ","; } diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 5b8d6ca62..179343e43 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -464,8 +464,7 @@ record.lastTradeROI + "," + record.beginRate + "," + record.endRate + "," + - record.exitType + "," + - record.stopRate + "]"; + record.exitType + "]"; if (separator === "") { separator = ","; } From 388f3b53b017ab112a43610c6d609e65c32cadae Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 24 Aug 2019 17:24:18 +0200 Subject: [PATCH 195/244] Removing Execution Record --- Commons.js | 106 ++--------------------------------------------------- 1 file changed, 3 insertions(+), 103 deletions(-) diff --git a/Commons.js b/Commons.js index 2e6c26b92..c61f32a43 100644 --- a/Commons.js +++ b/Commons.js @@ -1,14 +1,4 @@ -const strategy = require('./Integrations/Strategy') - -exports.newCommons = function newCommons(bot, logger, UTILITIES) { - - const { orderMessage } = require("@superalgos/mqservice") - - const { - MESSAGE_ENTITY, MESSAGE_TYPE, ORDER_CREATOR, ORDER_TYPE, - ORDER_OWNER, ORDER_DIRECTION, ORDER_STATUS, ORDER_EXIT_OUTCOME, - createMessage, getMessage, getExpandedMessage - } = orderMessage.newOrderMessage() +exports.newCommons = function newCommons(bot, logger, UTILITIES) { const FULL_LOG = true; const LOG_FILE_CONTENT = false; @@ -37,6 +27,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let bollingerSubChannelsArray = []; let candles = []; + const definition = global.DEFINITION return thisObject; @@ -74,7 +65,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let tradesArray = []; let lastObjectsArray = []; - let definition = await strategy.getStrategy(); let tradingSystem = definition.tradingSystem; /* Initial Default Values */ @@ -2380,96 +2370,6 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { let message; let simulationRecord; let executionRecord; - let executionMessage; - - messageId++; - - if (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage' || type === '"Close@TakeProfit"' || type === '"Close@StopLoss"') { - - if (type === '"Take Position"') { - messageType = MESSAGE_TYPE.Order; - orderId++; - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> addRecord -> Taking Position Now. "); } - - } else { - if (type === '"Close@TakeProfit"' || type === '"Close@StopLoss"') { - messageType = MESSAGE_TYPE.OrderClose; - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> addRecord -> Closing Position Now. "); } - - } else { - messageType = MESSAGE_TYPE.OrderUpdate; - } - } - - let exitOutcome = "" - if (messageType === MESSAGE_TYPE.OrderClose && type === '"Close@TakeProfit"') { - exitOutcome = "TP" - } - if (messageType === MESSAGE_TYPE.OrderClose && type === '"Close@StopLoss"') { - exitOutcome = "SL" - } - - executionMessage = createMessage( - messageId, - MESSAGE_ENTITY.SimulationEngine, - MESSAGE_ENTITY.SimulationExecutor, - messageType, - (new Date()).valueOf(), - orderId.toString(), - ORDER_CREATOR.SimulationEngine, - (new Date()).valueOf(), - ORDER_OWNER.User, - global.EXCHANGE_NAME, - "BTC_USDT", - 0, - ORDER_TYPE.Limit, - tradePositionRate, - stopLoss, - takeProfit, - ORDER_DIRECTION.Sell, - -1, - ORDER_STATUS.Signaled, - 0, - exitOutcome, - "") - - } - else { - - executionMessage = createMessage( - messageId, - MESSAGE_ENTITY.SimulationEngine, - MESSAGE_ENTITY.SimulationExecutor, - MESSAGE_TYPE.HeartBeat, - (new Date()).valueOf(), - "", - "", - 0, - "", - "", - "", - 0, - "", - 0, - 0, - 0, - "", - 0, - "", - 0, - "", - "") - } - - executionRecord = { - begin: candle.begin, - end: candle.end, - executionRecord: executionMessage - } - - executionArray.push(executionRecord) let strategyStageNumber switch (strategyStage) { @@ -2531,7 +2431,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) { takeProfit: takeProfit, stopLossPhase: stopLossPhase, takeProfitPhase: takeProfitPhase, - executionRecord: executionMessage, + executionRecord: '', positionSize: tradePositionSize, initialBalanceA: initialBalanceA, minimumBalanceA: minimumBalanceA, From a9c1f270d9b96be27aa83b8c8ba70f94ea5f32c1 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 24 Aug 2019 18:57:15 +0200 Subject: [PATCH 196/244] Bug Fix, removing Formula from base asset --- Commons.js | 113 ++++++++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 57 deletions(-) diff --git a/Commons.js b/Commons.js index c61f32a43..0678ae4ba 100644 --- a/Commons.js +++ b/Commons.js @@ -88,67 +88,66 @@ if (tradingSystem.parameters !== undefined) { if (tradingSystem.parameters.baseAsset !== undefined) { - if (tradingSystem.parameters.baseAsset.formula !== undefined) { - let receivedParameters - try { - receivedParameters = JSON.parse(tradingSystem.parameters.baseAsset.formula.code); - if (receivedParameters.name !== undefined) { - baseAsset = receivedParameters.name; - if (baseAsset !== 'BTC' && baseAsset !== 'USDT') { - tradingSystem.parameters.baseAsset.formula.error = baseAsset + ' is not supported. Using default: BTC.' - baseAsset = 'BTC' - } - } + let code + try { + code = JSON.parse(tradingSystem.parameters.baseAsset.code); - if (baseAsset === 'BTC') { - if (receivedParameters.initialBalance !== undefined) { - initialBalanceA = receivedParameters.initialBalance; - initialBalanceB = 0 - } else { - initialBalanceA = DEFAULT_BASE_ASSET_BALANCE; - initialBalanceB = 0 - } - if (receivedParameters.minimumBalance !== undefined) { - minimumBalanceA = receivedParameters.minimumBalance; - minimumBalanceB = 0 - } else { - minimumBalanceA = DEFAULT_BASE_ASSET_MINIMUN_BALANCE; - minimumBalanceB = 0 - } - if (receivedParameters.maximumBalance !== undefined) { - maximumBalanceA = receivedParameters.maximumBalance; - maximumBalanceB = 0 - } else { - maximumBalanceA = DEFAULT_BASE_ASSET_MAXIMUN_BALANCE; - maximumBalanceB = 0 - } - } else { - if (receivedParameters.initialBalance !== undefined) { - initialBalanceB = receivedParameters.initialBalance; - initialBalanceA = 0 - } else { - initialBalanceB = DEFAULT_BASE_ASSET_BALANCE; - initialBalanceA = 0 - } - if (receivedParameters.minimumBalance !== undefined) { - minimumBalanceB = receivedParameters.minimumBalance; - minimumBalanceA = 0 - } else { - minimumBalanceB = DEFAULT_BASE_ASSET_MINIMUN_BALANCE; - minimumBalanceA = 0 - } - if (receivedParameters.maximumBalance !== undefined) { - maximumBalanceB = receivedParameters.maximumBalance; - maximumBalanceA = 0 - } else { - maximumBalanceB = DEFAULT_BASE_ASSET_MAXIMUN_BALANCE; - maximumBalanceA = 0 - } + if (code.name !== undefined) { + baseAsset = code.name; + if (baseAsset !== 'BTC' && baseAsset !== 'USDT') { + tradingSystem.parameters.baseAsset.error = baseAsset + ' is not supported. Using default: BTC.' + baseAsset = 'BTC' } - } catch (err) { - tradingSystem.parameters.baseAsset.formula.error = err.message } + + if (baseAsset === 'BTC') { + if (code.initialBalance !== undefined) { + initialBalanceA = code.initialBalance; + initialBalanceB = 0 + } else { + initialBalanceA = DEFAULT_BASE_ASSET_BALANCE; + initialBalanceB = 0 + } + if (code.minimumBalance !== undefined) { + minimumBalanceA = code.minimumBalance; + minimumBalanceB = 0 + } else { + minimumBalanceA = DEFAULT_BASE_ASSET_MINIMUN_BALANCE; + minimumBalanceB = 0 + } + if (code.maximumBalance !== undefined) { + maximumBalanceA = code.maximumBalance; + maximumBalanceB = 0 + } else { + maximumBalanceA = DEFAULT_BASE_ASSET_MAXIMUN_BALANCE; + maximumBalanceB = 0 + } + } else { + if (code.initialBalance !== undefined) { + initialBalanceB = code.initialBalance; + initialBalanceA = 0 + } else { + initialBalanceB = DEFAULT_BASE_ASSET_BALANCE; + initialBalanceA = 0 + } + if (code.minimumBalance !== undefined) { + minimumBalanceB = code.minimumBalance; + minimumBalanceA = 0 + } else { + minimumBalanceB = DEFAULT_BASE_ASSET_MINIMUN_BALANCE; + minimumBalanceA = 0 + } + if (code.maximumBalance !== undefined) { + maximumBalanceB = code.maximumBalance; + maximumBalanceA = 0 + } else { + maximumBalanceB = DEFAULT_BASE_ASSET_MAXIMUN_BALANCE; + maximumBalanceA = 0 + } + } + } catch (err) { + tradingSystem.parameters.baseAsset.error = err.message } } } From 51f0ed6e7cd553287f06135c7e27fc66e0029fcb Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 25 Aug 2019 09:20:26 +0200 Subject: [PATCH 197/244] Fixing Missing 40 min --- this.bot.config.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/this.bot.config.json b/this.bot.config.json index 447906e76..c27201ef4 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -127,6 +127,7 @@ "name": "Multi-Period-Daily", "validPeriods": [ "45-min", + "40-min", "30-min", "20-min", "15-min", @@ -284,6 +285,7 @@ "type": "Daily Files", "validPeriods": [ "45-min", + "40-min", "30-min", "20-min", "15-min", @@ -343,6 +345,7 @@ "type": "Daily Files", "validPeriods": [ "45-min", + "40-min", "30-min", "20-min", "15-min", @@ -402,6 +405,7 @@ "type": "Daily Files", "validPeriods": [ "45-min", + "40-min", "30-min", "20-min", "15-min", @@ -461,6 +465,7 @@ "type": "Daily Files", "validPeriods": [ "45-min", + "40-min", "30-min", "20-min", "15-min", From 03426de2de9edccb06c2fb6e15a603dfa4f3d5d3 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 25 Aug 2019 13:58:43 +0200 Subject: [PATCH 198/244] Multi Period Process created --- Multi-Period/User.Bot.js | 674 +++++++++++++++++++++++++++++++++++++++ this.bot.config.json | 140 ++++++++ 2 files changed, 814 insertions(+) create mode 100644 Multi-Period/User.Bot.js diff --git a/Multi-Period/User.Bot.js b/Multi-Period/User.Bot.js new file mode 100644 index 000000000..d2d1ad6a0 --- /dev/null +++ b/Multi-Period/User.Bot.js @@ -0,0 +1,674 @@ +exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, fileStorage) { + + const FULL_LOG = true; + const LOG_FILE_CONTENT = false; + + const MODULE_NAME = "User Bot"; + + const EXECUTION_FOLDER_NAME = "Trading-Execution"; + const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; + const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; + const STRATEGIES_FOLDER_NAME = "Simulation-Strategies"; + const TRADES_FOLDER_NAME = "Simulation-Trades"; + + const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; + + const commons = COMMONS.newCommons(bot, logger, UTILITIES); + + thisObject = { + initialize: initialize, + start: start + }; + + let utilities = UTILITIES.newCloudUtilities(bot, logger); + + let dataDependencies; + let assistant; + + return thisObject; + + function initialize(pDataDependencies, callBackFunction, pAssistant) { + + try { + + logger.fileName = MODULE_NAME; + logger.initialize(); + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } + + dataDependencies = pDataDependencies; + assistant = pAssistant; + + callBackFunction(global.DEFAULT_OK_RESPONSE); + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function start(dataFiles, timePeriod, outputPeriodLabel, currentDay, startDate, endDate, interExecutionMemory, callBackFunction) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); } + + let market = global.MARKET; + let dataFile; + + let recordsArray + let conditionsArray + let strategiesArray + let tradesArray + let lastObjectsArray + + let tradingSystem = {}; + + commons.initializeData(); + + for (let i = 0; i < dataDependencies.config.length; i++) { + + let dependency = dataDependencies.config[i]; + dataFile = dataFiles[i]; + + switch (i) { + /* + case 0: { + commons.buildLRC(dataFile, callBackFunction); + break; + }*/ + case 0: { + commons.buildPercentageBandwidthMap(dataFile, callBackFunction); + break; + } + case 1: { + commons.buildBollingerBandsMap(dataFile, callBackFunction); + break; + } + case 2: { + commons.buildBollingerChannelsArray(dataFile, callBackFunction); + break; + } + case 3: { + commons.buildBollingerSubChannelsArray(dataFile, callBackFunction); + break; + } + case 4: { + commons.buildCandles(dataFile, callBackFunction); + break; + } + } + } + + commons.runSimulation( + timePeriod, + currentDay, + startDate, + endDate, + interExecutionMemory, + assistant, + writeFiles, + callBackFunction) + + function writeFiles(pTradingSystem, pExecutionArray, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) { + + tradingSystem = pTradingSystem + executionArray = pExecutionArray + recordsArray = pRecordsArray + conditionsArray = pConditionsArray + strategiesArray = pStrategiesArray + tradesArray = pTradesArray + lastObjectsArray = pLastObjectsArray + + writeExecutionFile() + } + + function writeExecutionFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < executionArray.length; i++) { + + let record = executionArray[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 + "," + + JSON.stringify(record.executionRecord) + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + EXECUTION_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + filePath += '/' + fileName + + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + writeFinalResults(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeFinalResults() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFinalResults -> Entering function."); } + + if ( // We only write this file if we are at the head of the market. + Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS + !== + Math.trunc((new Date()).valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS + ) { + writeRecordsFile(); + return; + } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < recordsArray.length; i++) { + + let record = recordsArray[i]; + + /* Will only add to the file the records of the current day */ + + if (record.begin < currentDay.valueOf()) { continue; } + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.type + "," + + record.marketRate + "," + + record.amount + "," + + record.balanceA + "," + + record.balanceB + "," + + record.profit + "," + + record.lastTradeProfitLoss + "," + + record.stopLoss + "," + + record.roundtrips + "," + + record.hits + "," + + record.fails + "," + + record.hitRatio + "," + + record.ROI + "," + + record.periods + "," + + record.days + "," + + record.anualizedRateOfReturn + "," + + record.positionRate + "," + + record.lastTradeROI + "," + + record.strategy + "," + + record.strategyStageNumber + "," + + record.takeProfit + "," + + record.stopLossPhase + "," + + record.takeProfitPhase + "," + + JSON.stringify(record.executionRecord) + "," + + record.positionSize + "," + + record.initialBalanceA + "," + + record.minimumBalanceA + "," + + record.maximumBalanceA + "," + + record.initialBalanceB + "," + + record.minimumBalanceB + "," + + record.maximumBalanceB + "," + + record.baseAsset + "," + + record.positionPeriods + "," + + record.positionDays + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel; + filePath += '/' + fileName + + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFinalResults -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFinalResults -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + writeRecordsFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeRecordsFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < recordsArray.length; i++) { + + let record = recordsArray[i]; + + /* Will only add to the file the records of the current day */ + + if (record.begin < currentDay.valueOf()) { continue; } + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.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.positionPeriods + "," + + record.positionDays + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + filePath += '/' + fileName + + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + writeConditionsFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeConditionsFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < conditionsArray.length; i++) { + + let record = conditionsArray[i]; + + /* Will only add to the file the records of the current day */ + + if (record.begin < currentDay.valueOf()) { continue; } + + let conditions = ""; + let conditionsSeparator = ""; + + /* Will only add to the file the records of the current day */ + + if (record.begin < currentDay.valueOf()) { continue; } + + for (let j = 0; j < record.length - 3; j++) { + conditions = conditions + conditionsSeparator + record[j]; + if (conditionsSeparator === "") { conditionsSeparator = ","; } + } + + conditions = conditions + conditionsSeparator + '[' + record[record.length - 3] + ']'; // The last item contains an Array of condition values. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 2] + ']'; // The last item contains an Array of formulaErrors. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of formulaValues. + + fileContent = fileContent + separator + '[' + conditions + ']'; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + fileContent = "[" + JSON.stringify(tradingSystem) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]"; + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + filePath += '/' + fileName + + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + writeStrategiesFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeStrategiesFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < strategiesArray.length; i++) { + let record = strategiesArray[i]; + + /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends + at the current date. */ + + if (record.end < currentDay.valueOf()) { continue; } + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.status + "," + + record.number + "," + + record.beginRate + "," + + record.endRate + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + filePath += '/' + fileName + + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + writeTradesFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeTradesFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < tradesArray.length; i++) { + + let record = tradesArray[i]; + + /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends + at the current date. */ + + if (record.end < currentDay.valueOf()) { continue; } + if (record.stopRate === undefined) { record.stopRate = 0 } + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.status + "," + + record.lastTradeROI + "," + + record.beginRate + "," + + record.endRate + "," + + record.exitType + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + filePath += '/' + fileName + + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + callBackFunction(global.DEFAULT_OK_RESPONSE); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } +}; diff --git a/this.bot.config.json b/this.bot.config.json index c27201ef4..34fc6f3b7 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -255,6 +255,146 @@ "dataSet": "One-Min" } ] + }, + { + "name": "Multi-Period", + "description": "Produces a Daily or Market files depending on the current timePeriod.", + "normalWaitTime": 60000, + "retryWaitTime": 10000, + "sleepWaitTime": 3600000, + "comaWaitTime": 86400000, + "framework": { + "name": "Multi-Period", + "validPeriods": [ + "45-min", + "40-min", + "30-min", + "20-min", + "15-min", + "10-min", + "05-min", + "04-min", + "03-min", + "02-min", + "01-min" + ], + "startDate": { + "fixedDate": "2018-07-01" + }, + "endDate": { + "takeItFromStatusDependency": 1 + } + }, + "statusDependencies": [ + { + "devTeam": "AAMasters", + "bot": "AACharly", + "botVersion": { + "major": 1, + "minor": 0 + }, + "process": "Historic-Trades", + "dataSetVersion": "dataSet.V1" + }, + { + "devTeam": "AAMasters", + "bot": "AAOlivia", + "botVersion": { + "major": 1, + "minor": 0 + }, + "process": "Multi-Period-Daily", + "dataSetVersion": "dataSet.V1" + }, + { + "devTeam": "AAMasters", + "bot": "AAJason", + "botVersion": { + "major": 1, + "minor": 0 + }, + "process": "Multi-Period-Daily", + "dataSetVersion": "dataSet.V1" + }, + { + "devTeam": "AAMasters", + "bot": "AAJason", + "botVersion": { + "major": 1, + "minor": 0 + }, + "process": "Context", + "dataSetVersion": "dataSet.V1" + } + ], + "dataDependencies": [ + { + "devTeam": "AAMasters", + "bot": "AAChris", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Percentage-Bandwidth", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Daily" + }, + { + "devTeam": "AAMasters", + "bot": "AAChris", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Bollinger-Bands", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Daily" + }, + { + "devTeam": "AAMasters", + "bot": "AAPaula", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Bollinger-Standard-Channels", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Daily" + }, + { + "devTeam": "AAMasters", + "bot": "AAPaula", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Bollinger-Standard-Sub-Channels", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Daily" + }, + { + "devTeam": "AAMasters", + "bot": "AAOlivia", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Candles", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Daily" + }, + { + "devTeam": "AAMasters", + "bot": "AABruce", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Candles", + "dataSetVersion": "dataSet.V1", + "dataSet": "One-Min" + } + ] } ], "products": [ From 4c89d3b45d7b4ba9496ca665cd600950b13503d2 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 25 Aug 2019 20:52:33 +0200 Subject: [PATCH 199/244] Running on top of Multi Period with Daily Files --- Commons.js | 199 ++++++++++++++++++++------------------- Multi-Period/User.Bot.js | 76 ++++++++------- Project.njsproj | 4 + this.bot.config.json | 2 +- 4 files changed, 145 insertions(+), 136 deletions(-) diff --git a/Commons.js b/Commons.js index 0678ae4ba..917df2f7c 100644 --- a/Commons.js +++ b/Commons.js @@ -8,11 +8,9 @@ const GMT_SECONDS = ':00.000 GMT+0000'; let thisObject = { - initializeData: initializeData, runSimulation: runSimulation, - buildLRC: buildLRC, - buildPercentageBandwidthMap: buildPercentageBandwidthMap, - buildBollingerBandsMap: buildBollingerBandsMap, + buildPercentageBandwidthArray: buildPercentageBandwidthArray, + buildBollingerBandsArray: buildBollingerBandsArray, buildBollingerChannelsArray: buildBollingerChannelsArray, buildBollingerSubChannelsArray: buildBollingerSubChannelsArray, buildCandles: buildCandles @@ -20,30 +18,19 @@ let utilities = UTILITIES.newCloudUtilities(bot, logger); - let LRCMap = new Map(); - let percentageBandwidthMap = new Map(); - let bollingerBandsMap = new Map(); - let bollingerChannelsArray = []; - let bollingerSubChannelsArray = []; + let percentageBandwidthAt = {} + let bollingerBandsAt = {} + let bollingerChannelsAt = {} + let bollingerSubChannelsAt = {} + let candlesAt = {} - let candles = []; const definition = global.DEFINITION return thisObject; - function initializeData() { - - LRCMap = new Map(); - percentageBandwidthMap = new Map(); - bollingerBandsMap = new Map(); - bollingerChannelsArray = []; - bollingerSubChannelsArray = []; - - candles = []; - } - async function runSimulation( timePeriod, + timePeriodLabel, currentDay, startDate, endDate, @@ -241,7 +228,6 @@ /* In some cases we need to know if we are positioned at the last candle of the calendar day, for that we need these variables. */ let lastInstantOfTheDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1; - let lastCandle = candles[candles.length - 1]; /* The following counters need to survive multiple executions of the similator and keep themselves reliable. @@ -550,9 +536,18 @@ yesterday.anualizedRateOfReturn = anualizedRateOfReturn; } - /* Main Simulation Loop: We go thourgh all the candles at this time period. */ - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Main Simulation Loop -> candles.length = " + candles.length); } + /* Main Array and Maps */ + let candles = candlesAt[timePeriodLabel] + let percentageBandwidthArray = percentageBandwidthAt[timePeriodLabel] + let bollingerBandsArray = bollingerBandsAt[timePeriodLabel] + let bollingerChannelsArray = bollingerChannelsAt[timePeriodLabel] + let bollingerSubChannelsArray = bollingerSubChannelsAt[timePeriodLabel] + + /* Last Candle */ + let lastCandle = candles[candles.length - 1]; + + /* Main Simulation Loop: We go thourgh all the candles at this time period. */ let i initializeLoop() @@ -568,16 +563,29 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Processing candle # " + i); } let candle = candles[i]; + let percentageBandwidth = getElement(percentageBandwidthArray, candle); + let bollingerBand = getElement(bollingerBandsArray, candle); + let bollingerChannel = getElement(bollingerChannelsArray, candle); + let bollingerSubChannel = getElement(bollingerSubChannelsArray, candle); + + let chart = {} + + for (let j = 0; j < global.dailyFilePeriods.length; j++) { + + let mapKey = dailyFilePeriods[j][1] + chart[mapKey] = {} + chart[mapKey].candle = getElement(candlesAt[mapKey], candle); + chart[mapKey].percentageBandwidth = getElement(percentageBandwidthAt[mapKey], candle); + chart[mapKey].bollingerBand = getElement(bollingerBandsAt[mapKey], candle); + chart[mapKey].bollingerChannel = getElement(bollingerChannelsAt[mapKey], candle); + chart[mapKey].bollingerSubChannel = getElement(bollingerSubChannelsAt[mapKey], candle); + } + + let positionedAtYesterday = (candle.end < currentDay.valueOf()) if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Candle Begin @ " + (new Date(candle.begin)).toLocaleString()) } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Candle End @ " + (new Date(candle.end)).toLocaleString()) } - let percentageBandwidth = percentageBandwidthMap.get(candle.begin); - let bollingerBand = bollingerBandsMap.get(candle.begin); - let bollingerChannel = getElement(bollingerChannelsArray, candle.begin, candle.end); - let bollingerSubChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end); - let positionedAtYesterday = (candle.end < currentDay.valueOf()) - /* Assistant Info */ let ticker = { @@ -586,8 +594,6 @@ last: candle.close } - //let LRC = LRCMap.get(candle.begin); - /* If any of the needed indicators is missing, then that period is not calculated */ if (candle.end < initialDate.valueOf()) { @@ -1088,12 +1094,14 @@ */ value = false - if (node.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { + if (node.code.indexOf('previous') > -1 && err.message.indexOf('of undefined') > -1 || + node.code.indexOf('chart') > -1 && err.message.indexOf('of undefined') > -1 + ) { /* We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. */ } else { - node.error = err.message + node.error = err.message + " @ " + (new Date(candle.begin)).toLocaleString() } } @@ -1201,10 +1209,10 @@ } else { let stopRunningDate = new Date(candle.begin) if (balance < minimumBalance) { - tradingSystem.error = "Min Balance @ " + stopRunningDate.toUTCString() + tradingSystem.error = "Min Balance @ " + stopRunningDate.toLocaleString() } if (balance > maximumBalance) { - tradingSystem.error = "Max Balance @ " + stopRunningDate.toUTCString() + tradingSystem.error = "Max Balance @ " + stopRunningDate.toLocaleString() } } } @@ -2612,19 +2620,36 @@ } - function getElement(pArray, begin, end) { + function getElement(pArray, currentCandle) { let element; - for (let i = 0; i < pArray.length; i++) { - element = pArray[i]; - if (begin >= element.begin && end <= element.end) { + if (currentCandle.end === element.end) { // when there is an exact match at the end we take that element return element - } + } else { + if ( + i > 0 && + element.end > currentCandle.end + ) + { + let previousElement = pArray[i - 1] + if (previousElement.end < currentCandle.end) { + return previousElement // If one elements goes into the future of currentCandle, then we stop and take the previous element. + } else { + return + } + } + if ( + i === pArray.length - 1 // If we reach the end of the array, then we return the last element. + && + element.end < currentCandle.end + ) { + return element + } + } } - return } } @@ -2634,58 +2659,13 @@ } } - function buildLRC(dataFile, callBackFunction) { + function buildPercentageBandwidthArray(dataFile, timePeriodLabel, callBackFunction) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildLRC -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildPercentageBandwidthArray -> Entering function."); } try { - let previous; - - for (let i = 0; i < dataFile.length; i++) { - - let LRC = { - begin: dataFile[i][0], - end: dataFile[i][1], - _15: dataFile[i][2], - _30: dataFile[i][3], - _60: dataFile[i][4] - }; - - if (previous !== undefined) { - - if (previous._15 > LRC._15) { LRC.direction15 = 'Down'; } - if (previous._15 < LRC._15) { LRC.direction15 = 'Up'; } - if (previous._15 === LRC._15) { LRC.direction15 = 'Side'; } - - if (previous._30 > LRC._30) { LRC.direction30 = 'Down'; } - if (previous._30 < LRC._30) { LRC.direction30 = 'Up'; } - if (previous._30 === LRC._30) { LRC.direction30 = 'Side'; } - - if (previous._60 > LRC._60) { LRC.direction60 = 'Down'; } - if (previous._60 < LRC._60) { LRC.direction60 = 'Up'; } - if (previous._60 === LRC._60) { LRC.direction60 = 'Side'; } - - } - - LRC.previous = previous; - - LRCMap.set(LRC.begin, LRC); - - previous = LRC; - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] buildLRC -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildPercentageBandwidthMap(dataFile, callBackFunction) { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildPercentageBandwidthMap -> Entering function."); } - - try { + let percentageBandwidthArray = []; let previous; @@ -2709,23 +2689,29 @@ percentageBandwidth.previous = previous; - percentageBandwidthMap.set(percentageBandwidth.begin, percentageBandwidth); + percentageBandwidthArray.push(percentageBandwidth); previous = percentageBandwidth; + } + + percentageBandwidthAt[timePeriodLabel] = percentageBandwidthArray + } catch (err) { - logger.write(MODULE_NAME, "[ERROR] buildPercentageBandwidthMap -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] buildPercentageBandwidthArray -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - function buildBollingerBandsMap(dataFile, callBackFunction) { + function buildBollingerBandsArray(dataFile, timePeriodLabel, callBackFunction) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildBollingerBandsMap -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildBollingerBandsArray -> Entering function."); } try { + let bollingerBandsArray = []; + let previous; for (let i = 0; i < dataFile.length; i++) { @@ -2748,23 +2734,28 @@ bollingerBand.previous = previous; - bollingerBandsMap.set(bollingerBand.begin, bollingerBand); + bollingerBandsArray.push(bollingerBand); previous = bollingerBand; } + + bollingerBandsAt[timePeriodLabel] = bollingerBandsArray + } catch (err) { - logger.write(MODULE_NAME, "[ERROR] buildBollingerBandsMap -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] buildBollingerBandsArray -> err = " + err.stack); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - function buildBollingerChannelsArray(dataFile, callBackFunction) { + function buildBollingerChannelsArray(dataFile, timePeriodLabel, callBackFunction) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildBollingerChannelsArray -> Entering function."); } try { + let bollingerChannelsArray = []; + let previous; for (let i = 0; i < dataFile.length; i++) { @@ -2782,6 +2773,9 @@ previous = bollingerChannel; } + + bollingerChannelsAt[timePeriodLabel] = bollingerChannelsArray + } catch (err) { logger.write(MODULE_NAME, "[ERROR] buildBollingerChannelsArray -> err = " + err.stack); @@ -2789,11 +2783,12 @@ } } - function buildBollingerSubChannelsArray(dataFile, callBackFunction) { + function buildBollingerSubChannelsArray(dataFile, timePeriodLabel, callBackFunction) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildBollingerSubChannelsArray -> Entering function."); } try { + let bollingerSubChannelsArray = []; let previous; @@ -2817,6 +2812,9 @@ previous = bollingerSubChannel; } + + bollingerSubChannelsAt[timePeriodLabel] = bollingerSubChannelsArray + } catch (err) { logger.write(MODULE_NAME, "[ERROR] buildBollingerSubChannelsArray -> err = " + err.stack); @@ -2824,11 +2822,12 @@ } } - function buildCandles(dataFile, callBackFunction) { + function buildCandles(dataFile, timePeriodLabel, callBackFunction) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] buildCandles -> Entering function."); } try { + let candles = []; let previous; @@ -2863,6 +2862,8 @@ previous = candle; } + + candlesAt[timePeriodLabel] = candles } catch (err) { logger.write(MODULE_NAME, "[ERROR] buildCandles -> err = " + err.stack); diff --git a/Multi-Period/User.Bot.js b/Multi-Period/User.Bot.js index d2d1ad6a0..5b47ac467 100644 --- a/Multi-Period/User.Bot.js +++ b/Multi-Period/User.Bot.js @@ -47,7 +47,7 @@ } } - function start(dataFiles, timePeriod, outputPeriodLabel, currentDay, startDate, endDate, interExecutionMemory, callBackFunction) { + function start(multiPeriodDataFiles, timePeriod, timePeriodLabel, currentDay, startDate, endDate, interExecutionMemory, callBackFunction) { try { @@ -64,44 +64,48 @@ let tradingSystem = {}; - commons.initializeData(); + for (let j = 0; j < global.dailyFilePeriods.length; j++) { - for (let i = 0; i < dataDependencies.config.length; i++) { + let mapKey = dailyFilePeriods[j][1] + let dataFiles = multiPeriodDataFiles.get(mapKey) - let dependency = dataDependencies.config[i]; - dataFile = dataFiles[i]; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Building Dataset for timePeriod = " + mapKey); } - switch (i) { - /* - case 0: { - commons.buildLRC(dataFile, callBackFunction); - break; - }*/ - case 0: { - commons.buildPercentageBandwidthMap(dataFile, callBackFunction); - break; - } - case 1: { - commons.buildBollingerBandsMap(dataFile, callBackFunction); - break; - } - case 2: { - commons.buildBollingerChannelsArray(dataFile, callBackFunction); - break; - } - case 3: { - commons.buildBollingerSubChannelsArray(dataFile, callBackFunction); - break; - } - case 4: { - commons.buildCandles(dataFile, callBackFunction); - break; + if (dataFiles) { + for (let i = 0; i < dataDependencies.config.length; i++) { + + let dependency = dataDependencies.config[i]; + dataFile = dataFiles[i]; + + switch (i) { + case 0: { + commons.buildPercentageBandwidthArray(dataFile, mapKey, callBackFunction); + break; + } + case 1: { + commons.buildBollingerBandsArray(dataFile, mapKey, callBackFunction); + break; + } + case 2: { + commons.buildBollingerChannelsArray(dataFile, mapKey, callBackFunction); + break; + } + case 3: { + commons.buildBollingerSubChannelsArray(dataFile, mapKey, callBackFunction); + break; + } + case 4: { + commons.buildCandles(dataFile, mapKey, callBackFunction); + break; + } + } } } } commons.runSimulation( timePeriod, + timePeriodLabel, currentDay, startDate, endDate, @@ -159,7 +163,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + EXECUTION_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + EXECUTION_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -274,7 +278,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -381,7 +385,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -469,7 +473,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -546,7 +550,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -626,7 +630,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); diff --git a/Project.njsproj b/Project.njsproj index 4cab6c556..6289f096d 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -38,6 +38,7 @@ + @@ -45,6 +46,9 @@ + + Code + diff --git a/this.bot.config.json b/this.bot.config.json index 34fc6f3b7..72f028270 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -313,7 +313,7 @@ "major": 1, "minor": 0 }, - "process": "Multi-Period-Daily", + "process": "Multi-Period", "dataSetVersion": "dataSet.V1" }, { From cce4839be35e61770c48872241e7fed3a13f842a Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 26 Aug 2019 17:18:31 +0200 Subject: [PATCH 200/244] Fullly working on Multi Period --- Commons.js | 99 ++- Multi-Period-Daily/User.Bot.js | 674 ------------------ Multi-Period-Market/User.Bot.js | 523 -------------- Multi-Period/User.Bot.js | 1181 +++++++++++++++++++------------ Project.njsproj | 4 - this.bot.config.json | 300 ++------ 6 files changed, 865 insertions(+), 1916 deletions(-) delete mode 100644 Multi-Period-Daily/User.Bot.js delete mode 100644 Multi-Period-Market/User.Bot.js diff --git a/Commons.js b/Commons.js index 917df2f7c..170498503 100644 --- a/Commons.js +++ b/Commons.js @@ -43,9 +43,12 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Entering function."); } - let processingDailyFiles = (currentDay !== undefined) + if (timePeriod > global.dailyFilePeriods[0][0]) { + processingDailyFiles = false + } else { + processingDailyFiles = true + } - let executionArray = []; let recordsArray = []; let conditionsArray = []; let strategiesArray = []; @@ -227,7 +230,10 @@ /* In some cases we need to know if we are positioned at the last candle of the calendar day, for that we need these variables. */ - let lastInstantOfTheDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1; + let lastInstantOfTheDay = 0 + if (currentDay) { + lastInstantOfTheDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1; + } /* The following counters need to survive multiple executions of the similator and keep themselves reliable. @@ -243,7 +249,7 @@ not adding to the counters duplicate info when processing the day before candles. To overcome these challenges we record the values of the counters and variables on the interExecutionMemory only when - the day is complete and if we have a currentDay. That menas that for Market Files we will never use + the day is complete and if we have a current Day. That menas that for Market Files we will never use interExecutionMemory. */ @@ -458,14 +464,16 @@ endRate: interExecutionMemory.currentTrade.endRate } - if (currentDay.valueOf() >= startDate.valueOf() + ONE_DAY_IN_MILISECONDS) { // Only after the first day we start grabbing the balance from this memory. + if (currentDay) { + if (currentDay.valueOf() >= startDate.valueOf() + ONE_DAY_IN_MILISECONDS) { // Only after the first day we start grabbing the balance from this memory. - balanceAssetA = interExecutionMemory.balanceAssetA; - balanceAssetB = interExecutionMemory.balanceAssetB; + balanceAssetA = interExecutionMemory.balanceAssetA; + balanceAssetB = interExecutionMemory.balanceAssetB; - yesterday.balanceAssetA = balanceAssetA; - yesterday.balanceAssetB = balanceAssetB; + yesterday.balanceAssetA = balanceAssetA; + yesterday.balanceAssetB = balanceAssetB; + } } lastTradeProfitLoss = interExecutionMemory.lastTradeProfitLoss; @@ -553,7 +561,17 @@ function initializeLoop() { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> initializeLoop -> Entering function."); } - i = 0 + + /* Estimate Initial Candle */ + + let firstEnd = candles[0].end + let targetEnd = initialDate.valueOf() + let diff = targetEnd - firstEnd + let amount = diff / timePeriod + + i = Math.trunc(amount) + if (i < 0) { i = 0 } + loop() } @@ -570,18 +588,39 @@ let chart = {} - for (let j = 0; j < global.dailyFilePeriods.length; j++) { + if (processingDailyFiles) { + for (let j = 0; j < global.dailyFilePeriods.length; j++) { - let mapKey = dailyFilePeriods[j][1] - chart[mapKey] = {} - chart[mapKey].candle = getElement(candlesAt[mapKey], candle); - chart[mapKey].percentageBandwidth = getElement(percentageBandwidthAt[mapKey], candle); - chart[mapKey].bollingerBand = getElement(bollingerBandsAt[mapKey], candle); - chart[mapKey].bollingerChannel = getElement(bollingerChannelsAt[mapKey], candle); - chart[mapKey].bollingerSubChannel = getElement(bollingerSubChannelsAt[mapKey], candle); + let mapKey = dailyFilePeriods[j][1] + let propertyName = 'at' + mapKey.replace('-', ''); + + chart[propertyName] = {} + chart[propertyName].candle = getElement(candlesAt[mapKey], candle); + chart[propertyName].percentageBandwidth = getElement(percentageBandwidthAt[mapKey], candle); + chart[propertyName].bollingerBand = getElement(bollingerBandsAt[mapKey], candle); + chart[propertyName].bollingerChannel = getElement(bollingerChannelsAt[mapKey], candle); + chart[propertyName].bollingerSubChannel = getElement(bollingerSubChannelsAt[mapKey], candle); + } } - let positionedAtYesterday = (candle.end < currentDay.valueOf()) + for (let j = 0; j < global.marketFilesPeriods.length; j++) { + + let mapKey = marketFilesPeriods[j][1] + let propertyName = 'at' + mapKey.replace('-', ''); + + chart[propertyName] = {} + chart[propertyName].candle = getElement(candlesAt[mapKey], candle); + chart[propertyName].percentageBandwidth = getElement(percentageBandwidthAt[mapKey], candle); + chart[propertyName].bollingerBand = getElement(bollingerBandsAt[mapKey], candle); + chart[propertyName].bollingerChannel = getElement(bollingerChannelsAt[mapKey], candle); + chart[propertyName].bollingerSubChannel = getElement(bollingerSubChannelsAt[mapKey], candle); + } + + /* While we are processing the previous day. */ + let positionedAtYesterday = false + if (currentDay) { + positionedAtYesterday = (candle.end < currentDay.valueOf()) + } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Candle Begin @ " + (new Date(candle.begin)).toLocaleString()) } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Candle End @ " + (new Date(candle.end)).toLocaleString()) } @@ -1913,14 +1952,16 @@ } /* We are not going to place orders based on outdated information. The next filter prevents firing orders when backtesting. */ - let today = new Date(Math.trunc((new Date().valueOf()) / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) - let processDay = new Date(Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) - if (today.valueOf() !== processDay.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because the current candle belongs to the previous day and that is considered simulation and not live trading."); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> today = " + today); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> processDay = " + processDay); } - takePositionAtSimulation() - return; + if (currentDay) { + let today = new Date(Math.trunc((new Date().valueOf()) / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) + let processDay = new Date(Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) + if (today.valueOf() !== processDay.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because the current candle belongs to the previous day and that is considered simulation and not live trading."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> today = " + today); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> processDay = " + processDay); } + takePositionAtSimulation() + return; + } } let openPositionRate @@ -2552,7 +2593,7 @@ /* Before returning we need to see if we have to record some of our counters at the interExecutionMemory. - To do that, the condition to be met is that this execution must include all candles of the currentDay. + To do that, the condition to be met is that this execution must include all candles of the current day. */ if (processingDailyFiles) { @@ -2616,7 +2657,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> callback -> recordsArray.length = " + recordsArray.length); } - callback(tradingSystem, executionArray, recordsArray, conditionsArray, strategiesArray, tradesArray, lastObjectsArray); + callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, tradesArray, lastObjectsArray); } diff --git a/Multi-Period-Daily/User.Bot.js b/Multi-Period-Daily/User.Bot.js deleted file mode 100644 index 88ddebd50..000000000 --- a/Multi-Period-Daily/User.Bot.js +++ /dev/null @@ -1,674 +0,0 @@ -exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, fileStorage) { - - const FULL_LOG = true; - const LOG_FILE_CONTENT = false; - - const MODULE_NAME = "User Bot"; - - const EXECUTION_FOLDER_NAME = "Trading-Execution"; - const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; - const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; - const STRATEGIES_FOLDER_NAME = "Simulation-Strategies"; - const TRADES_FOLDER_NAME = "Simulation-Trades"; - - const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; - - const commons = COMMONS.newCommons(bot, logger, UTILITIES); - - thisObject = { - initialize: initialize, - start: start - }; - - let utilities = UTILITIES.newCloudUtilities(bot, logger); - - let dataDependencies; - let assistant; - - return thisObject; - - function initialize(pDataDependencies, callBackFunction, pAssistant) { - - try { - - logger.fileName = MODULE_NAME; - logger.initialize(); - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } - - dataDependencies = pDataDependencies; - assistant = pAssistant; - - callBackFunction(global.DEFAULT_OK_RESPONSE); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function start(dataFiles, timePeriod, outputPeriodLabel, currentDay, startDate, endDate, interExecutionMemory, callBackFunction) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); } - - let market = global.MARKET; - let dataFile; - - let recordsArray - let conditionsArray - let strategiesArray - let tradesArray - let lastObjectsArray - - let tradingSystem = {}; - - commons.initializeData(); - - for (let i = 0; i < dataDependencies.config.length; i++) { - - let dependency = dataDependencies.config[i]; - dataFile = dataFiles[i]; - - switch (i) { - /* - case 0: { - commons.buildLRC(dataFile, callBackFunction); - break; - }*/ - case 0: { - commons.buildPercentageBandwidthMap(dataFile, callBackFunction); - break; - } - case 1: { - commons.buildBollingerBandsMap(dataFile, callBackFunction); - break; - } - case 2: { - commons.buildBollingerChannelsArray(dataFile, callBackFunction); - break; - } - case 3: { - commons.buildBollingerSubChannelsArray(dataFile, callBackFunction); - break; - } - case 4: { - commons.buildCandles(dataFile, callBackFunction); - break; - } - } - } - - commons.runSimulation( - timePeriod, - currentDay, - startDate, - endDate, - interExecutionMemory, - assistant, - writeFiles, - callBackFunction) - - function writeFiles(pTradingSystem, pExecutionArray, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) { - - tradingSystem = pTradingSystem - executionArray = pExecutionArray - recordsArray = pRecordsArray - conditionsArray = pConditionsArray - strategiesArray = pStrategiesArray - tradesArray = pTradesArray - lastObjectsArray = pLastObjectsArray - - writeExecutionFile() - } - - function writeExecutionFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < executionArray.length; i++) { - - let record = executionArray[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 + "," + - JSON.stringify(record.executionRecord) + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + EXECUTION_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - writeFinalResults(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeFinalResults() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFinalResults -> Entering function."); } - - if ( // We only write this file if we are at the head of the market. - Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS - !== - Math.trunc((new Date()).valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS - ) { - writeRecordsFile(); - return; - } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < recordsArray.length; i++) { - - let record = recordsArray[i]; - - /* Will only add to the file the records of the current day */ - - if (record.begin < currentDay.valueOf()) { continue; } - - fileContent = fileContent + separator + '[' + - record.begin + "," + - record.end + "," + - record.type + "," + - record.marketRate + "," + - record.amount + "," + - record.balanceA + "," + - record.balanceB + "," + - record.profit + "," + - record.lastTradeProfitLoss + "," + - record.stopLoss + "," + - record.roundtrips + "," + - record.hits + "," + - record.fails + "," + - record.hitRatio + "," + - record.ROI + "," + - record.periods + "," + - record.days + "," + - record.anualizedRateOfReturn + "," + - record.positionRate + "," + - record.lastTradeROI + "," + - record.strategy + "," + - record.strategyStageNumber + "," + - record.takeProfit + "," + - record.stopLossPhase + "," + - record.takeProfitPhase + "," + - JSON.stringify(record.executionRecord) + "," + - record.positionSize + "," + - record.initialBalanceA + "," + - record.minimumBalanceA + "," + - record.maximumBalanceA + "," + - record.initialBalanceB + "," + - record.minimumBalanceB + "," + - record.maximumBalanceB + "," + - record.baseAsset + "," + - record.positionPeriods + "," + - record.positionDays + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFinalResults -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFinalResults -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - writeRecordsFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeRecordsFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < recordsArray.length; i++) { - - let record = recordsArray[i]; - - /* Will only add to the file the records of the current day */ - - if (record.begin < currentDay.valueOf()) { continue; } - - fileContent = fileContent + separator + '[' + - record.begin + "," + - record.end + "," + - record.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.positionPeriods + "," + - record.positionDays + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - writeConditionsFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeConditionsFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < conditionsArray.length; i++) { - - let record = conditionsArray[i]; - - /* Will only add to the file the records of the current day */ - - if (record.begin < currentDay.valueOf()) { continue; } - - let conditions = ""; - let conditionsSeparator = ""; - - /* Will only add to the file the records of the current day */ - - if (record.begin < currentDay.valueOf()) { continue; } - - for (let j = 0; j < record.length - 3; j++) { - conditions = conditions + conditionsSeparator + record[j]; - if (conditionsSeparator === "") { conditionsSeparator = ","; } - } - - conditions = conditions + conditionsSeparator + '[' + record[record.length - 3] + ']'; // The last item contains an Array of condition values. - conditions = conditions + conditionsSeparator + '[' + record[record.length - 2] + ']'; // The last item contains an Array of formulaErrors. - conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of formulaValues. - - fileContent = fileContent + separator + '[' + conditions + ']'; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - fileContent = "[" + JSON.stringify(tradingSystem) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]"; - - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - writeStrategiesFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeStrategiesFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < strategiesArray.length; i++) { - let record = strategiesArray[i]; - - /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends - at the current date. */ - - if (record.end < currentDay.valueOf()) { continue; } - - fileContent = fileContent + separator + '[' + - record.begin + "," + - record.end + "," + - record.status + "," + - record.number + "," + - record.beginRate + "," + - record.endRate + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - writeTradesFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeTradesFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < tradesArray.length; i++) { - - let record = tradesArray[i]; - - /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends - at the current date. */ - - if (record.end < currentDay.valueOf()) { continue; } - if (record.stopRate === undefined) { record.stopRate = 0} - - fileContent = fileContent + separator + '[' + - record.begin + "," + - record.end + "," + - record.status + "," + - record.lastTradeROI + "," + - record.beginRate + "," + - record.endRate + "," + - record.exitType + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - callBackFunction(global.DEFAULT_OK_RESPONSE); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } -}; diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js deleted file mode 100644 index 179343e43..000000000 --- a/Multi-Period-Market/User.Bot.js +++ /dev/null @@ -1,523 +0,0 @@ -exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, fileStorage) { - - const FULL_LOG = true; - const LOG_FILE_CONTENT = false; - - const MODULE_NAME = "User Bot"; - - const EXECUTION_FOLDER_NAME = "Trading-Execution"; - const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; - const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; - const STRATEGIES_FOLDER_NAME = "Simulation-Strategies"; - const TRADES_FOLDER_NAME = "Simulation-Trades"; - - const commons = COMMONS.newCommons(bot, logger, UTILITIES); - - thisObject = { - initialize: initialize, - start: start - }; - - let dataDependencies; - let assistant; - - return thisObject; - - function initialize(pDataDependencies, callBackFunction, pAssistant) { - - try { - - logger.fileName = MODULE_NAME; - logger.initialize(); - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } - - dataDependencies = pDataDependencies; - assistant = pAssistant; - - callBackFunction(global.DEFAULT_OK_RESPONSE); - - } catch (err) { - logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function start(dataFiles, timePeriod, outputPeriodLabel, startDate, endDate, callBackFunction) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); } - - let market = global.MARKET; - let dataFile; - - let recordsArray - let conditionsArray - let strategiesArray - let tradesArray - let lastObjectsArray - - let tradingSystem = {}; - let interExecutionMemory = {}; - let currentDay = bot.processDatetime; - - commons.initializeData(); - - for (let i = 0; i < dataDependencies.config.length; i++) { - - let dependency = dataDependencies.config[i]; - dataFile = dataFiles[i]; - - switch (i) { - - /* - case 0: { - commons.buildLRC(dataFile, callBackFunction); - break; - }*/ - case 0: { - commons.buildPercentageBandwidthMap(dataFile, callBackFunction); - break; - } - case 1: { - commons.buildBollingerBandsMap(dataFile, callBackFunction); - break; - } - case 2: { - commons.buildBollingerChannelsArray(dataFile, callBackFunction); - break; - } - case 3: { - commons.buildBollingerSubChannelsArray(dataFile, callBackFunction); - break; - } - case 4: { - commons.buildCandles(dataFile, callBackFunction); - break; - } - } - } - - commons.runSimulation( - timePeriod, - currentDay, - startDate, - endDate, - interExecutionMemory, - assistant, - writeFiles, - callBackFunction) - - function writeFiles(pTradingSystem, pExecutionArray, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) { - - tradingSystem = pTradingSystem - executionArray = pExecutionArray - recordsArray = pRecordsArray - conditionsArray = pConditionsArray - strategiesArray = pStrategiesArray - tradesArray = pTradesArray - lastObjectsArray = pLastObjectsArray - - writeExecutionFile() - } - - function writeExecutionFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < executionArray.length; i++) { - - let record = executionArray[i]; - - fileContent = fileContent + separator + '[' + - record.begin + "," + - record.end + "," + - JSON.stringify(record.executionRecord) + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + EXECUTION_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - writeRecordsFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeRecordsFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < recordsArray.length; i++) { - - let record = recordsArray[i]; - - fileContent = fileContent + separator + '[' + - record.begin + "," + - record.end + "," + - record.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.positionPeriods + "," + - record.positionDays + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - writeConditionsFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeConditionsFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < conditionsArray.length; i++) { - - let record = conditionsArray[i]; - - let conditions = ""; - let conditionsSeparator = ""; - - for (let j = 0; j < record.length - 3; j++) { - conditions = conditions + conditionsSeparator + record[j]; - if (conditionsSeparator === "") { conditionsSeparator = ","; } - } - - conditions = conditions + conditionsSeparator + '[' + record[record.length - 3] + ']'; // The last item contains an Array of condition values. - conditions = conditions + conditionsSeparator + '[' + record[record.length - 2] + ']'; // The last item contains an Array of formulaErrors. - conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of formulaValues. - - fileContent = fileContent + separator + '[' + conditions + ']'; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - fileContent = "[" + JSON.stringify(tradingSystem) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]"; - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - writeStrategiesFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeStrategiesFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < strategiesArray.length; i++) { - let record = strategiesArray[i]; - - fileContent = fileContent + separator + '[' + - record.begin + "," + - record.end + "," + - record.status + "," + - record.number + "," + - record.beginRate + "," + - record.endRate + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - writeTradesFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeTradesFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < tradesArray.length; i++) { - - let record = tradesArray[i]; - if (record.stopRate === undefined) { record.stopRate = 0 } - - fileContent = fileContent + separator + '[' + - record.begin + "," + - record.end + "," + - record.status + "," + - record.lastTradeROI + "," + - record.beginRate + "," + - record.endRate + "," + - record.exitType + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - callBackFunction(global.DEFAULT_OK_RESPONSE); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } -}; diff --git a/Multi-Period/User.Bot.js b/Multi-Period/User.Bot.js index 5b47ac467..72a6e93d0 100644 --- a/Multi-Period/User.Bot.js +++ b/Multi-Period/User.Bot.js @@ -5,7 +5,6 @@ const MODULE_NAME = "User Bot"; - const EXECUTION_FOLDER_NAME = "Trading-Execution"; const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation"; const CONDITIONS_FOLDER_NAME = "Simulation-Conditions"; const STRATEGIES_FOLDER_NAME = "Simulation-Strategies"; @@ -22,12 +21,11 @@ let utilities = UTILITIES.newCloudUtilities(bot, logger); - let dataDependencies; let assistant; return thisObject; - function initialize(pDataDependencies, callBackFunction, pAssistant) { + function initialize(callBackFunction, pAssistant) { try { @@ -36,7 +34,6 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } - dataDependencies = pDataDependencies; assistant = pAssistant; callBackFunction(global.DEFAULT_OK_RESPONSE); @@ -64,17 +61,54 @@ let tradingSystem = {}; - for (let j = 0; j < global.dailyFilePeriods.length; j++) { + for (let j = 0; j < global.marketFilesPeriods.length; j++) { - let mapKey = dailyFilePeriods[j][1] + let mapKey = marketFilesPeriods[j][1] let dataFiles = multiPeriodDataFiles.get(mapKey) if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Building Dataset for timePeriod = " + mapKey); } if (dataFiles) { - for (let i = 0; i < dataDependencies.config.length; i++) { + for (let i = 0; i < 5; i++) { + + dataFile = dataFiles[i]; + + switch (i) { + case 0: { + commons.buildPercentageBandwidthArray(dataFile, mapKey, callBackFunction); + break; + } + case 1: { + commons.buildBollingerBandsArray(dataFile, mapKey, callBackFunction); + break; + } + case 2: { + commons.buildBollingerChannelsArray(dataFile, mapKey, callBackFunction); + break; + } + case 3: { + commons.buildBollingerSubChannelsArray(dataFile, mapKey, callBackFunction); + break; + } + case 4: { + commons.buildCandles(dataFile, mapKey, callBackFunction); + break; + } + } + } + } + } + + for (let j = 0; j < global.dailyFilePeriods.length; j++) { + + let mapKey = global.dailyFilePeriods[j][1] + let dataFiles = multiPeriodDataFiles.get(mapKey) + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Building Dataset for timePeriod = " + mapKey); } + + if (dataFiles) { + for (let i = 0; i < 5; i++) { - let dependency = dataDependencies.config[i]; dataFile = dataFiles[i]; switch (i) { @@ -114,561 +148,826 @@ writeFiles, callBackFunction) - function writeFiles(pTradingSystem, pExecutionArray, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) { + function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) { tradingSystem = pTradingSystem - executionArray = pExecutionArray recordsArray = pRecordsArray conditionsArray = pConditionsArray strategiesArray = pStrategiesArray tradesArray = pTradesArray lastObjectsArray = pLastObjectsArray - writeExecutionFile() - } - - function writeExecutionFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < executionArray.length; i++) { - - let record = executionArray[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 + "," + - JSON.stringify(record.executionRecord) + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + EXECUTION_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; - - } - - writeFinalResults(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); + if (timePeriod > global.dailyFilePeriods[0][0]) { + writeMarketFiles() + } else { + writeDailyFiles() } } - function writeFinalResults() { + function writeMarketFiles() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> Entering function."); } - try { + writeRecordsFile(); - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFinalResults -> Entering function."); } + function writeRecordsFile() { - 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; - } + try { - let separator = ""; - let fileRecordCounter = 0; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeRecordsFile -> Entering function."); } - let fileContent = ""; + let separator = ""; + let fileRecordCounter = 0; - for (let i = 0; i < recordsArray.length; i++) { + let fileContent = ""; - let record = recordsArray[i]; + for (let i = 0; i < recordsArray.length; i++) { - /* Will only add to the file the records of the current day */ + let record = recordsArray[i]; - 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.positionPeriods + "," + + record.positionDays + "]"; - 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.positionPeriods + "," + - record.positionDays + "]"; + if (separator === "") { separator = ","; } - if (separator === "") { separator = ","; } + fileRecordCounter++; - fileRecordCounter++; + } - } + fileContent = "[" + fileContent + "]"; - fileContent = "[" + fileContent + "]"; + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; + filePath += '/' + fileName - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel; - filePath += '/' + fileName + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + function onFileCreated(err) { - function onFileCreated(err) { + try { - try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> fileContent = " + fileContent); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFinalResults -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFinalResults -> onFileCreated -> fileContent = " + fileContent); } + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + callBackFunction(err); + return; - callBackFunction(err); - return; + } + + writeConditionsFile(); } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeRecordsFile -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeRecordsFile -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + function writeConditionsFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeConditionsFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < conditionsArray.length; i++) { + + let record = conditionsArray[i]; + + let conditions = ""; + let conditionsSeparator = ""; + + for (let j = 0; j < record.length - 3; j++) { + conditions = conditions + conditionsSeparator + record[j]; + if (conditionsSeparator === "") { conditionsSeparator = ","; } + } + + conditions = conditions + conditionsSeparator + '[' + record[record.length - 3] + ']'; // The last item contains an Array of condition values. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 2] + ']'; // The last item contains an Array of formulaErrors. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of formulaValues. + + fileContent = fileContent + separator + '[' + conditions + ']'; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + fileContent = "[" + JSON.stringify(tradingSystem) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]"; + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; + filePath += '/' + fileName + + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + writeStrategiesFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeConditionsFile -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeConditionsFile -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeStrategiesFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeStrategiesFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < strategiesArray.length; i++) { + let record = strategiesArray[i]; + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.status + "," + + record.number + "," + + record.beginRate + "," + + record.endRate + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; + filePath += '/' + fileName + + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + writeTradesFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeStrategiesFile -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeStrategiesFile -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function writeTradesFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeTradesFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < tradesArray.length; i++) { + + let record = tradesArray[i]; + if (record.stopRate === undefined) { record.stopRate = 0 } + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.status + "," + + record.lastTradeROI + "," + + record.beginRate + "," + + record.endRate + "," + + record.exitType + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; + filePath += '/' + fileName + + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + callBackFunction(global.DEFAULT_OK_RESPONSE); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeTradesFile -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeTradesFile -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + } + + function writeDailyFiles() { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> Entering function."); } + + writeRecordsFile(); + + /* TODO : NEXT function is a work in progress, not used today */ + function writeFinalResults() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeFinalResults -> Entering function."); } + + if ( // We only write this file if we are at the head of the market. + Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS + !== + Math.trunc((new Date()).valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS + ) { writeRecordsFile(); + return; + } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < recordsArray.length; i++) { + + let record = recordsArray[i]; + + /* Will only add to the file the records of the current day */ + + if (record.begin < currentDay.valueOf()) { continue; } + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.type + "," + + record.marketRate + "," + + record.amount + "," + + record.balanceA + "," + + record.balanceB + "," + + record.profit + "," + + record.lastTradeProfitLoss + "," + + record.stopLoss + "," + + record.roundtrips + "," + + record.hits + "," + + record.fails + "," + + record.hitRatio + "," + + record.ROI + "," + + record.periods + "," + + record.days + "," + + record.anualizedRateOfReturn + "," + + record.positionRate + "," + + record.lastTradeROI + "," + + record.strategy + "," + + record.strategyStageNumber + "," + + record.takeProfit + "," + + record.stopLossPhase + "," + + record.takeProfitPhase + "," + + JSON.stringify(record.executionRecord) + "," + + record.positionSize + "," + + record.initialBalanceA + "," + + record.minimumBalanceA + "," + + record.maximumBalanceA + "," + + record.initialBalanceB + "," + + record.minimumBalanceB + "," + + record.maximumBalanceB + "," + + record.baseAsset + "," + + record.positionPeriods + "," + + record.positionDays + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeFinalResults -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - function writeRecordsFile() { + fileContent = "[" + fileContent + "]"; - try { + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> Entering function."); } + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel; + filePath += '/' + fileName - let separator = ""; - let fileRecordCounter = 0; + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - let fileContent = ""; + function onFileCreated(err) { - for (let i = 0; i < recordsArray.length; i++) { + try { - let record = recordsArray[i]; + 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); } - /* Will only add to the file the records of the current day */ + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - if (record.begin < currentDay.valueOf()) { continue; } + 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.assetA + "_" + market.assetB); - 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.positionPeriods + "," + - record.positionDays + "]"; + callBackFunction(err); + return; - if (separator === "") { separator = ","; } + } - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; + writeRecordsFile(); } - - writeConditionsFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } } } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - function writeConditionsFile() { + function writeRecordsFile() { - try { + try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeRecordsFile -> Entering function."); } - let separator = ""; - let fileRecordCounter = 0; + let separator = ""; + let fileRecordCounter = 0; - let fileContent = ""; + let fileContent = ""; - for (let i = 0; i < conditionsArray.length; i++) { + for (let i = 0; i < recordsArray.length; i++) { - let record = conditionsArray[i]; + let record = recordsArray[i]; - /* Will only add to the file the records of the current day */ + /* Will only add to the file the records of the current day */ - if (record.begin < currentDay.valueOf()) { continue; } + if (record.begin < currentDay.valueOf()) { continue; } - let conditions = ""; - let conditionsSeparator = ""; + 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.positionPeriods + "," + + record.positionDays + "]"; - /* Will only add to the file the records of the current day */ + if (separator === "") { separator = ","; } - if (record.begin < currentDay.valueOf()) { continue; } + fileRecordCounter++; - for (let j = 0; j < record.length - 3; j++) { - conditions = conditions + conditionsSeparator + record[j]; - if (conditionsSeparator === "") { conditionsSeparator = ","; } } - conditions = conditions + conditionsSeparator + '[' + record[record.length - 3] + ']'; // The last item contains an Array of condition values. - conditions = conditions + conditionsSeparator + '[' + record[record.length - 2] + ']'; // The last item contains an Array of formulaErrors. - conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of formulaValues. + fileContent = "[" + fileContent + "]"; - fileContent = fileContent + separator + '[' + conditions + ']'; + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - if (separator === "") { separator = ","; } + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; + filePath += '/' + fileName - fileRecordCounter++; + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - } + function onFileCreated(err) { - fileContent = "[" + fileContent + "]"; - fileContent = "[" + JSON.stringify(tradingSystem) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]"; + try { - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> fileContent = " + fileContent); } - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; - filePath += '/' + fileName + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - function onFileCreated(err) { + callBackFunction(err); + return; - try { + } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; + writeConditionsFile(); } - - writeStrategiesFile(); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeRecordsFile -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } } } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function writeStrategiesFile() { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> Entering function."); } - - let separator = ""; - let fileRecordCounter = 0; - - let fileContent = ""; - - for (let i = 0; i < strategiesArray.length; i++) { - let record = strategiesArray[i]; - - /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends - at the current date. */ - - if (record.end < currentDay.valueOf()) { continue; } - - fileContent = fileContent + separator + '[' + - record.begin + "," + - record.end + "," + - record.status + "," + - record.number + "," + - record.beginRate + "," + - record.endRate + "]"; - - if (separator === "") { separator = ","; } - - fileRecordCounter++; - + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeRecordsFile -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); } + } - fileContent = "[" + fileContent + "]"; + function writeConditionsFile() { - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + try { - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; - filePath += '/' + fileName + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeConditionsFile -> Entering function."); } - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + let separator = ""; + let fileRecordCounter = 0; - function onFileCreated(err) { + let fileContent = ""; - try { + for (let i = 0; i < conditionsArray.length; i++) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> onFileCreated -> fileContent = " + fileContent); } + let record = conditionsArray[i]; - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + /* Will only add to the file the records of the current day */ - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + if (record.begin < currentDay.valueOf()) { continue; } - callBackFunction(err); - return; + let conditions = ""; + let conditionsSeparator = ""; + /* Will only add to the file the records of the current day */ + + if (record.begin < currentDay.valueOf()) { continue; } + + for (let j = 0; j < record.length - 3; j++) { + conditions = conditions + conditionsSeparator + record[j]; + if (conditionsSeparator === "") { conditionsSeparator = ","; } } - writeTradesFile(); + conditions = conditions + conditionsSeparator + '[' + record[record.length - 3] + ']'; // The last item contains an Array of condition values. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 2] + ']'; // The last item contains an Array of formulaErrors. + conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of formulaValues. + + fileContent = fileContent + separator + '[' + conditions + ']'; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - function writeTradesFile() { + fileContent = "[" + fileContent + "]"; + fileContent = "[" + JSON.stringify(tradingSystem) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]"; - try { + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> Entering function."); } + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; + filePath += '/' + fileName - let separator = ""; - let fileRecordCounter = 0; + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - let fileContent = ""; + function onFileCreated(err) { - for (let i = 0; i < tradesArray.length; i++) { + try { - let record = tradesArray[i]; + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> fileContent = " + fileContent); } - /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends - at the current date. */ + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - if (record.end < currentDay.valueOf()) { continue; } - if (record.stopRate === undefined) { record.stopRate = 0 } + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - fileContent = fileContent + separator + '[' + - record.begin + "," + - record.end + "," + - record.status + "," + - record.lastTradeROI + "," + - record.beginRate + "," + - record.endRate + "," + - record.exitType + "]"; + callBackFunction(err); + return; - if (separator === "") { separator = ","; } + } - fileRecordCounter++; - - } - - fileContent = "[" + fileContent + "]"; - - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); - let fileName = '' + market.assetA + '_' + market.assetB + '.json'; - - let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; - filePath += '/' + fileName - - fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); - - function onFileCreated(err) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> onFileCreated -> fileContent = " + fileContent); } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.stack); - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); - - callBackFunction(err); - return; + writeStrategiesFile(); } - - callBackFunction(global.DEFAULT_OK_RESPONSE); - - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeConditionsFile -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } } } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeConditionsFile -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); + + function writeStrategiesFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeStrategiesFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < strategiesArray.length; i++) { + let record = strategiesArray[i]; + + /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends + at the current date. */ + + if (record.end < currentDay.valueOf()) { continue; } + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.status + "," + + record.number + "," + + record.beginRate + "," + + record.endRate + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; + filePath += '/' + fileName + + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + writeTradesFile(); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeStrategiesFile -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeStrategiesFile -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } } + + function writeTradesFile() { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeTradesFile -> Entering function."); } + + let separator = ""; + let fileRecordCounter = 0; + + let fileContent = ""; + + for (let i = 0; i < tradesArray.length; i++) { + + let record = tradesArray[i]; + + /* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends + at the current date. */ + + if (record.end < currentDay.valueOf()) { continue; } + if (record.stopRate === undefined) { record.stopRate = 0 } + + fileContent = fileContent + separator + '[' + + record.begin + "," + + record.end + "," + + record.status + "," + + record.lastTradeROI + "," + + record.beginRate + "," + + record.endRate + "," + + record.exitType + "]"; + + if (separator === "") { separator = ","; } + + fileRecordCounter++; + + } + + fileContent = "[" + fileContent + "]"; + + let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); + let fileName = '' + market.assetA + '_' + market.assetB + '.json'; + + let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; + let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; + filePath += '/' + fileName + + fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); + + function onFileCreated(err) { + + try { + + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> Entering function."); } + if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> fileContent = " + fileContent); } + + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> err = " + err.stack); + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> filePath = " + filePath); + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + + callBackFunction(err); + return; + + } + + callBackFunction(global.DEFAULT_OK_RESPONSE); + + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeTradesFile -> onFileCreated -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeTradesFile -> err = " + err.stack); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + } - - } catch (err) { logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack); diff --git a/Project.njsproj b/Project.njsproj index 6289f096d..0351129cc 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -28,8 +28,6 @@ - - @@ -44,8 +42,6 @@ - - Code diff --git a/this.bot.config.json b/this.bot.config.json index 72f028270..f71b4eb6a 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -11,251 +11,6 @@ "profilePicture": "Jason.png", "dataSetVersion": "dataSet.V1", "processes": [ - { - "name": "Multi-Period-Market", - "description": "Produces a single file for each time period covering all the market.", - "normalWaitTime": 60000, - "retryWaitTime": 10000, - "sleepWaitTime": 3600000, - "comaWaitTime": 86400000, - "framework": { - "name": "Multi-Period-Market", - "startDate": { - "fixedDate": "2018-07-01" - }, - "endDate": {} - }, - "statusDependencies": [ - { - "devTeam": "AAMasters", - "bot": "AAJason", - "botVersion": { - "major": 1, - "minor": 0 - }, - "process": "Multi-Period-Market", - "dataSetVersion": "dataSet.V1" - }, - { - "devTeam": "AAMasters", - "bot": "AAJason", - "botVersion": { - "major": 1, - "minor": 0 - }, - "process": "Context", - "dataSetVersion": "dataSet.V1" - } - ], - "dataDependencies": [ - { - "devTeam": "AAMasters", - "bot": "AAChris", - "botVersion": { - "major": 1, - "minor": 0 - }, - "product": "Percentage-Bandwidth", - "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Market" - }, - { - "devTeam": "AAMasters", - "bot": "AAChris", - "botVersion": { - "major": 1, - "minor": 0 - }, - "product": "Bollinger-Bands", - "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Market" - }, - { - "devTeam": "AAMasters", - "bot": "AAPaula", - "botVersion": { - "major": 1, - "minor": 0 - }, - "product": "Bollinger-Standard-Channels", - "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Market" - }, - { - "devTeam": "AAMasters", - "bot": "AAPaula", - "botVersion": { - "major": 1, - "minor": 0 - }, - "product": "Bollinger-Standard-Sub-Channels", - "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Market" - }, - { - "devTeam": "AAMasters", - "bot": "AAOlivia", - "botVersion": { - "major": 1, - "minor": 0 - }, - "product": "Candles", - "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Market" - }, - { - "devTeam": "AAMasters", - "bot": "AABruce", - "botVersion": { - "major": 1, - "minor": 0 - }, - "product": "Candles", - "dataSetVersion": "dataSet.V1", - "dataSet": "One-Min" - } - ] - }, - { - "name": "Multi-Period-Daily", - "description": "Produces a Daily File at each time period.", - "normalWaitTime": 60000, - "retryWaitTime": 10000, - "sleepWaitTime": 3600000, - "comaWaitTime": 86400000, - "framework": { - "name": "Multi-Period-Daily", - "validPeriods": [ - "45-min", - "40-min", - "30-min", - "20-min", - "15-min", - "10-min", - "05-min", - "04-min", - "03-min", - "02-min", - "01-min" - ], - "startDate": { - "fixedDate": "2018-07-01" - }, - "endDate": { - "takeItFromStatusDependency": 1 - } - }, - "statusDependencies": [ - { - "devTeam": "AAMasters", - "bot": "AACharly", - "botVersion": { - "major": 1, - "minor": 0 - }, - "process": "Historic-Trades", - "dataSetVersion": "dataSet.V1" - }, - { - "devTeam": "AAMasters", - "bot": "AAOlivia", - "botVersion": { - "major": 1, - "minor": 0 - }, - "process": "Multi-Period-Daily", - "dataSetVersion": "dataSet.V1" - }, - { - "devTeam": "AAMasters", - "bot": "AAJason", - "botVersion": { - "major": 1, - "minor": 0 - }, - "process": "Multi-Period-Daily", - "dataSetVersion": "dataSet.V1" - }, - { - "devTeam": "AAMasters", - "bot": "AAJason", - "botVersion": { - "major": 1, - "minor": 0 - }, - "process": "Context", - "dataSetVersion": "dataSet.V1" - } - ], - "dataDependencies": [ - { - "devTeam": "AAMasters", - "bot": "AAChris", - "botVersion": { - "major": 1, - "minor": 0 - }, - "product": "Percentage-Bandwidth", - "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Daily" - }, - { - "devTeam": "AAMasters", - "bot": "AAChris", - "botVersion": { - "major": 1, - "minor": 0 - }, - "product": "Bollinger-Bands", - "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Daily" - }, - { - "devTeam": "AAMasters", - "bot": "AAPaula", - "botVersion": { - "major": 1, - "minor": 0 - }, - "product": "Bollinger-Standard-Channels", - "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Daily" - }, - { - "devTeam": "AAMasters", - "bot": "AAPaula", - "botVersion": { - "major": 1, - "minor": 0 - }, - "product": "Bollinger-Standard-Sub-Channels", - "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Daily" - }, - { - "devTeam": "AAMasters", - "bot": "AAOlivia", - "botVersion": { - "major": 1, - "minor": 0 - }, - "product": "Candles", - "dataSetVersion": "dataSet.V1", - "dataSet": "Multi-Period-Daily" - }, - { - "devTeam": "AAMasters", - "bot": "AABruce", - "botVersion": { - "major": 1, - "minor": 0 - }, - "product": "Candles", - "dataSetVersion": "dataSet.V1", - "dataSet": "One-Min" - } - ] - }, { "name": "Multi-Period", "description": "Produces a Daily or Market files depending on the current timePeriod.", @@ -328,6 +83,61 @@ } ], "dataDependencies": [ + { + "devTeam": "AAMasters", + "bot": "AAChris", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Percentage-Bandwidth", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Market" + }, + { + "devTeam": "AAMasters", + "bot": "AAChris", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Bollinger-Bands", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Market" + }, + { + "devTeam": "AAMasters", + "bot": "AAPaula", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Bollinger-Standard-Channels", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Market" + }, + { + "devTeam": "AAMasters", + "bot": "AAPaula", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Bollinger-Standard-Sub-Channels", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Market" + }, + { + "devTeam": "AAMasters", + "bot": "AAOlivia", + "botVersion": { + "major": 1, + "minor": 0 + }, + "product": "Candles", + "dataSetVersion": "dataSet.V1", + "dataSet": "Multi-Period-Market" + }, { "devTeam": "AAMasters", "bot": "AAChris", From c0294e4288a63ed8c4c637866d66c8206e2059b8 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 4 Sep 2019 09:23:45 +0200 Subject: [PATCH 201/244] Removing dependence to Bruce --- this.bot.config.json | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/this.bot.config.json b/this.bot.config.json index f71b4eb6a..2566c3c59 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -192,17 +192,6 @@ "product": "Candles", "dataSetVersion": "dataSet.V1", "dataSet": "Multi-Period-Daily" - }, - { - "devTeam": "AAMasters", - "bot": "AABruce", - "botVersion": { - "major": 1, - "minor": 0 - }, - "product": "Candles", - "dataSetVersion": "dataSet.V1", - "dataSet": "One-Min" } ] } @@ -493,22 +482,5 @@ "moduleName": "SimulationExecution" } } - ], - "marketRateProvider": { - "devTeam": "AAMasters", - "bot": "AABruce", - "host": { - "url": "https://demo-dev.superalgos.org/", - "storage": "localStorage", - "container": "aamasters", - "accessKey": "" - }, - "botVersion": { - "major": 1, - "minor": 0 - }, - "product": "Candles", - "dataSet": "One-Min", - "dataSetVersion": "dataSet.V1" - } + ] } \ No newline at end of file From 04c325675e558cc871e8a706718f8f36f9a07681 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 11 Sep 2019 09:35:39 +0200 Subject: [PATCH 202/244] Logging Improved --- this.bot.config.json | 1 + 1 file changed, 1 insertion(+) diff --git a/this.bot.config.json b/this.bot.config.json index 2566c3c59..d2d71066c 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -14,6 +14,7 @@ { "name": "Multi-Period", "description": "Produces a Daily or Market files depending on the current timePeriod.", + "deadWaitTime": 90000, "normalWaitTime": 60000, "retryWaitTime": 10000, "sleepWaitTime": 3600000, From 2952b333460102bdaeaec48fea40fe2f275ae54e Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 11 Sep 2019 17:04:16 +0200 Subject: [PATCH 203/244] Config updated --- this.bot.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/this.bot.config.json b/this.bot.config.json index d2d71066c..5d32b801a 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -15,7 +15,7 @@ "name": "Multi-Period", "description": "Produces a Daily or Market files depending on the current timePeriod.", "deadWaitTime": 90000, - "normalWaitTime": 60000, + "normalWaitTime": 5000, "retryWaitTime": 10000, "sleepWaitTime": 3600000, "comaWaitTime": 86400000, From 707c37f08ca92eff021c348ed8b78fe376ca1490 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 12 Sep 2019 10:08:06 +0200 Subject: [PATCH 204/244] Needed config --- this.bot.config.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/this.bot.config.json b/this.bot.config.json index 5d32b801a..48109984a 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -14,6 +14,11 @@ { "name": "Multi-Period", "description": "Produces a Daily or Market files depending on the current timePeriod.", + "startMode": { + "userDefined": { + "run": "true" + } + }, "deadWaitTime": 90000, "normalWaitTime": 5000, "retryWaitTime": 10000, From 2fb6e6e7b93abbebd10b25d4550374029fbf1a77 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 12 Sep 2019 16:29:29 +0200 Subject: [PATCH 205/244] Adding Distance in Periods Counters --- Commons.js | 137 ++++++++++++++++++++++++++++++++++++++- Multi-Period/User.Bot.js | 6 +- 2 files changed, 140 insertions(+), 3 deletions(-) diff --git a/Commons.js b/Commons.js index 170498503..2d335e8dd 100644 --- a/Commons.js +++ b/Commons.js @@ -305,6 +305,15 @@ let periods = 0; let positionPeriods = 0; + /* Usefull counters for conditions and formulas */ + + let distanceToLast = { + triggerOn: 0, + triggerOff: 0, + takePosition: 0, + closePosition: 0 + } + /* Message to the Simulation Executor */ let orderId = 0; @@ -361,6 +370,13 @@ yesterday.periods = 0; yesterday.positionPeriods = 0; + yesterday.distanceToLast = { + triggerOn: 0, + triggerOff: 0, + takePosition: 0, + closePosition: 0 + } + yesterday.orderId = 0; yesterday.messageId = 0; @@ -419,6 +435,13 @@ interExecutionMemory.periods = 0; interExecutionMemory.positionPeriods = 0; + interExecutionMemory.distanceToLast = { + triggerOn: 0, + triggerOff: 0, + takePosition: 0, + closePosition: 0 + } + interExecutionMemory.orderId = 0; interExecutionMemory.messageId = 0; @@ -486,6 +509,11 @@ periods = interExecutionMemory.periods; positionPeriods = interExecutionMemory.positionPeriods; + distanceToLast.triggerOn = interExecutionMemory.distanceToLast.triggerOn + distanceToLast.triggerOff = interExecutionMemory.distanceToLast.triggerOff + distanceToLast.takePosition = interExecutionMemory.distanceToLast.takePosition + distanceToLast.closePosition = interExecutionMemory.distanceToLast.closePosition + orderId = interExecutionMemory.orderId; // to be deprecated messageId = interExecutionMemory.messageId; // to be deprecated @@ -539,6 +567,11 @@ yesterday.periods = periods; yesterday.positionPeriods = positionPeriods; + yesterday.distanceToLast.triggerOn = distanceToLast.triggerOn + yesterday.distanceToLast.triggerOff = distanceToLast.triggerOff + yesterday.distanceToLast.takePosition = distanceToLast.takePosition + yesterday.distanceToLast.closePosition = distanceToLast.closePosition + yesterday.hitRatio = hitRatio; yesterday.ROI = ROI; yesterday.anualizedRateOfReturn = anualizedRateOfReturn; @@ -1238,6 +1271,14 @@ } } + distanceToLast.triggerOn = 1; + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.distanceToLast.triggerOn = distanceToLast.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; } @@ -1305,6 +1346,14 @@ } } + distanceToLast.triggerOff = 1; + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.distanceToLast.triggerOff = distanceToLast.triggerOff + } + } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Switching to No Stage because conditions at the Trigger Off Event were met."); } break; } @@ -1636,6 +1685,55 @@ } } + /* Keeping Distance Counters Up-to-date */ + if ( + distanceToLast.triggerOn > 0 // with this we avoind counting before the first event happens. + ) { + distanceToLast.triggerOn++; + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.distanceToLast.triggerOn = distanceToLast.triggerOn + } + } + } + + if ( + distanceToLast.triggerOff > 0 // with this we avoind counting before the first event happens. + ) { + distanceToLast.triggerOff++; + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.distanceToLast.triggerOff = distanceToLast.triggerOff + } + } + } + + if ( + distanceToLast.takePosition > 0 // with this we avoind counting before the first event happens. + ) { + distanceToLast.takePosition++; + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.distanceToLast.takePosition = distanceToLast.takePosition + } + } + } + + if ( + distanceToLast.closePosition > 0 // with this we avoind counting before the first event happens. + ) { + distanceToLast.closePosition++; + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.distanceToLast.takePosition = distanceToLast.closePosition + } + } + } + /* Checking if Stop or Take Profit were hit */ if ( (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') && @@ -1820,6 +1918,15 @@ takePositionNow = false if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> takePositionNow -> Entering code block."); } + /* Inicializing this counter */ + distanceToLast.takePosition = 1; + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.distanceToLast.takePosition = distanceToLast.takePosition + } + } + /* Position size and rate */ let strategy = tradingSystem.strategies[currentStrategyIndex]; @@ -2106,6 +2213,15 @@ closePositionNow = false + /* Inicializing this counter */ + distanceToLast.closePosition = 1; + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.distanceToLast.closePosition = distanceToLast.closePosition + } + } + /* Position size and rate */ let strategy = tradingSystem.strategies[currentStrategyIndex]; @@ -2396,6 +2512,14 @@ timerToCloseStage = 0 + distanceToLast.triggerOff = 1; + + if (processingDailyFiles) { + if (positionedAtYesterday) { + yesterday.distanceToLast.triggerOff = distanceToLast.triggerOff + } + } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing the Closing Stage -> Exiting Close Stage."); } } else { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Closing the Closing Stage -> Waiting for timer."); } @@ -2489,7 +2613,11 @@ maximumBalanceB: maximumBalanceB, baseAsset: quotedBaseAsset, positionPeriods: positionPeriods, - positionDays: positionDays + positionDays: positionDays, + distanceToLastTriggerOn: distanceToLast.triggerOn, + distanceToLastTriggerOff: distanceToLast.triggerOff, + distanceToLastTakePosition: distanceToLast.takePosition, + distanceToLastClosePosition: distanceToLast.closePosition } recordsArray.push(simulationRecord); @@ -2644,7 +2772,12 @@ interExecutionMemory.fails = yesterday.fails; interExecutionMemory.hits = yesterday.hits; interExecutionMemory.periods = yesterday.periods; - interExecutionMemory.positionPeriods = yesterday.positionPeriods; + interExecutionMemory.positionPeriods = yesterday.positionPeriods; + + interExecutionMemory.distanceToLast.triggerOn = yesterday.distanceToLast.triggerOn + interExecutionMemory.distanceToLast.triggerOff = yesterday.distanceToLast.triggerOff + interExecutionMemory.distanceToLast.takePosition = yesterday.distanceToLast.takePosition + interExecutionMemory.distanceToLast.closePosition = yesterday.distanceToLast.closePosition interExecutionMemory.messageId = interExecutionMemory.messageId + yesterday.messageId; interExecutionMemory.orderId = interExecutionMemory.orderId + yesterday.orderId; diff --git a/Multi-Period/User.Bot.js b/Multi-Period/User.Bot.js index 72a6e93d0..7e8d47bfb 100644 --- a/Multi-Period/User.Bot.js +++ b/Multi-Period/User.Bot.js @@ -220,7 +220,11 @@ record.maximumBalanceB + "," + record.baseAsset + "," + record.positionPeriods + "," + - record.positionDays + "]"; + record.positionDays + "," + + record.distanceToLastTriggerOn + "," + + record.distanceToLastTriggerOff + "," + + record.distanceToLastTakePosition + "," + + record.distanceToLastClosePosition + "]"; if (separator === "") { separator = ","; } From 363ce4d302488f6b590649ed17cc67f1efa96a0b Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 17 Sep 2019 16:02:30 +0200 Subject: [PATCH 206/244] Bug Fixes and Improvements to better respond to UI --- Commons.js | 28 +++++++++++++++++++++++++++- Multi-Period/User.Bot.js | 6 ++++++ this.bot.config.json | 2 +- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Commons.js b/Commons.js index 2d335e8dd..86c24b94e 100644 --- a/Commons.js +++ b/Commons.js @@ -590,6 +590,11 @@ /* Main Simulation Loop: We go thourgh all the candles at this time period. */ let i + + /* For Loop Level heartbeat */ + let loopingDay + let previousLoopingDay + initializeLoop() function initializeLoop() { @@ -666,6 +671,17 @@ last: candle.close } + /* We will produce a simulation level heartbeat in order to inform the user this is running. */ + + loopingDay = new Date(Math.trunc(candle.begin / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) + if (loopingDay.valueOf() !== previousLoopingDay) { + if (FULL_LOG === true) {logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Simulation Loop # " + i + " @ " + (loopingDay.toLocaleString()))} + console.log("Jason -> " + MODULE_NAME + " -> runSimulation -> loop -> Simulation Loop # " + i + " @ " + (loopingDay.toLocaleString())) + + bot.hearBeat() // tell the world we are alive and doing well + } + previousLoopingDay = loopingDay.valueOf() + /* If any of the needed indicators is missing, then that period is not calculated */ if (candle.end < initialDate.valueOf()) { @@ -2708,9 +2724,19 @@ function controlLoop() { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> controlLoop -> Entering function."); } + + /* Checking if we should continue processing this loop or not.*/ + if (global.STOP_PROCESSING === 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.") + afterLoop() + return + } + i++ if (i < candles.length) { - process.nextTick(loop) + // process.nextTick(loop) + setTimeout(loop, 100) } else { afterLoop() } diff --git a/Multi-Period/User.Bot.js b/Multi-Period/User.Bot.js index 7e8d47bfb..7d818ef4e 100644 --- a/Multi-Period/User.Bot.js +++ b/Multi-Period/User.Bot.js @@ -481,6 +481,9 @@ } + /* Emit event that signals that simulation files were updated */ + global.SYSTEM_EVENT_HANDLER.raiseEvent('Jason-Multi-Period', 'Simulation Files Updated') + callBackFunction(global.DEFAULT_OK_RESPONSE); } @@ -956,6 +959,9 @@ } + /* Emit event that signals that simulation files were updated */ + global.SYSTEM_EVENT_HANDLER.raiseEvent('Jason-Multi-Period', 'Simulation Files Updated') + callBackFunction(global.DEFAULT_OK_RESPONSE); } diff --git a/this.bot.config.json b/this.bot.config.json index 48109984a..68d242ab3 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -40,7 +40,7 @@ "01-min" ], "startDate": { - "fixedDate": "2018-07-01" + "takeItFromStatusDependency": 2 }, "endDate": { "takeItFromStatusDependency": 1 From e96ce4e484b8b90b435e65a15c14df29c740a3df Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 17 Sep 2019 19:28:53 +0200 Subject: [PATCH 207/244] Memory Leak Bug Fixed --- Commons.js | 14 ++++++++++++-- Multi-Period/User.Bot.js | 11 ++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Commons.js b/Commons.js index 86c24b94e..66931e537 100644 --- a/Commons.js +++ b/Commons.js @@ -8,6 +8,7 @@ const GMT_SECONDS = ':00.000 GMT+0000'; let thisObject = { + finalize: finalize, runSimulation: runSimulation, buildPercentageBandwidthArray: buildPercentageBandwidthArray, buildBollingerBandsArray: buildBollingerBandsArray, @@ -28,6 +29,15 @@ return thisObject; + function finalize() { + percentageBandwidthAt = undefined + bollingerBandsAt = undefined + bollingerChannelsAt = undefined + bollingerSubChannelsAt = undefined + candlesAt = undefined + thisObject = undefined + } + async function runSimulation( timePeriod, timePeriodLabel, @@ -2735,8 +2745,8 @@ i++ if (i < candles.length) { - // process.nextTick(loop) - setTimeout(loop, 100) + process.nextTick(loop) + //setTimeout(loop, 100) } else { afterLoop() } diff --git a/Multi-Period/User.Bot.js b/Multi-Period/User.Bot.js index 7d818ef4e..95d9b8ba8 100644 --- a/Multi-Period/User.Bot.js +++ b/Multi-Period/User.Bot.js @@ -12,10 +12,11 @@ const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; - const commons = COMMONS.newCommons(bot, logger, UTILITIES); + let commons = COMMONS.newCommons(bot, logger, UTILITIES); thisObject = { initialize: initialize, + finalize: finalize, start: start }; @@ -44,6 +45,14 @@ } } + function finalize() { + commons.finalize() + commons = undefined + utilities = undefined + assistant = undefined + thisObject = undefined + } + function start(multiPeriodDataFiles, timePeriod, timePeriodLabel, currentDay, startDate, endDate, interExecutionMemory, callBackFunction) { try { From 76bf04167877d5c670bb3b4ac534c0d80698bed6 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 18 Sep 2019 10:27:52 +0200 Subject: [PATCH 208/244] removing this that added time --- Commons.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Commons.js b/Commons.js index 66931e537..0652c164f 100644 --- a/Commons.js +++ b/Commons.js @@ -2746,7 +2746,6 @@ i++ if (i < candles.length) { process.nextTick(loop) - //setTimeout(loop, 100) } else { afterLoop() } From 5d573f66f9f0b116218c4ca5d1cf65065177c523 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 18 Sep 2019 12:08:20 +0200 Subject: [PATCH 209/244] Standarizing Type --- this.bot.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/this.bot.config.json b/this.bot.config.json index 68d242ab3..a6b350aba 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -1,7 +1,7 @@ { "displayName": "Jason", "codeName": "AAJason", - "type": "Trading-Engine", + "type": "Trading Engine", "version": { "major": 1, "minor": 0, From 516668902ce8850ebac52a7f07c1663b4913f49e Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 19 Sep 2019 15:23:18 +0200 Subject: [PATCH 210/244] no health check for now --- this.bot.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/this.bot.config.json b/this.bot.config.json index a6b350aba..344afdb7f 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -19,7 +19,7 @@ "run": "true" } }, - "deadWaitTime": 90000, + "deadWaitTime": 0, "normalWaitTime": 5000, "retryWaitTime": 10000, "sleepWaitTime": 3600000, From 8f2895e4611a67650882f27e12fa711706ffe9d7 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 21 Sep 2019 12:23:34 +0200 Subject: [PATCH 211/244] Bug Fixed when running live without updating the datasets --- Commons.js | 89 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/Commons.js b/Commons.js index 0652c164f..21dc42ae5 100644 --- a/Commons.js +++ b/Commons.js @@ -619,6 +619,10 @@ i = Math.trunc(amount) if (i < 0) { i = 0 } + if (i > candles.length - 1) { + /* This will happen when the initialDate is beyond the last candle available, meaning that the dataSet needs to be updated with more up-to-date data. */ + i = candles.length - 1 + } loop() } @@ -629,10 +633,10 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Processing candle # " + i); } let candle = candles[i]; - let percentageBandwidth = getElement(percentageBandwidthArray, candle); - let bollingerBand = getElement(bollingerBandsArray, candle); - let bollingerChannel = getElement(bollingerChannelsArray, candle); - let bollingerSubChannel = getElement(bollingerSubChannelsArray, candle); + let percentageBandwidth = getElement(percentageBandwidthArray, candle, 'Current' + '-' + 'Percentage Bandwidth'); + let bollingerBand = getElement(bollingerBandsArray, candle, 'Current' + '-' + 'Bollinger Band'); + let bollingerChannel = getElement(bollingerChannelsArray, candle, 'Current' + '-' + 'Bollnger Channel'); + let bollingerSubChannel = getElement(bollingerSubChannelsArray, candle, 'Current' + '-' + 'Bollnger Sub Channel'); let chart = {} @@ -643,11 +647,11 @@ let propertyName = 'at' + mapKey.replace('-', ''); chart[propertyName] = {} - chart[propertyName].candle = getElement(candlesAt[mapKey], candle); - chart[propertyName].percentageBandwidth = getElement(percentageBandwidthAt[mapKey], candle); - chart[propertyName].bollingerBand = getElement(bollingerBandsAt[mapKey], candle); - chart[propertyName].bollingerChannel = getElement(bollingerChannelsAt[mapKey], candle); - chart[propertyName].bollingerSubChannel = getElement(bollingerSubChannelsAt[mapKey], candle); + chart[propertyName].candle = getElement(candlesAt[mapKey], candle, 'Daily' + '-' + mapKey + '-' + 'Candles'); + chart[propertyName].percentageBandwidth = getElement(percentageBandwidthAt[mapKey], candle, 'Daily' + '-' + mapKey + '-' + 'Percentage Bandwidth'); + chart[propertyName].bollingerBand = getElement(bollingerBandsAt[mapKey], candle, 'Daily' + '-' + mapKey + '-' + 'Bollinger Band'); + chart[propertyName].bollingerChannel = getElement(bollingerChannelsAt[mapKey], candle, 'Daily' + '-' + mapKey + '-' + 'Bollnger Channel'); + chart[propertyName].bollingerSubChannel = getElement(bollingerSubChannelsAt[mapKey], candle, 'Daily' + '-' + mapKey + '-' + 'Bollnger Sub Channel'); } } @@ -657,11 +661,11 @@ let propertyName = 'at' + mapKey.replace('-', ''); chart[propertyName] = {} - chart[propertyName].candle = getElement(candlesAt[mapKey], candle); - chart[propertyName].percentageBandwidth = getElement(percentageBandwidthAt[mapKey], candle); - chart[propertyName].bollingerBand = getElement(bollingerBandsAt[mapKey], candle); - chart[propertyName].bollingerChannel = getElement(bollingerChannelsAt[mapKey], candle); - chart[propertyName].bollingerSubChannel = getElement(bollingerSubChannelsAt[mapKey], candle); + chart[propertyName].candle = getElement(candlesAt[mapKey], candle, 'Market' + '-' + mapKey + '-' + 'Candles'); + chart[propertyName].percentageBandwidth = getElement(percentageBandwidthAt[mapKey], candle, 'Market' + '-' + mapKey + '-' + 'Percentage Bandwidth'); + chart[propertyName].bollingerBand = getElement(bollingerBandsAt[mapKey], candle, 'Market' + '-' + mapKey + '-' + 'Bollinger Band'); + chart[propertyName].bollingerChannel = getElement(bollingerChannelsAt[mapKey], candle, 'Market' + '-' + mapKey + '-' + 'Bollnger Channel'); + chart[propertyName].bollingerSubChannel = getElement(bollingerSubChannelsAt[mapKey], candle, 'Market' + '-' + mapKey + '-' + 'Bollnger Sub Channel'); } /* While we are processing the previous day. */ @@ -2829,37 +2833,42 @@ } - function getElement(pArray, currentCandle) { + function getElement(pArray, currentCandle, datasetName) { - let element; - for (let i = 0; i < pArray.length; i++) { - element = pArray[i]; + try { + let element; + for (let i = 0; i < pArray.length; i++) { + element = pArray[i]; - if (currentCandle.end === element.end) { // when there is an exact match at the end we take that element - return element - } else { - if ( - i > 0 && - element.end > currentCandle.end - ) - { - let previousElement = pArray[i - 1] - if (previousElement.end < currentCandle.end) { - return previousElement // If one elements goes into the future of currentCandle, then we stop and take the previous element. - } else { - return + if (currentCandle.end === element.end) { // when there is an exact match at the end we take that element + return element + } else { + if ( + i > 0 && + element.end > currentCandle.end + ) { + let previousElement = pArray[i - 1] + if (previousElement.end < currentCandle.end) { + return previousElement // If one elements goes into the future of currentCandle, then we stop and take the previous element. + } else { + return + } + } + if ( + i === pArray.length - 1 // If we reach the end of the array, then we return the last element. + && + element.end < currentCandle.end + ) { + return element } } - if ( - i === pArray.length - 1 // If we reach the end of the array, then we return the last element. - && - element.end < currentCandle.end - ) { - return element - } - } + } + return + } + catch (err) { + logger.write(MODULE_NAME, "[ERROR] runSimulation -> getElement -> datasetName = " + datasetName); + throw(err) } - return } } catch (err) { From 59ba5b1a8a2f26b546d87b86331eb17d8d0cac8e Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 22 Sep 2019 18:12:58 +0200 Subject: [PATCH 212/244] Config to raise events when updating Datasets --- this.bot.config.json | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/this.bot.config.json b/this.bot.config.json index 344afdb7f..84bc9dce1 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -24,6 +24,48 @@ "retryWaitTime": 10000, "sleepWaitTime": 3600000, "comaWaitTime": 86400000, + "updatesDatasets": [ + { + "product": "Trading-Simulation", + "dataSet": "Multi-Period-Market" + }, + { + "product": "Simulation-Conditions", + "dataSet": "Multi-Period-Market" + }, + { + "product": "Simulation-Strategies", + "dataSet": "Multi-Period-Market" + }, + { + "product": "Simulation-Trades", + "dataSet": "Multi-Period-Market" + }, + { + "product": "Live Trading History", + "dataSet": "Multi-Period-Market" + }, + { + "product": "Trading-Simulation", + "dataSet": "Multi-Period-Daily" + }, + { + "product": "Simulation-Conditions", + "dataSet": "Multi-Period-Daily" + }, + { + "product": "Simulation-Strategies", + "dataSet": "Multi-Period-Daily" + }, + { + "product": "Simulation-Trades", + "dataSet": "Multi-Period-Daily" + }, + { + "product": "Live Trading History", + "dataSet": "Multi-Period-Daily" + } + ], "framework": { "name": "Multi-Period", "validPeriods": [ From e76e3a35683947a278a7dbd3487e6a369e497e81 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 23 Sep 2019 17:22:20 +0200 Subject: [PATCH 213/244] No process helth check for now --- this.bot.config.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/this.bot.config.json b/this.bot.config.json index 84bc9dce1..19e1959bd 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -20,6 +20,7 @@ } }, "deadWaitTime": 0, + "liveWaitTime": 60000, "normalWaitTime": 5000, "retryWaitTime": 10000, "sleepWaitTime": 3600000, @@ -63,7 +64,7 @@ }, { "product": "Live Trading History", - "dataSet": "Multi-Period-Daily" + "dataSet": "Oficial History" } ], "framework": { From c643f87263d2d3fe83757c4cf4dd1fc0612ea83f Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 24 Sep 2019 11:30:29 +0200 Subject: [PATCH 214/244] Bug Fixed, using env --- Commons.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Commons.js b/Commons.js index 21dc42ae5..79963abbb 100644 --- a/Commons.js +++ b/Commons.js @@ -1993,7 +1993,7 @@ /* Check if we need to execute. */ if (i > candles.length - 10) { /* Only at the last candles makes sense to check if we are in live mode or not.*/ /* Check that we are in LIVE MODE */ - if (process.env.START_MODE === "live") { + if (bot.startMode === "Live") { /* We see if we need to put the actual order at the exchange. */ if (interExecutionMemory.executionContext !== undefined) { switch (interExecutionMemory.executionContext.status) { @@ -2257,7 +2257,7 @@ if (i > candles.length - 10) { /* Only at the last candles makes sense to check if we are in live mode or not.*/ /* Check that we are in LIVE MODE */ - if (process.env.START_MODE === "live") { + if (bot.startMode === "Live") { /* We see if we need to put the actual order at the exchange. */ if (interExecutionMemory.executionContext !== undefined) { switch (interExecutionMemory.executionContext.status) { From cc194c68c37e50e3a69748ce1f0b52f0e2d13605 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 25 Sep 2019 09:34:12 +0200 Subject: [PATCH 215/244] Issue Fixed with stopLostPhase variable displaced --- Commons.js | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Commons.js b/Commons.js index 79963abbb..b667f7dad 100644 --- a/Commons.js +++ b/Commons.js @@ -275,10 +275,10 @@ let currentStrategyIndex = -1; let strategyStage = 'No Stage'; - let stopLossPhase = 0; + let stopLossPhase = -1; let stopLossStage = 'No Stage'; - let takeProfitPhase = 0; + let takeProfitPhase = -1; let takeProfitStage = 'No Stage'; /* These 2 objects will allow us to create separate files for each one of them. */ @@ -1428,8 +1428,8 @@ strategyStage = 'Open Stage'; stopLossStage = 'Open Stage'; takeProfitStage = 'Open Stage'; - stopLossPhase = 1; - takeProfitPhase = 1; + stopLossPhase = 0; + takeProfitPhase = 0; if (processingDailyFiles) { if (positionedAtYesterday) { @@ -1480,7 +1480,7 @@ parentNode = openStage.initialDefinition initialDefinitionKey = '-' + 'initialDefinition' stageKey = 'openStage' - p = stopLossPhase - 1 + p = stopLossPhase } } } @@ -1489,7 +1489,7 @@ if (manageStage.stopLoss !== undefined) { parentNode = manageStage stageKey = 'manageStage' - p = stopLossPhase - 2 + p = stopLossPhase - 1 } } @@ -1520,7 +1520,7 @@ stopLossPhase++; stopLossStage = 'Manage Stage' - if (takeProfitPhase > 1) { strategyStage = 'Manage Stage' } + if (takeProfitPhase > 0) { strategyStage = 'Manage Stage' } if (processingDailyFiles) { if (positionedAtYesterday) { @@ -1546,16 +1546,16 @@ if (stopLossStage === 'Open Stage' && openStage !== undefined) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.stopLoss !== undefined) { - phase = openStage.initialDefinition.stopLoss.phases[stopLossPhase - 1]; - key = currentStrategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + (stopLossPhase - 1); + phase = openStage.initialDefinition.stopLoss.phases[stopLossPhase]; + key = currentStrategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + (stopLossPhase); } } } if (stopLossStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.stopLoss !== undefined) { - phase = manageStage.stopLoss.phases[stopLossPhase - 2]; - key = currentStrategyIndex + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + (stopLossPhase - 2); + phase = manageStage.stopLoss.phases[stopLossPhase - 1]; + key = currentStrategyIndex + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + (stopLossPhase - 1); } } @@ -1595,7 +1595,7 @@ parentNode = openStage.initialDefinition initialDefinitionKey = '-' + 'initialDefinition' stageKey = 'openStage' - p = takeProfitPhase - 1 + p = takeProfitPhase } } } @@ -1604,7 +1604,7 @@ if (manageStage.takeProfit !== undefined) { parentNode = manageStage stageKey = 'manageStage' - p = takeProfitPhase - 2 + p = takeProfitPhase - 1 } } @@ -1635,7 +1635,7 @@ takeProfitPhase++; takeProfitStage = 'Manage Stage' - if (stopLossPhase > 1) { strategyStage = 'Manage Stage' } + if (stopLossPhase > 0) { strategyStage = 'Manage Stage' } if (processingDailyFiles) { if (positionedAtYesterday) { @@ -1661,16 +1661,16 @@ if (takeProfitStage === 'Open Stage' && openStage !== undefined) { if (openStage.initialDefinition !== undefined) { if (openStage.initialDefinition.takeProfit !== undefined) { - phase = openStage.initialDefinition.takeProfit.phases[takeProfitPhase - 1]; - key = currentStrategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 1); + phase = openStage.initialDefinition.takeProfit.phases[takeProfitPhase]; + key = currentStrategyIndex + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + (takeProfitPhase); } } } if (takeProfitStage === 'Manage Stage' && manageStage !== undefined) { if (manageStage.takeProfit !== undefined) { - phase = manageStage.takeProfit.phases[takeProfitPhase - 2]; - key = currentStrategyIndex + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 2); + phase = manageStage.takeProfit.phases[takeProfitPhase - 1]; + key = currentStrategyIndex + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 1); } } @@ -2493,8 +2493,8 @@ timerToCloseStage = candle.begin stopLossStage = 'No Stage'; takeProfitStage = 'No Stage'; - stopLossPhase = 0; - takeProfitPhase = 0; + stopLossPhase = -1; + takeProfitPhase = -1; if (processingDailyFiles) { if (positionedAtYesterday) { From cff623114ca6bbb15d6315a85b89e2b053442f13 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 25 Sep 2019 13:15:05 +0200 Subject: [PATCH 216/244] Dates issues fixed --- Commons.js | 51 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/Commons.js b/Commons.js index b667f7dad..48748ca78 100644 --- a/Commons.js +++ b/Commons.js @@ -42,8 +42,8 @@ timePeriod, timePeriodLabel, currentDay, - startDate, - endDate, + userDefinedStartDatetime, + userDefinedEndDatetime, interExecutionMemory, assistant, callback, @@ -59,6 +59,9 @@ processingDailyFiles = true } + userDefinedStartDatetime = new Date(userDefinedStartDatetime) + userDefinedEndDatetime = new Date(userDefinedEndDatetime) + let recordsArray = []; let conditionsArray = []; let strategiesArray = []; @@ -69,8 +72,8 @@ /* Initial Default Values */ - let initialDate = startDate; - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> initialDate = " + initialDate); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> userDefinedStartDatetime = " + userDefinedStartDatetime); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> userDefinedEndDatetime = " + userDefinedEndDatetime); } const DEFAULT_BASE_ASSET_BALANCE = 1 const DEFAULT_BASE_ASSET_MINIMUN_BALANCE = 0.5 @@ -498,7 +501,7 @@ } if (currentDay) { - if (currentDay.valueOf() >= startDate.valueOf() + ONE_DAY_IN_MILISECONDS) { // Only after the first day we start grabbing the balance from this memory. + if (currentDay.valueOf() >= userDefinedStartDatetime.valueOf() + ONE_DAY_IN_MILISECONDS) { // Only after the first day we start grabbing the balance from this memory. balanceAssetA = interExecutionMemory.balanceAssetA; balanceAssetB = interExecutionMemory.balanceAssetB; @@ -613,14 +616,14 @@ /* Estimate Initial Candle */ let firstEnd = candles[0].end - let targetEnd = initialDate.valueOf() + let targetEnd = userDefinedStartDatetime.valueOf() let diff = targetEnd - firstEnd let amount = diff / timePeriod i = Math.trunc(amount) if (i < 0) { i = 0 } if (i > candles.length - 1) { - /* This will happen when the initialDate is beyond the last candle available, meaning that the dataSet needs to be updated with more up-to-date data. */ + /* This will happen when the userDefinedStartDatetime is beyond the last candle available, meaning that the dataSet needs to be updated with more up-to-date data. */ i = candles.length - 1 } @@ -633,6 +636,20 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Processing candle # " + i); } let candle = candles[i]; + + /* Not processing while out of user-defined time range */ + + if (candle.end < userDefinedStartDatetime.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Candle before the userDefinedStartDatetime."); } + controlLoop(); + return + } + if (candle.begin > userDefinedEndDatetime.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Candle after the userDefinedEndDatetime."); } + afterLoop(); + return + } + let percentageBandwidth = getElement(percentageBandwidthArray, candle, 'Current' + '-' + 'Percentage Bandwidth'); let bollingerBand = getElement(bollingerBandsArray, candle, 'Current' + '-' + 'Bollinger Band'); let bollingerChannel = getElement(bollingerChannelsArray, candle, 'Current' + '-' + 'Bollnger Channel'); @@ -697,12 +714,6 @@ previousLoopingDay = loopingDay.valueOf() /* If any of the needed indicators is missing, then that period is not calculated */ - - if (candle.end < initialDate.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Candle before the initialDate."); } - controlLoop(); - return - } if (bollingerBand === undefined) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Candle because Bollinger Band is undefined."); } controlLoop(); @@ -2046,19 +2057,19 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Entering function."); } - /* We wont take a position unless we are withing the startDate and the endDate range */ - if (startDate !== undefined) { - if (candle.end < startDate.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because current candle ends before the start date. -> startDate = " + startDate); } + /* We wont take a position unless we are withing the userDefinedStartDatetime and the userDefinedEndDatetime range */ + if (userDefinedStartDatetime !== undefined) { + if (candle.end < userDefinedStartDatetime.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because current candle ends before the start date. -> userDefinedStartDatetime = " + userDefinedStartDatetime); } takePositionAtSimulation() return; } } /* This validation is disbled for now because we do not have the correct end date at this point. - if (endDate !== undefined) { - if (candle.begin > endDate.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because current candle begins after the end date. -> endDate = " + endDate); } + if (userDefinedEndDatetime !== undefined) { + if (candle.begin > userDefinedEndDatetime.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because current candle begins after the end date. -> userDefinedEndDatetime = " + userDefinedEndDatetime); } takePositionAtSimulation() return; } From 28d290af1ff3f611870c5bb8ffb82ad69a3cd141 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 25 Sep 2019 17:37:55 +0200 Subject: [PATCH 217/244] setInmediate --- Commons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index 48748ca78..b54d04cc3 100644 --- a/Commons.js +++ b/Commons.js @@ -2760,7 +2760,7 @@ i++ if (i < candles.length) { - process.nextTick(loop) + setImmediate(loop) // This will execute the next loop in the next iteration of the NodeJs event loop allowing for other callbacks to be executed. } else { afterLoop() } From 456562f64cfd67bae9dc92b44e47440f46351ca0 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 3 Oct 2019 22:05:56 +0200 Subject: [PATCH 218/244] Session Hearbeat --- Commons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index b54d04cc3..4ebff6e45 100644 --- a/Commons.js +++ b/Commons.js @@ -709,7 +709,7 @@ if (FULL_LOG === true) {logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Simulation Loop # " + i + " @ " + (loopingDay.toLocaleString()))} console.log("Jason -> " + MODULE_NAME + " -> runSimulation -> loop -> Simulation Loop # " + i + " @ " + (loopingDay.toLocaleString())) - bot.hearBeat() // tell the world we are alive and doing well + bot.sessionHeartBeat() // tell the world we are alive and doing well } previousLoopingDay = loopingDay.valueOf() From 35b369a9a3a016d4605b5bb0ec448daa0c1985a2 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 4 Oct 2019 09:59:15 +0200 Subject: [PATCH 219/244] Code Moved to Values to Use function --- Commons.js | 229 +++++++++++------------------------------------------ 1 file changed, 45 insertions(+), 184 deletions(-) diff --git a/Commons.js b/Commons.js index 4ebff6e45..82cb0a5f0 100644 --- a/Commons.js +++ b/Commons.js @@ -75,145 +75,6 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> userDefinedStartDatetime = " + userDefinedStartDatetime); } if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> userDefinedEndDatetime = " + userDefinedEndDatetime); } - const DEFAULT_BASE_ASSET_BALANCE = 1 - const DEFAULT_BASE_ASSET_MINIMUN_BALANCE = 0.5 - const DEFAULT_BASE_ASSET_MAXIMUN_BALANCE = 2 - - let initialBalanceA = DEFAULT_BASE_ASSET_BALANCE - let minimumBalanceA = DEFAULT_BASE_ASSET_MINIMUN_BALANCE - let maximumBalanceA = DEFAULT_BASE_ASSET_MAXIMUN_BALANCE - let initialBalanceB = 0 - let minimumBalanceB = 0 - let maximumBalanceB = 0 - let baseAsset = 'BTC' - - /* Parameters Processing */ - - if (tradingSystem.parameters !== undefined) { - if (tradingSystem.parameters.baseAsset !== undefined) { - - let code - try { - code = JSON.parse(tradingSystem.parameters.baseAsset.code); - - if (code.name !== undefined) { - baseAsset = code.name; - if (baseAsset !== 'BTC' && baseAsset !== 'USDT') { - tradingSystem.parameters.baseAsset.error = baseAsset + ' is not supported. Using default: BTC.' - baseAsset = 'BTC' - } - } - - if (baseAsset === 'BTC') { - if (code.initialBalance !== undefined) { - initialBalanceA = code.initialBalance; - initialBalanceB = 0 - } else { - initialBalanceA = DEFAULT_BASE_ASSET_BALANCE; - initialBalanceB = 0 - } - if (code.minimumBalance !== undefined) { - minimumBalanceA = code.minimumBalance; - minimumBalanceB = 0 - } else { - minimumBalanceA = DEFAULT_BASE_ASSET_MINIMUN_BALANCE; - minimumBalanceB = 0 - } - if (code.maximumBalance !== undefined) { - maximumBalanceA = code.maximumBalance; - maximumBalanceB = 0 - } else { - maximumBalanceA = DEFAULT_BASE_ASSET_MAXIMUN_BALANCE; - maximumBalanceB = 0 - } - } else { - if (code.initialBalance !== undefined) { - initialBalanceB = code.initialBalance; - initialBalanceA = 0 - } else { - initialBalanceB = DEFAULT_BASE_ASSET_BALANCE; - initialBalanceA = 0 - } - if (code.minimumBalance !== undefined) { - minimumBalanceB = code.minimumBalance; - minimumBalanceA = 0 - } else { - minimumBalanceB = DEFAULT_BASE_ASSET_MINIMUN_BALANCE; - minimumBalanceA = 0 - } - if (code.maximumBalance !== undefined) { - maximumBalanceB = code.maximumBalance; - maximumBalanceA = 0 - } else { - maximumBalanceB = DEFAULT_BASE_ASSET_MAXIMUN_BALANCE; - maximumBalanceA = 0 - } - } - } catch (err) { - tradingSystem.parameters.baseAsset.error = err.message - } - } - } - - /* Slippage */ - let slippage = { // Default Values - positionRate: 0, - stopLoss: 0, - takeProfit: 0 - } - if (definition.tradingSystem !== undefined) { - if (definition.tradingSystem.parameters !== undefined) { - if (definition.tradingSystem.parameters.slippage !== undefined) { - if (definition.tradingSystem.parameters.slippage.code !== undefined) { - try { - let code = JSON.parse(definition.tradingSystem.parameters.slippage.code) - - if (code.positionRate !== undefined) { - slippage.positionRate = code.positionRate - } - if (code.stopLoss !== undefined) { - slippage.stopLoss = code.stopLoss - } - if (code.takeProfit !== undefined) { - slippage.takeProfit = code.takeProfit - } - - } catch (err) { - tradingSystem.parameters.slippage.error = err.message - } - } - } - } - } - - /* Fee Structure */ - let feeStructure = { // Default Values - maker: 0, - taker: 0 - } - - if (definition.tradingSystem !== undefined) { - if (definition.tradingSystem.parameters !== undefined) { - if (definition.tradingSystem.parameters.feeStructure !== undefined) { - if (definition.tradingSystem.parameters.feeStructure.code !== undefined) { - try { - let code = JSON.parse(definition.tradingSystem.parameters.feeStructure.code) - - if (code.maker !== undefined) { - feeStructure.maker = code.maker - } - if (code.taker !== undefined) { - feeStructure.taker = code.taker - } - - } catch (err) { - tradingSystem.parameters.feeStructure.error = err.message - } - } - } - } - } - let timerToCloseStage = 0 /* Stop Loss Management */ @@ -305,8 +166,8 @@ endRate: 0 } - let balanceAssetA = initialBalanceA; - let balanceAssetB = initialBalanceB; + let balanceAssetA = bot.VALUES_TO_USE.initialBalanceA; + let balanceAssetB = bot.VALUES_TO_USE.initialBalanceB; let lastTradeProfitLoss = 0; let profit = 0; @@ -886,7 +747,7 @@ if (openStage !== undefined) { /* Default Values*/ - if (baseAsset === 'BTC') { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { positionSize = balanceAssetA; positionRate = candle.close; } else { @@ -909,13 +770,13 @@ initialDefinition.positionSize.formula.error = err.message } if (isNaN(positionSize)) { - if (baseAsset === 'BTC') { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { positionSize = balanceAssetA; } else { positionSize = balanceAssetB; } } else { - if (baseAsset === 'BTC') { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { if (positionSize > balanceAssetA) { positionSize = balanceAssetA } } else { if (positionSize > balanceAssetB) { positionSize = balanceAssetB } @@ -936,7 +797,7 @@ initialDefinition.positionRate.formula.error = err.message } if (isNaN(positionRate)) { - if (baseAsset === 'BTC') { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { positionRate = candle.close; } else { positionRate = candle.close; @@ -1243,14 +1104,14 @@ let maximumBalance let balance - if (baseAsset === 'BTC') { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { balance = balanceAssetA - minimumBalance = minimumBalanceA - maximumBalance = maximumBalanceA + minimumBalance = bot.VALUES_TO_USE.minimumBalanceA + maximumBalance = bot.VALUES_TO_USE.maximumBalanceA } else { balance = balanceAssetB - minimumBalance = minimumBalanceB - maximumBalance = maximumBalanceB + minimumBalance = bot.VALUES_TO_USE.minimumBalanceB + maximumBalance = bot.VALUES_TO_USE.maximumBalanceB } if (balance > minimumBalance && balance < maximumBalance) { @@ -1787,7 +1648,7 @@ /* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */ - if ((baseAsset === 'BTC' && candle.max >= stopLoss) || (baseAsset !== 'BTC' && candle.min <= stopLoss)) { + if ((bot.VALUES_TO_USE.baseAsset === 'BTC' && candle.max >= stopLoss) || (bot.VALUES_TO_USE.baseAsset !== 'BTC' && candle.min <= stopLoss)) { /* Hit Point Validation @@ -1796,7 +1657,7 @@ If we take the stop loss value at those situation would be a huge distortion of facts. */ - if (baseAsset === 'BTC') { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { if (stopLoss < candle.min) { stopLoss = candle.min } } else { if (stopLoss > candle.max) { stopLoss = candle.max } @@ -1805,9 +1666,9 @@ let slippedStopLoss = stopLoss /* Apply the Slippage */ - let slippageAmount = slippedStopLoss * slippage.stopLoss / 100 + let slippageAmount = slippedStopLoss * bot.VALUES_TO_USE.slippage.stopLoss / 100 - if (baseAsset === 'BTC') { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { slippedStopLoss = slippedStopLoss + slippageAmount } else { slippedStopLoss = slippedStopLoss - slippageAmount @@ -1817,11 +1678,11 @@ let feePaid = 0 - if (baseAsset === 'BTC') { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { strategy.positionSize = balanceAssetB / finalStopLoss; strategy.positionRate = finalStopLoss; - feePaid = balanceAssetB / finalStopLoss * feeStructure.taker / 100 + feePaid = balanceAssetB / finalStopLoss * bot.VALUES_TO_USE.feeStructure.taker / 100 balanceAssetA = balanceAssetA + balanceAssetB / finalStopLoss - feePaid; balanceAssetB = 0; @@ -1829,7 +1690,7 @@ strategy.positionSize = balanceAssetA * finalStopLoss; strategy.positionRate = finalStopLoss; - feePaid = balanceAssetA * finalStopLoss * feeStructure.taker / 100 + feePaid = balanceAssetA * finalStopLoss * bot.VALUES_TO_USE.feeStructure.taker / 100 balanceAssetB = balanceAssetB + balanceAssetA * finalStopLoss - feePaid; balanceAssetA = 0; @@ -1869,7 +1730,7 @@ /* Take Profit condition: Here we verify if the Take Profit was hit or not. */ - if ((baseAsset === 'BTC' && candle.min <= takeProfit) || (baseAsset !== 'BTC' && candle.max >= takeProfit)) { + if ((bot.VALUES_TO_USE.baseAsset === 'BTC' && candle.min <= takeProfit) || (bot.VALUES_TO_USE.baseAsset !== 'BTC' && candle.max >= takeProfit)) { /* Hit Point Validation: @@ -1878,7 +1739,7 @@ If we take the stop loss value at those situation would be a huge distortion of facts. */ - if (baseAsset === 'BTC') { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { if (takeProfit > candle.max) { takeProfit = candle.max } } else { if (takeProfit < candle.min) { takeProfit = candle.min } @@ -1886,9 +1747,9 @@ let slippedTakeProfit = takeProfit /* Apply the Slippage */ - let slippageAmount = slippedTakeProfit * slippage.takeProfit / 100 + let slippageAmount = slippedTakeProfit * bot.VALUES_TO_USE.slippage.takeProfit / 100 - if (baseAsset === 'BTC') { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { slippedTakeProfit = slippedTakeProfit + slippageAmount } else { slippedTakeProfit = slippedTakeProfit - slippageAmount @@ -1898,11 +1759,11 @@ let feePaid = 0 - if (baseAsset === 'BTC') { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { strategy.positionSize = balanceAssetB / finalTakeProfit; strategy.positionRate = finalTakeProfit; - feePaid = balanceAssetB / finalTakeProfit * feeStructure.taker / 100 + feePaid = balanceAssetB / finalTakeProfit * bot.VALUES_TO_USE.feeStructure.taker / 100 balanceAssetA = balanceAssetA + balanceAssetB / finalTakeProfit - feePaid; balanceAssetB = 0; @@ -1910,7 +1771,7 @@ strategy.positionSize = balanceAssetA * finalTakeProfit; strategy.positionRate = finalTakeProfit; - feePaid = balanceAssetA * finalTakeProfit * feeStructure.taker / 100 + feePaid = balanceAssetA * finalTakeProfit * bot.VALUES_TO_USE.feeStructure.taker / 100 balanceAssetB = balanceAssetB + balanceAssetA * finalTakeProfit - feePaid; balanceAssetA = 0; @@ -1975,9 +1836,9 @@ tradePositionRate = strategy.positionRate; /* We take what was calculated at the formula and apply the slippage. */ - let slippageAmount = tradePositionRate * slippage.positionRate / 100 + let slippageAmount = tradePositionRate * bot.VALUES_TO_USE.slippage.positionRate / 100 - if (baseAsset === 'BTC') { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { tradePositionRate = tradePositionRate - slippageAmount } else { tradePositionRate = tradePositionRate + slippageAmount @@ -2118,7 +1979,7 @@ let positionDirection let availableBalance = assistant.getAvailableBalance() - if (baseAsset === 'BTC') { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { positionDirection = "sell" openPositionRate = tradePositionRate - 100 // 100 is Provisional since we do have management of orders yet @@ -2217,15 +2078,15 @@ let feePaid = 0 - if (baseAsset === 'BTC') { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { - feePaid = tradePositionSize * tradePositionRate * feeStructure.taker / 100 + feePaid = tradePositionSize * tradePositionRate * bot.VALUES_TO_USE.feeStructure.taker / 100 balanceAssetB = balanceAssetB + tradePositionSize * tradePositionRate - feePaid; balanceAssetA = balanceAssetA - tradePositionSize; } else { - feePaid = tradePositionSize / tradePositionRate * feeStructure.taker / 100 + feePaid = tradePositionSize / tradePositionRate * bot.VALUES_TO_USE.feeStructure.taker / 100 balanceAssetA = balanceAssetA + tradePositionSize / tradePositionRate - feePaid; balanceAssetB = balanceAssetB - tradePositionSize; @@ -2342,7 +2203,7 @@ let positionDirection let availableBalance = assistant.getAvailableBalance() - if (baseAsset === 'BTC') { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { positionDirection = "buy" closePositionRate = ticker.last + 100; // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff. @@ -2421,16 +2282,16 @@ } } - if (baseAsset === 'BTC') { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { lastTradeProfitLoss = balanceAssetA - previousBalanceAssetA; lastTradeROI = lastTradeProfitLoss * 100 / tradePositionSize; if (isNaN(lastTradeROI)) { lastTradeROI = 0; } - profit = balanceAssetA - initialBalanceA; + profit = balanceAssetA - bot.VALUES_TO_USE.initialBalanceA; } else { lastTradeProfitLoss = balanceAssetB - previousBalanceAssetB; lastTradeROI = lastTradeProfitLoss * 100 / tradePositionSize; if (isNaN(lastTradeROI)) { lastTradeROI = 0; } - profit = balanceAssetB - initialBalanceB; + profit = balanceAssetB - bot.VALUES_TO_USE.initialBalanceB; } if (processingDailyFiles) { @@ -2468,12 +2329,12 @@ } } - if (baseAsset === 'BTC') { - ROI = (initialBalanceA + profit) / initialBalanceA - 1; + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { + ROI = (bot.VALUES_TO_USE.initialBalanceA + profit) / bot.VALUES_TO_USE.initialBalanceA - 1; hitRatio = hits / roundtrips; anualizedRateOfReturn = ROI / days * 365; } else { - ROI = (initialBalanceB + profit) / initialBalanceB - 1; + ROI = (bot.VALUES_TO_USE.initialBalanceB + profit) / bot.VALUES_TO_USE.initialBalanceB - 1; hitRatio = hits / roundtrips; anualizedRateOfReturn = ROI / days * 365; } @@ -2616,7 +2477,7 @@ balanceAssetB = Number.MAX_SAFE_INTEGER } - let quotedBaseAsset = '"' + baseAsset + '"' + let quotedBaseAsset = '"' + bot.VALUES_TO_USE.baseAsset + '"' simulationRecord = { begin: candle.begin, @@ -2646,12 +2507,12 @@ takeProfitPhase: takeProfitPhase, executionRecord: '', positionSize: tradePositionSize, - initialBalanceA: initialBalanceA, - minimumBalanceA: minimumBalanceA, - maximumBalanceA: maximumBalanceA, - initialBalanceB: initialBalanceB, - minimumBalanceB: minimumBalanceB, - maximumBalanceB: maximumBalanceB, + initialBalanceA: bot.VALUES_TO_USE.initialBalanceA, + minimumBalanceA: bot.VALUES_TO_USE.minimumBalanceA, + maximumBalanceA: bot.VALUES_TO_USE.maximumBalanceA, + initialBalanceB: bot.VALUES_TO_USE.initialBalanceB, + minimumBalanceB: bot.VALUES_TO_USE.minimumBalanceB, + maximumBalanceB: bot.VALUES_TO_USE.maximumBalanceB, baseAsset: quotedBaseAsset, positionPeriods: positionPeriods, positionDays: positionDays, From 7c697fbfb5adcff6c5f0045543f382b041058567 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 4 Oct 2019 10:49:09 +0200 Subject: [PATCH 220/244] Better Handling of timeRange --- Commons.js | 37 ++++++++++++++++--------------------- Multi-Period/User.Bot.js | 4 +--- 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/Commons.js b/Commons.js index 82cb0a5f0..43d192be4 100644 --- a/Commons.js +++ b/Commons.js @@ -42,8 +42,6 @@ timePeriod, timePeriodLabel, currentDay, - userDefinedStartDatetime, - userDefinedEndDatetime, interExecutionMemory, assistant, callback, @@ -59,9 +57,6 @@ processingDailyFiles = true } - userDefinedStartDatetime = new Date(userDefinedStartDatetime) - userDefinedEndDatetime = new Date(userDefinedEndDatetime) - let recordsArray = []; let conditionsArray = []; let strategiesArray = []; @@ -72,8 +67,8 @@ /* Initial Default Values */ - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> userDefinedStartDatetime = " + userDefinedStartDatetime); } - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> userDefinedEndDatetime = " + userDefinedEndDatetime); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> bot.VALUES_TO_USE.timeRange.initialDatetime = " + bot.VALUES_TO_USE.timeRange.initialDatetime); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> bot.VALUES_TO_USE.timeRange.finalDatetime = " + bot.VALUES_TO_USE.timeRange.finalDatetime); } let timerToCloseStage = 0 @@ -362,7 +357,7 @@ } if (currentDay) { - if (currentDay.valueOf() >= userDefinedStartDatetime.valueOf() + ONE_DAY_IN_MILISECONDS) { // Only after the first day we start grabbing the balance from this memory. + if (currentDay.valueOf() >= bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf() + ONE_DAY_IN_MILISECONDS) { // Only after the first day we start grabbing the balance from this memory. balanceAssetA = interExecutionMemory.balanceAssetA; balanceAssetB = interExecutionMemory.balanceAssetB; @@ -477,14 +472,14 @@ /* Estimate Initial Candle */ let firstEnd = candles[0].end - let targetEnd = userDefinedStartDatetime.valueOf() + let targetEnd = bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf() let diff = targetEnd - firstEnd let amount = diff / timePeriod i = Math.trunc(amount) if (i < 0) { i = 0 } if (i > candles.length - 1) { - /* This will happen when the userDefinedStartDatetime is beyond the last candle available, meaning that the dataSet needs to be updated with more up-to-date data. */ + /* This will happen when the bot.VALUES_TO_USE.timeRange.initialDatetime is beyond the last candle available, meaning that the dataSet needs to be updated with more up-to-date data. */ i = candles.length - 1 } @@ -500,13 +495,13 @@ /* Not processing while out of user-defined time range */ - if (candle.end < userDefinedStartDatetime.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Candle before the userDefinedStartDatetime."); } + if (candle.end < bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Candle before the bot.VALUES_TO_USE.timeRange.initialDatetime."); } controlLoop(); return } - if (candle.begin > userDefinedEndDatetime.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Candle after the userDefinedEndDatetime."); } + if (candle.begin > bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Skipping Candle after the bot.VALUES_TO_USE.timeRange.finalDatetime."); } afterLoop(); return } @@ -1918,19 +1913,19 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Entering function."); } - /* We wont take a position unless we are withing the userDefinedStartDatetime and the userDefinedEndDatetime range */ - if (userDefinedStartDatetime !== undefined) { - if (candle.end < userDefinedStartDatetime.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because current candle ends before the start date. -> userDefinedStartDatetime = " + userDefinedStartDatetime); } + /* We wont take a position unless we are withing the bot.VALUES_TO_USE.timeRange.initialDatetime and the bot.VALUES_TO_USE.timeRange.finalDatetime range */ + if (bot.VALUES_TO_USE.timeRange.initialDatetime !== undefined) { + if (candle.end < bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> putOpeningOrder -> Not placing the trade at the exchange because current candle ends before the start date. -> bot.VALUES_TO_USE.timeRange.initialDatetime = " + bot.VALUES_TO_USE.timeRange.initialDatetime); } takePositionAtSimulation() return; } } /* This validation is disbled for now because we do not have the correct end date at this point. - if (userDefinedEndDatetime !== undefined) { - if (candle.begin > userDefinedEndDatetime.valueOf()) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because current candle begins after the end date. -> userDefinedEndDatetime = " + userDefinedEndDatetime); } + if (bot.VALUES_TO_USE.timeRange.finalDatetime !== undefined) { + if (candle.begin > bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf()) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because current candle begins after the end date. -> bot.VALUES_TO_USE.timeRange.finalDatetime = " + bot.VALUES_TO_USE.timeRange.finalDatetime); } takePositionAtSimulation() return; } diff --git a/Multi-Period/User.Bot.js b/Multi-Period/User.Bot.js index 95d9b8ba8..44e6d77f6 100644 --- a/Multi-Period/User.Bot.js +++ b/Multi-Period/User.Bot.js @@ -53,7 +53,7 @@ thisObject = undefined } - function start(multiPeriodDataFiles, timePeriod, timePeriodLabel, currentDay, startDate, endDate, interExecutionMemory, callBackFunction) { + function start(multiPeriodDataFiles, timePeriod, timePeriodLabel, currentDay, interExecutionMemory, callBackFunction) { try { @@ -150,8 +150,6 @@ timePeriod, timePeriodLabel, currentDay, - startDate, - endDate, interExecutionMemory, assistant, writeFiles, From 2c98d89d591430f47d4196525b93ab2c358d45dc Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 4 Oct 2019 12:04:16 +0200 Subject: [PATCH 221/244] Definition at bot level --- Commons.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Commons.js b/Commons.js index 43d192be4..de827c9cf 100644 --- a/Commons.js +++ b/Commons.js @@ -25,8 +25,6 @@ let bollingerSubChannelsAt = {} let candlesAt = {} - const definition = global.DEFINITION - return thisObject; function finalize() { @@ -63,7 +61,7 @@ let tradesArray = []; let lastObjectsArray = []; - let tradingSystem = definition.tradingSystem; + let tradingSystem = bot.DEFINITION.tradingSystem; /* Initial Default Values */ From ec2dc7dab2988d543026ee67f0eb23683dc45a60 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 4 Oct 2019 18:40:22 +0200 Subject: [PATCH 222/244] Logging Improved --- Commons.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Commons.js b/Commons.js index de827c9cf..15e382643 100644 --- a/Commons.js +++ b/Commons.js @@ -560,8 +560,8 @@ loopingDay = new Date(Math.trunc(candle.begin / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) if (loopingDay.valueOf() !== previousLoopingDay) { - if (FULL_LOG === true) {logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Simulation Loop # " + i + " @ " + (loopingDay.toLocaleString()))} - console.log("Jason -> " + MODULE_NAME + " -> runSimulation -> loop -> Simulation Loop # " + i + " @ " + (loopingDay.toLocaleString())) + if (FULL_LOG === true) {logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Simulation " + bot.sessionKey + " Loop # " + i + " @ " + (loopingDay.toLocaleString()))} + console.log("Jason -> " + MODULE_NAME + " -> runSimulation -> loop -> Simulation " + bot.sessionKey + " Loop # " + i + " @ " + (loopingDay.toLocaleString())) bot.sessionHeartBeat() // tell the world we are alive and doing well } @@ -2605,7 +2605,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> controlLoop -> Entering function."); } /* Checking if we should continue processing this loop or not.*/ - if (global.STOP_PROCESSING === true) { + 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.") afterLoop() From fc24c7ce66d841488381cf65ca7a166eaca68da4 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 4 Oct 2019 19:43:58 +0200 Subject: [PATCH 223/244] Bug Fixed when balance out of range --- Commons.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Commons.js b/Commons.js index 15e382643..021c56621 100644 --- a/Commons.js +++ b/Commons.js @@ -1183,10 +1183,10 @@ } } else { let stopRunningDate = new Date(candle.begin) - if (balance < minimumBalance) { + if (balance <= minimumBalance) { tradingSystem.error = "Min Balance @ " + stopRunningDate.toLocaleString() } - if (balance > maximumBalance) { + if (balance >= maximumBalance) { tradingSystem.error = "Max Balance @ " + stopRunningDate.toLocaleString() } } From 3000cf74fa783d1c85ccc8a8800e36bd80e6023d Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 4 Oct 2019 21:20:55 +0200 Subject: [PATCH 224/244] Sending the processing date at heartbeat event --- Commons.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Commons.js b/Commons.js index 021c56621..67a1b3c04 100644 --- a/Commons.js +++ b/Commons.js @@ -560,10 +560,13 @@ loopingDay = new Date(Math.trunc(candle.begin / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS) if (loopingDay.valueOf() !== previousLoopingDay) { - if (FULL_LOG === true) {logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Simulation " + bot.sessionKey + " Loop # " + i + " @ " + (loopingDay.toLocaleString()))} - console.log("Jason -> " + MODULE_NAME + " -> runSimulation -> loop -> Simulation " + bot.sessionKey + " Loop # " + i + " @ " + (loopingDay.toLocaleString())) - bot.sessionHeartBeat() // tell the world we are alive and doing well + 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 # " + i + " @ " + processingDate)} + console.log("Jason -> " + MODULE_NAME + " -> runSimulation -> loop -> Simulation " + bot.sessionKey + " Loop # " + i + " @ " + processingDate) + + bot.sessionHeartBeat(processingDate) // tell the world we are alive and doing well } previousLoopingDay = loopingDay.valueOf() From b61349ab0194a88bca2d192000326621cfc43c8b Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 5 Oct 2019 10:50:38 +0200 Subject: [PATCH 225/244] Bug fixed variable not declared --- Commons.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Commons.js b/Commons.js index 67a1b3c04..630a25a23 100644 --- a/Commons.js +++ b/Commons.js @@ -3,7 +3,7 @@ const FULL_LOG = true; const LOG_FILE_CONTENT = false; - const MODULE_NAME = "Commons"; + const MODULE_NAME = "Commons -> " + bot.sessionKey ; const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; const GMT_SECONDS = ':00.000 GMT+0000'; @@ -24,6 +24,7 @@ let bollingerChannelsAt = {} let bollingerSubChannelsAt = {} let candlesAt = {} + let processingDailyFiles return thisObject; @@ -36,7 +37,7 @@ thisObject = undefined } - async function runSimulation( + function runSimulation( timePeriod, timePeriodLabel, currentDay, @@ -2735,7 +2736,7 @@ } catch (err) { logger.write(MODULE_NAME, "[ERROR] runSimulation -> getElement -> datasetName = " + datasetName); - throw(err) + callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } @@ -2950,6 +2951,7 @@ } candlesAt[timePeriodLabel] = candles + } catch (err) { logger.write(MODULE_NAME, "[ERROR] buildCandles -> err = " + err.stack); From fa6025b6dfb6cc2b05049d1a0e68e8887b3d204d Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 6 Oct 2019 16:04:24 +0200 Subject: [PATCH 226/244] Warnings when using MIN STOP LOSS --- Commons.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Commons.js b/Commons.js index 630a25a23..3dd86c569 100644 --- a/Commons.js +++ b/Commons.js @@ -3,7 +3,7 @@ const FULL_LOG = true; const LOG_FILE_CONTENT = false; - const MODULE_NAME = "Commons -> " + bot.sessionKey ; + const MODULE_NAME = "Commons -> " + bot.SESSION.name ; const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; const GMT_SECONDS = ':00.000 GMT+0000'; @@ -877,8 +877,9 @@ try { formulaValue = eval(phase.formula.code); if (formulaValue === Infinity) { - formulaError = "Formula evaluates to Infinity." formulaValue = MAX_TAKE_PROFIT_VALUE + formulaError = "WARNING: Formula evaluates to Infinity." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> evaluateConditionsAndFormulas -> MAX_TAKE_PROFIT_VALUE -> formulaError = " + formulaError); } } } catch (err) { if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { @@ -892,6 +893,8 @@ if (isNaN(formulaValue)) { formulaValue = 0; } if (formulaValue < MIN_TAKE_PROFIT_VALUE) { formulaValue = MIN_TAKE_PROFIT_VALUE + formulaError = "WARNING: Formula is evaluating below the MIN_TAKE_PROFIT_VALUE." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> evaluateConditionsAndFormulas -> MIN_TAKE_PROFIT_VALUE -> formulaError = " + formulaError); } } formulasErrors.push('"' + formulaError + '"') @@ -945,8 +948,10 @@ try { formulaValue = eval(phase.formula.code); if (formulaValue === Infinity) { - formulaError = "Formula evaluates to Infinity." + formulaError = "" formulaValue = MAX_STOP_LOSS_VALUE + formulaError = "WARNING: Formula evaluates to Infinity." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> evaluateConditionsAndFormulas -> MAX_STOP_LOSS_VALUE -> formulaError = " + formulaError); } } } catch (err) { if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { @@ -960,6 +965,8 @@ if (isNaN(formulaValue)) { formulaValue = 0; } if (formulaValue < MIN_STOP_LOSS_VALUE) { formulaValue = MIN_STOP_LOSS_VALUE + formulaError = "WARNING: Formula is evaluating below the MIN_STOP_LOSS_VALUE." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> evaluateConditionsAndFormulas -> MIN_STOP_LOSS_VALUE -> formulaError = " + formulaError); } } formulasErrors.push('"' + formulaError + '"') From c47af95b359217fc5a2a49486f4254e2c93f826a Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 6 Oct 2019 16:55:08 +0200 Subject: [PATCH 227/244] Bug Fixed, inside a function for some reason I got not available for properties of Charts --- Commons.js | 568 +++++++++++++++++++++++++++-------------------------- 1 file changed, 285 insertions(+), 283 deletions(-) diff --git a/Commons.js b/Commons.js index 3dd86c569..16b46c64a 100644 --- a/Commons.js +++ b/Commons.js @@ -81,7 +81,6 @@ const MIN_TAKE_PROFIT_VALUE = 1 // We can not let the buy order be zero to avoid division by 0 error or infinity numbers as a result. const MAX_TAKE_PROFIT_VALUE = Number.MAX_SAFE_INTEGER - let previousTakeProfit = 0; let takeProfit = 0; /* Simulation Records */ @@ -667,278 +666,144 @@ conditionsArrayRecord.push(candle.begin); conditionsArrayRecord.push(candle.end); - evaluateConditionsAndFormulas(tradingSystem, conditions); + for (let j = 0; j < tradingSystem.strategies.length; j++) { - function evaluateConditionsAndFormulas(tradingSystem, conditions) { + let strategy = tradingSystem.strategies[j]; - for (let j = 0; j < tradingSystem.strategies.length; j++) { + let positionSize = 0 + let positionRate = 0 - let strategy = tradingSystem.strategies[j]; + /* Continue with the rest of the formulas and conditions */ - let positionSize = 0 - let positionRate = 0 + let triggerStage = strategy.triggerStage - /* Continue with the rest of the formulas and conditions */ + if (triggerStage !== undefined) { - let triggerStage = strategy.triggerStage + if (triggerStage.triggerOn !== undefined) { - if (triggerStage !== undefined) { + for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { - if (triggerStage.triggerOn !== undefined) { + let situation = triggerStage.triggerOn.situations[k]; - for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) { + for (let m = 0; m < situation.conditions.length; m++) { - let situation = triggerStage.triggerOn.situations[k]; + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; - - if (condition.code !== undefined) { - newCondition(key, condition.code); - } - } - } - } - - if (triggerStage.triggerOff !== undefined) { - - for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { - - let situation = triggerStage.triggerOff.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; - - if (condition.code !== undefined) { - newCondition(key, condition.code); - } - } - } - } - - if (triggerStage.takePosition !== undefined) { - - for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { - - let situation = triggerStage.takePosition.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; - - if (condition.code !== undefined) { - newCondition(key, condition.code); - } + if (condition.code !== undefined) { + newCondition(key, condition.code); } } } } - let openStage = strategy.openStage + if (triggerStage.triggerOff !== undefined) { - if (openStage !== undefined) { + for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { - /* Default Values*/ - if (bot.VALUES_TO_USE.baseAsset === 'BTC') { - positionSize = balanceAssetA; - positionRate = candle.close; + let situation = triggerStage.triggerOff.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; + + if (condition.code !== undefined) { + newCondition(key, condition.code); + } + } + } + } + + if (triggerStage.takePosition !== undefined) { + + for (let k = 0; k < triggerStage.takePosition.situations.length; k++) { + + let situation = triggerStage.takePosition.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'triggerStage' + '-' + 'takePosition' + '-' + k + '-' + m; + + if (condition.code !== undefined) { + newCondition(key, condition.code); + } + } + } + } + } + + let openStage = strategy.openStage + + if (openStage !== undefined) { + + /* Default Values*/ + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { + positionSize = balanceAssetA; + positionRate = candle.close; + } else { + positionSize = balanceAssetB; + positionRate = candle.close; + } + + let initialDefinition = openStage.initialDefinition + + if (initialDefinition !== undefined) { + + if (tradePositionSize !== 0) { + positionSize = tradePositionSize } else { - positionSize = balanceAssetB; - positionRate = candle.close; - } - - let initialDefinition = openStage.initialDefinition - - if (initialDefinition !== undefined) { - - if (tradePositionSize !== 0) { - positionSize = tradePositionSize - } else { - if (initialDefinition.positionSize !== undefined) { - if (initialDefinition.positionSize.formula !== undefined) { - try { - positionSize = eval(initialDefinition.positionSize.formula.code); - } catch (err) { - initialDefinition.positionSize.formula.error = err.message - } - if (isNaN(positionSize)) { - if (bot.VALUES_TO_USE.baseAsset === 'BTC') { - positionSize = balanceAssetA; - } else { - positionSize = balanceAssetB; - } + if (initialDefinition.positionSize !== undefined) { + if (initialDefinition.positionSize.formula !== undefined) { + try { + positionSize = eval(initialDefinition.positionSize.formula.code); + } catch (err) { + initialDefinition.positionSize.formula.error = err.message + } + if (isNaN(positionSize)) { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { + positionSize = balanceAssetA; } else { - if (bot.VALUES_TO_USE.baseAsset === 'BTC') { - if (positionSize > balanceAssetA) { positionSize = balanceAssetA } - } else { - if (positionSize > balanceAssetB) { positionSize = balanceAssetB } - } + positionSize = balanceAssetB; } - } - } - } - - if (tradePositionRate !== 0) { - positionRate = tradePositionRate - } else { - if (initialDefinition.positionRate !== undefined) { - if (initialDefinition.positionRate.formula !== undefined) { - try { - positionRate = eval(initialDefinition.positionRate.formula.code); - } catch (err) { - initialDefinition.positionRate.formula.error = err.message - } - if (isNaN(positionRate)) { - if (bot.VALUES_TO_USE.baseAsset === 'BTC') { - positionRate = candle.close; - } else { - positionRate = candle.close; - } - } - } - } - } - - if (initialDefinition.stopLoss !== undefined) { - - for (let p = 0; p < initialDefinition.stopLoss.phases.length; p++) { - - let phase = initialDefinition.stopLoss.phases[p]; - - /* Evaluate Formula */ - let formulaValue - let formulaError = '' - - if (phase.formula !== undefined) { - try { - formulaValue = eval(phase.formula.code); - if (formulaValue === Infinity) { - formulaError = "Formula evaluates to Infinity." - formulaValue = MAX_STOP_LOSS_VALUE - } - } catch (err) { - if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { - /* - We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. - */ - } else { - formulaError = err.message - } - } - if (isNaN(formulaValue)) { formulaValue = 0; } - if (formulaValue < MIN_STOP_LOSS_VALUE) { - formulaValue = MIN_STOP_LOSS_VALUE - } - - formulasErrors.push('"' + formulaError + '"') - formulasValues.push(formulaValue) - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p; - formulas.set(key, formulaValue) - } - - /* next phase event */ - let nextPhaseEvent = phase.nextPhaseEvent; - if (nextPhaseEvent !== undefined) { - - for (let k = 0; k < nextPhaseEvent.situations.length; k++) { - - let situation = nextPhaseEvent.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; - - if (condition.code !== undefined) { - newCondition(key, condition.code); - } - } - } - } - } - } - - if (initialDefinition.takeProfit !== undefined) { - - for (let p = 0; p < initialDefinition.takeProfit.phases.length; p++) { - - let phase = initialDefinition.takeProfit.phases[p]; - - /* Evaluate Formula */ - let formulaValue - let formulaError = '' - - if (phase.formula !== undefined) { - try { - formulaValue = eval(phase.formula.code); - if (formulaValue === Infinity) { - formulaValue = MAX_TAKE_PROFIT_VALUE - formulaError = "WARNING: Formula evaluates to Infinity." - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> evaluateConditionsAndFormulas -> MAX_TAKE_PROFIT_VALUE -> formulaError = " + formulaError); } - } - } catch (err) { - if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { - /* - We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. - */ - } else { - formulaError = err.message - } - } - if (isNaN(formulaValue)) { formulaValue = 0; } - if (formulaValue < MIN_TAKE_PROFIT_VALUE) { - formulaValue = MIN_TAKE_PROFIT_VALUE - formulaError = "WARNING: Formula is evaluating below the MIN_TAKE_PROFIT_VALUE." - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> evaluateConditionsAndFormulas -> MIN_TAKE_PROFIT_VALUE -> formulaError = " + formulaError); } - } - - formulasErrors.push('"' + formulaError + '"') - formulasValues.push(formulaValue) - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p; - formulas.set(key, formulaValue) - } - - /* next phase event */ - let nextPhaseEvent = phase.nextPhaseEvent; - if (nextPhaseEvent !== undefined) { - - for (let k = 0; k < nextPhaseEvent.situations.length; k++) { - - let situation = nextPhaseEvent.situations[k]; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; - - if (condition.code !== undefined) { - newCondition(key, condition.code); - } - } + } else { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { + if (positionSize > balanceAssetA) { positionSize = balanceAssetA } + } else { + if (positionSize > balanceAssetB) { positionSize = balanceAssetB } } } } } } - strategy.positionSize = positionSize - strategy.positionRate = positionRate - } + if (tradePositionRate !== 0) { + positionRate = tradePositionRate + } else { + if (initialDefinition.positionRate !== undefined) { + if (initialDefinition.positionRate.formula !== undefined) { + try { + positionRate = eval(initialDefinition.positionRate.formula.code); + } catch (err) { + initialDefinition.positionRate.formula.error = err.message + } + if (isNaN(positionRate)) { + if (bot.VALUES_TO_USE.baseAsset === 'BTC') { + positionRate = candle.close; + } else { + positionRate = candle.close; + } + } + } + } + } - let manageStage = strategy.manageStage + if (initialDefinition.stopLoss !== undefined) { - if (manageStage !== undefined) { + for (let p = 0; p < initialDefinition.stopLoss.phases.length; p++) { - if (manageStage.stopLoss !== undefined) { - - for (let p = 0; p < manageStage.stopLoss.phases.length; p++) { - - let phase = manageStage.stopLoss.phases[p]; + let phase = initialDefinition.stopLoss.phases[p]; /* Evaluate Formula */ let formulaValue @@ -948,10 +813,10 @@ try { formulaValue = eval(phase.formula.code); if (formulaValue === Infinity) { - formulaError = "" + formulaError = "Formula evaluates to Infinity." formulaValue = MAX_STOP_LOSS_VALUE formulaError = "WARNING: Formula evaluates to Infinity." - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> evaluateConditionsAndFormulas -> MAX_STOP_LOSS_VALUE -> formulaError = " + formulaError); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> initialDefinition.stopLoss -> MAX_STOP_LOSS_VALUE -> formulaError = " + formulaError); } } } catch (err) { if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { @@ -966,12 +831,12 @@ if (formulaValue < MIN_STOP_LOSS_VALUE) { formulaValue = MIN_STOP_LOSS_VALUE formulaError = "WARNING: Formula is evaluating below the MIN_STOP_LOSS_VALUE." - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> evaluateConditionsAndFormulas -> MIN_STOP_LOSS_VALUE -> formulaError = " + formulaError); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> initialDefinition.stopLoss -> MIN_STOP_LOSS_VALUE -> formulaError = " + formulaError); } } formulasErrors.push('"' + formulaError + '"') formulasValues.push(formulaValue) - let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p; + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p; formulas.set(key, formulaValue) } @@ -986,7 +851,7 @@ for (let m = 0; m < situation.conditions.length; m++) { let condition = situation.conditions[m]; - let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; if (condition.code !== undefined) { newCondition(key, condition.code); @@ -997,11 +862,11 @@ } } - if (manageStage.takeProfit !== undefined) { + if (initialDefinition.takeProfit !== undefined) { - for (let p = 0; p < manageStage.takeProfit.phases.length; p++) { + for (let p = 0; p < initialDefinition.takeProfit.phases.length; p++) { - let phase = manageStage.takeProfit.phases[p]; + let phase = initialDefinition.takeProfit.phases[p]; /* Evaluate Formula */ let formulaValue @@ -1011,8 +876,9 @@ try { formulaValue = eval(phase.formula.code); if (formulaValue === Infinity) { - formulaError = "Formula evaluates to Infinity." formulaValue = MAX_TAKE_PROFIT_VALUE + formulaError = "WARNING: Formula evaluates to Infinity." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> initialDefinition.takeProfit -> MAX_TAKE_PROFIT_VALUE -> formulaError = " + formulaError); } } } catch (err) { if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { @@ -1026,11 +892,13 @@ if (isNaN(formulaValue)) { formulaValue = 0; } if (formulaValue < MIN_TAKE_PROFIT_VALUE) { formulaValue = MIN_TAKE_PROFIT_VALUE + formulaError = "WARNING: Formula is evaluating below the MIN_TAKE_PROFIT_VALUE." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> initialDefinition.takeProfit -> MIN_TAKE_PROFIT_VALUE -> formulaError = " + formulaError); } } formulasErrors.push('"' + formulaError + '"') formulasValues.push(formulaValue) - let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p; + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p; formulas.set(key, formulaValue) } @@ -1045,7 +913,7 @@ for (let m = 0; m < situation.conditions.length; m++) { let condition = situation.conditions[m]; - let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; + let key = j + '-' + 'openStage' + '-' + 'initialDefinition' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; if (condition.code !== undefined) { newCondition(key, condition.code); @@ -1057,46 +925,180 @@ } } - function newCondition(key, node) { + strategy.positionSize = positionSize + strategy.positionRate = positionRate + } - let condition; - let error = '' - let value + let manageStage = strategy.manageStage - try { - value = eval(node.code); - } catch (err) { - /* - One possible error is that the conditions references a .previous that is undefined. For this - reason and others, we will simply set the value to false. - */ - value = false + if (manageStage !== undefined) { - if (node.code.indexOf('previous') > -1 && err.message.indexOf('of undefined') > -1 || - node.code.indexOf('chart') > -1 && err.message.indexOf('of undefined') > -1 - ) { - /* - We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. - */ - } else { - node.error = err.message + " @ " + (new Date(candle.begin)).toLocaleString() + if (manageStage.stopLoss !== undefined) { + + for (let p = 0; p < manageStage.stopLoss.phases.length; p++) { + + let phase = manageStage.stopLoss.phases[p]; + + /* Evaluate Formula */ + let formulaValue + let formulaError = '' + + if (phase.formula !== undefined) { + try { + formulaValue = eval(phase.formula.code); + if (formulaValue === Infinity) { + formulaError = "" + formulaValue = MAX_STOP_LOSS_VALUE + formulaError = "WARNING: Formula evaluates to Infinity." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> manageStage.stopLoss -> MAX_STOP_LOSS_VALUE -> formulaError = " + formulaError); } + } + } catch (err) { + if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { + /* + We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. + */ + } else { + formulaError = err.message + } + } + if (isNaN(formulaValue)) { formulaValue = 0; } + if (formulaValue < MIN_STOP_LOSS_VALUE) { + formulaValue = MIN_STOP_LOSS_VALUE + formulaError = "WARNING: Formula is evaluating below the MIN_STOP_LOSS_VALUE." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> manageStage.stopLoss -> MIN_STOP_LOSS_VALUE -> formulaError = " + formulaError); } + } + + formulasErrors.push('"' + formulaError + '"') + formulasValues.push(formulaValue) + let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p; + formulas.set(key, formulaValue) + } + + /* next phase event */ + let nextPhaseEvent = phase.nextPhaseEvent; + if (nextPhaseEvent !== undefined) { + + for (let k = 0; k < nextPhaseEvent.situations.length; k++) { + + let situation = nextPhaseEvent.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; + + if (condition.code !== undefined) { + newCondition(key, condition.code); + } + } + } } } + } - condition = { - key: key, - value: value - }; + if (manageStage.takeProfit !== undefined) { - conditions.set(condition.key, condition); + for (let p = 0; p < manageStage.takeProfit.phases.length; p++) { - if (condition.value) { - conditionsArrayValues.push(1); - } else { - conditionsArrayValues.push(0); + let phase = manageStage.takeProfit.phases[p]; + + /* Evaluate Formula */ + let formulaValue + let formulaError = '' + + if (phase.formula !== undefined) { + try { + formulaValue = eval(phase.formula.code); + if (formulaValue === Infinity) { + formulaError = "Formula evaluates to Infinity." + formulaValue = MAX_TAKE_PROFIT_VALUE + formulaError = "WARNING: Formula evaluates to Infinity." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> manageStage.takeProfit -> MAX_TAKE_PROFIT_VALUE -> formulaError = " + formulaError); } + } + } catch (err) { + if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { + /* + We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. + */ + } else { + formulaError = err.message + } + } + if (isNaN(formulaValue)) { formulaValue = 0; } + if (formulaValue < MIN_TAKE_PROFIT_VALUE) { + formulaValue = MIN_TAKE_PROFIT_VALUE + formulaError = "WARNING: Formula is evaluating below the MIN_TAKE_PROFIT_VALUE." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> manageStage.takeProfit -> MIN_TAKE_PROFIT_VALUE -> formulaError = " + formulaError); } + } + + formulasErrors.push('"' + formulaError + '"') + formulasValues.push(formulaValue) + let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p; + formulas.set(key, formulaValue) + } + + /* next phase event */ + let nextPhaseEvent = phase.nextPhaseEvent; + if (nextPhaseEvent !== undefined) { + + for (let k = 0; k < nextPhaseEvent.situations.length; k++) { + + let situation = nextPhaseEvent.situations[k]; + + for (let m = 0; m < situation.conditions.length; m++) { + + let condition = situation.conditions[m]; + let key = j + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; + + if (condition.code !== undefined) { + newCondition(key, condition.code); + } + } + } + } } } } + + function newCondition(key, node) { + + let condition; + let error = '' + let value + + try { + value = eval(node.code); + } catch (err) { + /* + One possible error is that the conditions references a .previous that is undefined. For this + reason and others, we will simply set the value to false. + */ + value = false + + if (node.code.indexOf('previous') > -1 && err.message.indexOf('of undefined') > -1 || + node.code.indexOf('chart') > -1 && err.message.indexOf('of undefined') > -1 + ) { + /* + We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined. + */ + } else { + node.error = err.message + " @ " + (new Date(candle.begin)).toLocaleString() + } + } + + condition = { + key: key, + value: value + }; + + conditions.set(condition.key, condition); + + if (condition.value) { + conditionsArrayValues.push(1); + } else { + conditionsArrayValues.push(0); + } + } } /* Trigger On Conditions */ From beef56b55ff865a9f8c2ffc5876430b292ad2d15 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 6 Oct 2019 17:24:02 +0200 Subject: [PATCH 228/244] Bug Fixed: stop Loss and takeProfit were not being remembered from the previous day --- Commons.js | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/Commons.js b/Commons.js index 16b46c64a..c432cbe89 100644 --- a/Commons.js +++ b/Commons.js @@ -190,6 +190,9 @@ /* Initialization */ + yesterday.stopLoss = 0 + yesterday.takeProfit = 0 + yesterday.previousBalanceAssetA = previousBalanceAssetA yesterday.previousBalanceAssetB = previousBalanceAssetB @@ -255,6 +258,9 @@ /* Initialize the data structure we will use inter execution. */ + interExecutionMemory.stopLoss = 0 + interExecutionMemory.takeProfit = 0 + interExecutionMemory.previousBalanceAssetA = previousBalanceAssetA interExecutionMemory.previousBalanceAssetB = previousBalanceAssetB @@ -320,6 +326,9 @@ /* We get the initial values from the day previous to the candles we receive at the current execution */ + stopLoss = interExecutionMemory.stopLoss + takeProfit = interExecutionMemory.takeProfit + previousBalanceAssetA = interExecutionMemory.previousBalanceAssetA previousBalanceAssetB = interExecutionMemory.previousBalanceAssetB @@ -390,6 +399,9 @@ /* For the case that any of these variables are not updated during the main loop, we need to store their value at the yesterday structure, otherwise it would be lost. */ + yesterday.stopLoss = stopLoss + yesterday.takeProfit = takeProfit + yesterday.previousBalanceAssetA = previousBalanceAssetA yesterday.previousBalanceAssetB = previousBalanceAssetB @@ -1440,6 +1452,10 @@ if (phase !== undefined) { if (phase.formula !== undefined) { stopLoss = formulas.get(key) + + if (processingDailyFiles) { + yesterday.stopLoss = stopLoss + } } } } @@ -1555,6 +1571,9 @@ if (phase !== undefined) { if (phase.formula !== undefined) { takeProfit = formulas.get(key) + if (processingDailyFiles) { + yesterday.takeProfit = takeProfit + } } } } @@ -1664,9 +1683,19 @@ */ if (bot.VALUES_TO_USE.baseAsset === 'BTC') { - if (stopLoss < candle.min) { stopLoss = candle.min } + if (stopLoss < candle.min) { + stopLoss = candle.min + if (processingDailyFiles) { + yesterday.stopLoss = stopLoss + } + } } else { - if (stopLoss > candle.max) { stopLoss = candle.max } + if (stopLoss > candle.max) { + stopLoss = candle.max + if (processingDailyFiles) { + yesterday.stopLoss = stopLoss + } + } } let slippedStopLoss = stopLoss @@ -1746,9 +1775,19 @@ */ if (bot.VALUES_TO_USE.baseAsset === 'BTC') { - if (takeProfit > candle.max) { takeProfit = candle.max } + if (takeProfit > candle.max) { + takeProfit = candle.max + if (processingDailyFiles) { + yesterday.takeProfit = takeProfit + } + } } else { - if (takeProfit < candle.min) { takeProfit = candle.min } + if (takeProfit < candle.min) { + takeProfit = candle.min + if (processingDailyFiles) { + yesterday.takeProfit = takeProfit + } + } } let slippedTakeProfit = takeProfit @@ -2356,7 +2395,13 @@ addRecord(); stopLoss = 0; + if (processingDailyFiles) { + yesterday.stopLoss = stopLoss + } takeProfit = 0; + if (processingDailyFiles) { + yesterday.takeProfit = takeProfit + } tradePositionRate = 0; tradePositionSize = 0; @@ -2645,6 +2690,9 @@ if (lastCandle.end === lastInstantOfTheDay) { + interExecutionMemory.stopLoss = yesterday.stopLoss + interExecutionMemory.takeProfit = yesterday.takeProfit + interExecutionMemory.previousBalanceAssetA = yesterday.previousBalanceAssetA interExecutionMemory.previousBalanceAssetB = yesterday.previousBalanceAssetB From 81215491dc2148f0a1639c98281fbf9f649ce700 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 8 Oct 2019 12:29:50 +0200 Subject: [PATCH 229/244] Sync config with ecosystem config --- this.bot.config.json | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/this.bot.config.json b/this.bot.config.json index 19e1959bd..5b94e1dd2 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -248,7 +248,7 @@ "products": [ { "codeName": "Trading-Simulation", - "displayName": "Trading Simulation", + "displayName": "Simulation", "description": "Trading Simulation", "storageAccount": "aajason", "dataSets": [ @@ -265,7 +265,7 @@ "02-hs", "01-hs" ], - "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Trading-Simulation/Multi-Period-Market/@Period", + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/@Session/Trading-Simulation/Multi-Period-Market/@Period", "fileName": "@AssetA_@AssetB.json" }, { @@ -284,10 +284,10 @@ "02-min", "01-min" ], - "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Trading-Simulation/Multi-Period-Daily/@Period/@Year/@Month/@Day", + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/@Session/Trading-Simulation/Multi-Period-Daily/@Period/@Year/@Month/@Day", "fileName": "@AssetA_@AssetB.json", "dataRange": { - "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Trading-Simulation/Multi-Period-Daily", + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/@Session/Trading-Simulation/Multi-Period-Daily", "fileName": "Data.Range.@AssetA_@AssetB.json" } } @@ -308,7 +308,7 @@ }, { "codeName": "Simulation-Conditions", - "displayName": "Simulation Conditions", + "displayName": "Conditions", "description": "Simulation Conditions", "storageAccount": "aajason", "dataSets": [ @@ -325,7 +325,7 @@ "02-hs", "01-hs" ], - "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Conditions/Multi-Period-Market/@Period", + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/@Session/Simulation-Conditions/Multi-Period-Market/@Period", "fileName": "@AssetA_@AssetB.json" }, { @@ -344,10 +344,10 @@ "02-min", "01-min" ], - "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Conditions/Multi-Period-Daily/@Period/@Year/@Month/@Day", + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/@Session/Simulation-Conditions/Multi-Period-Daily/@Period/@Year/@Month/@Day", "fileName": "@AssetA_@AssetB.json", "dataRange": { - "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Conditions/Multi-Period-Daily", + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/@Session/Simulation-Conditions/Multi-Period-Daily", "fileName": "Data.Range.@AssetA_@AssetB.json" } } @@ -368,7 +368,7 @@ }, { "codeName": "Simulation-Strategies", - "displayName": "Simulation Strategies", + "displayName": "Strategies", "description": "Simulation Strategies", "storageAccount": "aajason", "dataSets": [ @@ -385,7 +385,7 @@ "02-hs", "01-hs" ], - "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Strategies/Multi-Period-Market/@Period", + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/@Session/Simulation-Strategies/Multi-Period-Market/@Period", "fileName": "@AssetA_@AssetB.json" }, { @@ -404,10 +404,10 @@ "02-min", "01-min" ], - "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Strategies/Multi-Period-Daily/@Period/@Year/@Month/@Day", + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/@Session/Simulation-Strategies/Multi-Period-Daily/@Period/@Year/@Month/@Day", "fileName": "@AssetA_@AssetB.json", "dataRange": { - "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Strategies/Multi-Period-Daily", + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/@Session/Simulation-Strategies/Multi-Period-Daily", "fileName": "Data.Range.@AssetA_@AssetB.json" } } @@ -428,7 +428,7 @@ }, { "codeName": "Simulation-Trades", - "displayName": "Simulation Trades", + "displayName": "Trades", "description": "Simulation Trades", "storageAccount": "aajason", "dataSets": [ @@ -445,7 +445,7 @@ "02-hs", "01-hs" ], - "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Trades/Multi-Period-Market/@Period", + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/@Session/Simulation-Trades/Multi-Period-Market/@Period", "fileName": "@AssetA_@AssetB.json" }, { @@ -464,10 +464,10 @@ "02-min", "01-min" ], - "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Trades/Multi-Period-Daily/@Period/@Year/@Month/@Day", + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/@Session/Simulation-Trades/Multi-Period-Daily/@Period/@Year/@Month/@Day", "fileName": "@AssetA_@AssetB.json", "dataRange": { - "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Simulation-Trades/Multi-Period-Daily", + "filePath": "AAMasters/AAJason.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/@Session/Simulation-Trades/Multi-Period-Daily", "fileName": "Data.Range.@AssetA_@AssetB.json" } } @@ -487,8 +487,8 @@ } }, { - "codeName": "Live Trading History", - "displayName": "Live Trading History", + "codeName": "Live-Trading-History", + "displayName": "Live", "shortDisplayName": "Live", "description": "Live Trading Execution.", "dataSets": [ @@ -516,7 +516,7 @@ "02-min", "01-min" ], - "filePath": "@DevTeam/@Bot.1.0/AACloud.1.1/Poloniex/dataSet.V1/Output/Trading-Process", + "filePath": "@DevTeam/@Bot.1.0/AACloud.1.1/Poloniex/dataSet.V1/Output/@Session/Trading-Process", "fileName": "Execution.History.Live.@Sequence.json" } ], From 3930728bfef13eb37fe44ff2a462e727a7923096 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 8 Oct 2019 16:39:02 +0200 Subject: [PATCH 230/244] Session Id for each file written --- Multi-Period/User.Bot.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Multi-Period/User.Bot.js b/Multi-Period/User.Bot.js index 44e6d77f6..c041e35c8 100644 --- a/Multi-Period/User.Bot.js +++ b/Multi-Period/User.Bot.js @@ -244,7 +244,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; + let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -322,7 +322,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; + let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -392,7 +392,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; + let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -465,7 +465,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; + let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -591,7 +591,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel; + let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -698,7 +698,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -786,7 +786,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -863,7 +863,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -943,7 +943,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); From d6e9da30bb14bdfb77764acf2b0d8e6693656cb2 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 10 Oct 2019 14:58:34 +0200 Subject: [PATCH 231/244] Conditional Warnings --- Commons.js | 58 ++++++++++++++++++++++++++++---------------- this.bot.config.json | 2 ++ 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/Commons.js b/Commons.js index c432cbe89..31d3dc6b3 100644 --- a/Commons.js +++ b/Commons.js @@ -827,9 +827,11 @@ if (formulaValue === Infinity) { formulaError = "Formula evaluates to Infinity." formulaValue = MAX_STOP_LOSS_VALUE - formulaError = "WARNING: Formula evaluates to Infinity." - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> initialDefinition.stopLoss -> MAX_STOP_LOSS_VALUE -> formulaError = " + formulaError); } - } + if (stopLossStage === 'Open Stage') { + formulaError = "WARNING: Formula evaluates to Infinity." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> initialDefinition.stopLoss -> MAX_STOP_LOSS_VALUE -> formulaError = " + formulaError); } + } + } } catch (err) { if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { /* @@ -842,9 +844,11 @@ if (isNaN(formulaValue)) { formulaValue = 0; } if (formulaValue < MIN_STOP_LOSS_VALUE) { formulaValue = MIN_STOP_LOSS_VALUE - formulaError = "WARNING: Formula is evaluating below the MIN_STOP_LOSS_VALUE." - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> initialDefinition.stopLoss -> MIN_STOP_LOSS_VALUE -> formulaError = " + formulaError); } - } + if (stopLossStage === 'Open Stage') { + formulaError = "WARNING: Formula is evaluating below the MIN_STOP_LOSS_VALUE." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> initialDefinition.stopLoss -> MIN_STOP_LOSS_VALUE -> formulaError = " + formulaError); } + } + } formulasErrors.push('"' + formulaError + '"') formulasValues.push(formulaValue) @@ -889,9 +893,11 @@ formulaValue = eval(phase.formula.code); if (formulaValue === Infinity) { formulaValue = MAX_TAKE_PROFIT_VALUE - formulaError = "WARNING: Formula evaluates to Infinity." - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> initialDefinition.takeProfit -> MAX_TAKE_PROFIT_VALUE -> formulaError = " + formulaError); } - } + if (takeProfitStage === 'Open Stage') { + formulaError = "WARNING: Formula evaluates to Infinity." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> initialDefinition.takeProfit -> MAX_TAKE_PROFIT_VALUE -> formulaError = " + formulaError); } + } + } } catch (err) { if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { /* @@ -904,9 +910,11 @@ if (isNaN(formulaValue)) { formulaValue = 0; } if (formulaValue < MIN_TAKE_PROFIT_VALUE) { formulaValue = MIN_TAKE_PROFIT_VALUE - formulaError = "WARNING: Formula is evaluating below the MIN_TAKE_PROFIT_VALUE." - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> initialDefinition.takeProfit -> MIN_TAKE_PROFIT_VALUE -> formulaError = " + formulaError); } - } + if (takeProfitStage === 'Open Stage') { + formulaError = "WARNING: Formula is evaluating below the MIN_TAKE_PROFIT_VALUE." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> initialDefinition.takeProfit -> MIN_TAKE_PROFIT_VALUE -> formulaError = " + formulaError); } + } + } formulasErrors.push('"' + formulaError + '"') formulasValues.push(formulaValue) @@ -961,9 +969,11 @@ if (formulaValue === Infinity) { formulaError = "" formulaValue = MAX_STOP_LOSS_VALUE - formulaError = "WARNING: Formula evaluates to Infinity." - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> manageStage.stopLoss -> MAX_STOP_LOSS_VALUE -> formulaError = " + formulaError); } - } + if (stopLossStage === 'Manage Stage') { + formulaError = "WARNING: Formula evaluates to Infinity." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> manageStage.stopLoss -> MAX_STOP_LOSS_VALUE -> formulaError = " + formulaError); } + } + } } catch (err) { if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { /* @@ -976,8 +986,10 @@ if (isNaN(formulaValue)) { formulaValue = 0; } if (formulaValue < MIN_STOP_LOSS_VALUE) { formulaValue = MIN_STOP_LOSS_VALUE - formulaError = "WARNING: Formula is evaluating below the MIN_STOP_LOSS_VALUE." - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> manageStage.stopLoss -> MIN_STOP_LOSS_VALUE -> formulaError = " + formulaError); } + if (stopLossStage === 'Manage Stage') { + formulaError = "WARNING: Formula is evaluating below the MIN_STOP_LOSS_VALUE." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> manageStage.stopLoss -> MIN_STOP_LOSS_VALUE -> formulaError = " + formulaError); } + } } formulasErrors.push('"' + formulaError + '"') @@ -1024,8 +1036,10 @@ if (formulaValue === Infinity) { formulaError = "Formula evaluates to Infinity." formulaValue = MAX_TAKE_PROFIT_VALUE - formulaError = "WARNING: Formula evaluates to Infinity." - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> manageStage.takeProfit -> MAX_TAKE_PROFIT_VALUE -> formulaError = " + formulaError); } + if (takeProfitStage === 'Manage Stage') { + formulaError = "WARNING: Formula evaluates to Infinity." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> manageStage.takeProfit -> MAX_TAKE_PROFIT_VALUE -> formulaError = " + formulaError); } + } } } catch (err) { if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) { @@ -1039,8 +1053,10 @@ if (isNaN(formulaValue)) { formulaValue = 0; } if (formulaValue < MIN_TAKE_PROFIT_VALUE) { formulaValue = MIN_TAKE_PROFIT_VALUE - formulaError = "WARNING: Formula is evaluating below the MIN_TAKE_PROFIT_VALUE." - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> manageStage.takeProfit -> MIN_TAKE_PROFIT_VALUE -> formulaError = " + formulaError); } + if (takeProfitStage === 'Manage Stage') { + formulaError = "WARNING: Formula is evaluating below the MIN_TAKE_PROFIT_VALUE." + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] runSimulation -> loop -> manageStage.takeProfit -> MIN_TAKE_PROFIT_VALUE -> formulaError = " + formulaError); } + } } formulasErrors.push('"' + formulaError + '"') diff --git a/this.bot.config.json b/this.bot.config.json index 5b94e1dd2..82e37a4a1 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -113,6 +113,7 @@ { "devTeam": "AAMasters", "bot": "AAJason", + "type": "Trading Engine", "botVersion": { "major": 1, "minor": 0 @@ -123,6 +124,7 @@ { "devTeam": "AAMasters", "bot": "AAJason", + "type": "Trading Engine", "botVersion": { "major": 1, "minor": 0 From 91ceec5f35a578095c5d6b64309555da7aeda50e Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 10 Oct 2019 15:57:53 +0200 Subject: [PATCH 232/244] Bug Fixed, not controling if positioned at yesterday --- Commons.js | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/Commons.js b/Commons.js index 31d3dc6b3..fea2cf165 100644 --- a/Commons.js +++ b/Commons.js @@ -1470,7 +1470,9 @@ stopLoss = formulas.get(key) if (processingDailyFiles) { - yesterday.stopLoss = stopLoss + if (positionedAtYesterday) { + yesterday.stopLoss = stopLoss + } } } } @@ -1588,7 +1590,9 @@ if (phase.formula !== undefined) { takeProfit = formulas.get(key) if (processingDailyFiles) { - yesterday.takeProfit = takeProfit + if (positionedAtYesterday) { + yesterday.takeProfit = takeProfit + } } } } @@ -1691,6 +1695,7 @@ if ((bot.VALUES_TO_USE.baseAsset === 'BTC' && candle.max >= stopLoss) || (bot.VALUES_TO_USE.baseAsset !== 'BTC' && candle.min <= stopLoss)) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Stop Loss was hit."); } /* Hit Point Validation @@ -1702,14 +1707,18 @@ if (stopLoss < candle.min) { stopLoss = candle.min if (processingDailyFiles) { - yesterday.stopLoss = stopLoss + if (positionedAtYesterday) { + yesterday.stopLoss = stopLoss + } } } } else { if (stopLoss > candle.max) { stopLoss = candle.max if (processingDailyFiles) { - yesterday.stopLoss = stopLoss + if (positionedAtYesterday) { + yesterday.stopLoss = stopLoss + } } } } @@ -1783,6 +1792,7 @@ if ((bot.VALUES_TO_USE.baseAsset === 'BTC' && candle.min <= takeProfit) || (bot.VALUES_TO_USE.baseAsset !== 'BTC' && candle.max >= takeProfit)) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Take Profit was hit."); } /* Hit Point Validation: @@ -1794,14 +1804,18 @@ if (takeProfit > candle.max) { takeProfit = candle.max if (processingDailyFiles) { - yesterday.takeProfit = takeProfit + if (positionedAtYesterday) { + yesterday.takeProfit = takeProfit + } } } } else { if (takeProfit < candle.min) { takeProfit = candle.min if (processingDailyFiles) { - yesterday.takeProfit = takeProfit + if (positionedAtYesterday) { + yesterday.takeProfit = takeProfit + } } } } @@ -2412,11 +2426,15 @@ stopLoss = 0; if (processingDailyFiles) { - yesterday.stopLoss = stopLoss + if (positionedAtYesterday) { + yesterday.stopLoss = stopLoss + } } takeProfit = 0; if (processingDailyFiles) { - yesterday.takeProfit = takeProfit + if (positionedAtYesterday) { + yesterday.takeProfit = takeProfit + } } tradePositionRate = 0; From ac720b103294f31fc72724bb019e1a92f68e2cee Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 10 Oct 2019 16:18:12 +0200 Subject: [PATCH 233/244] latests objects cleaned --- Commons.js | 37 ++----------------------------------- Multi-Period/User.Bot.js | 8 +++----- 2 files changed, 5 insertions(+), 40 deletions(-) diff --git a/Commons.js b/Commons.js index fea2cf165..ff857dc31 100644 --- a/Commons.js +++ b/Commons.js @@ -60,7 +60,6 @@ let conditionsArray = []; let strategiesArray = []; let tradesArray = []; - let lastObjectsArray = []; let tradingSystem = bot.DEFINITION.tradingSystem; @@ -633,38 +632,7 @@ controlLoop(); return } - } - - let lastObjects = { - candle: clone(candle), - //LRC: clone(LRC), - bollingerBand: clone(bollingerBand), - percentageBandwidth: clone(percentageBandwidth), - bollingerChannel: clone(bollingerChannel), - bollingerSubChannel: clone(bollingerSubChannel) - } - - function clone(obj) { - if (null == obj || "object" != typeof obj) return obj; - var copy = obj.constructor(); - for (var attr in obj) { - if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr]; - } - return copy; - } - - lastObjects.candle.previous = undefined; - //lastObjects.LRC.previous = undefined; - lastObjects.bollingerBand.previous = undefined; - lastObjects.percentageBandwidth.previous = undefined; - lastObjects.bollingerChannel.previous = undefined; - lastObjects.bollingerSubChannel.previous = undefined; - - lastObjectsArray.push(lastObjects); - - if (lastObjectsArray.length > 5) { - lastObjectsArray.splice(0, 1); - } + } let conditions = new Map; // Here we store the conditions values that will be use in the simulator for decision making. let formulas = new Map; @@ -2789,10 +2757,9 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> callback -> recordsArray.length = " + recordsArray.length); } - callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, tradesArray, lastObjectsArray); + callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, tradesArray); } - function getElement(pArray, currentCandle, datasetName) { try { diff --git a/Multi-Period/User.Bot.js b/Multi-Period/User.Bot.js index c041e35c8..b631534ea 100644 --- a/Multi-Period/User.Bot.js +++ b/Multi-Period/User.Bot.js @@ -66,7 +66,6 @@ let conditionsArray let strategiesArray let tradesArray - let lastObjectsArray let tradingSystem = {}; @@ -155,14 +154,13 @@ writeFiles, callBackFunction) - function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) { + function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray) { tradingSystem = pTradingSystem recordsArray = pRecordsArray conditionsArray = pConditionsArray strategiesArray = pStrategiesArray tradesArray = pTradesArray - lastObjectsArray = pLastObjectsArray if (timePeriod > global.dailyFilePeriods[0][0]) { writeMarketFiles() @@ -318,7 +316,7 @@ } fileContent = "[" + fileContent + "]"; - fileContent = "[" + JSON.stringify(tradingSystem) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]"; + fileContent = "[" + JSON.stringify(tradingSystem) + "," + fileContent + "]"; let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; @@ -780,7 +778,7 @@ } fileContent = "[" + fileContent + "]"; - fileContent = "[" + JSON.stringify(tradingSystem) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]"; + fileContent = "[" + JSON.stringify(tradingSystem) + "," + fileContent + "]"; let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2); let fileName = '' + market.assetA + '_' + market.assetB + '.json'; From 61eb0af4fe2f7a2385c0e7df3816a2df1250fcfe Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 17 Oct 2019 10:20:39 +0200 Subject: [PATCH 234/244] SESSION.folderName implemented --- Multi-Period/User.Bot.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Multi-Period/User.Bot.js b/Multi-Period/User.Bot.js index b631534ea..7ee305706 100644 --- a/Multi-Period/User.Bot.js +++ b/Multi-Period/User.Bot.js @@ -161,7 +161,7 @@ conditionsArray = pConditionsArray strategiesArray = pStrategiesArray tradesArray = pTradesArray - + if (timePeriod > global.dailyFilePeriods[0][0]) { writeMarketFiles() } else { @@ -242,7 +242,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; + let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -320,7 +320,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; + let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -390,7 +390,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; + let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -463,7 +463,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; + let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriodLabel; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -589,7 +589,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel; + let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -696,7 +696,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -784,7 +784,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -861,7 +861,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); @@ -941,7 +941,7 @@ let fileName = '' + market.assetA + '_' + market.assetB + '.json'; let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion; - let filePath = filePathRoot + "/Output/" + bot.SESSION.id + "/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; + let filePath = filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timePeriodLabel + "/" + dateForPath; filePath += '/' + fileName fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated); From aa0a835f45e291dd83f6a422170e6e81aa134292 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 19 Oct 2019 13:35:54 +0200 Subject: [PATCH 235/244] Announcements Implemented --- Commons.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Commons.js b/Commons.js index ff857dc31..91ef9c820 100644 --- a/Commons.js +++ b/Commons.js @@ -1183,6 +1183,8 @@ } } + 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; } @@ -1258,6 +1260,8 @@ } } + checkAnnouncements(triggerStage.triggerOff) + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Switching to No Stage because conditions at the Trigger Off Event were met."); } break; } @@ -1317,6 +1321,8 @@ takePositionNow = true + checkAnnouncements(triggerStage.takePosition) + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Conditions at the Take Position Event were met."); } break; } @@ -1403,6 +1409,8 @@ yesterday.strategyStage = strategyStage; } } + + checkAnnouncements(nextPhaseEvent) return; } } @@ -1524,6 +1532,8 @@ yesterday.strategyStage = strategyStage; } } + + checkAnnouncements(nextPhaseEvent) return; } } @@ -2659,6 +2669,15 @@ } } } + + function checkAnnouncements(node) { + if (node.announcements !== undefined) { + for (let i = 0; i < node.announcements.length; i++) { + let announcement = node.announcements[i] + bot.SESSION.socialBots.announce(announcement) + } + } + } } function controlLoop() { From 189d9ea9da9e0bcbb7a6f961148003c24dd96f59 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 20 Oct 2019 09:40:29 +0200 Subject: [PATCH 236/244] Removing restriction --- Commons.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Commons.js b/Commons.js index 91ef9c820..0809f931f 100644 --- a/Commons.js +++ b/Commons.js @@ -1980,7 +1980,7 @@ } } - /* This validation is disbled for now because we do not have the correct end date at this point. + This validation is disbled for now because we do not have the correct end date at this point. if (bot.VALUES_TO_USE.timeRange.finalDatetime !== undefined) { if (candle.begin > bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf()) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because current candle begins after the end date. -> bot.VALUES_TO_USE.timeRange.finalDatetime = " + bot.VALUES_TO_USE.timeRange.finalDatetime); } @@ -1988,7 +1988,7 @@ return; } } - */ + /* Checking the status of current positions */ let positions = assistant.getPositions(); From 28ccfdaa90d1c92eb8e6cd8f11d17a3048b9c4ae Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 21 Oct 2019 08:23:11 +0200 Subject: [PATCH 237/244] Checking that announcements are not fired more than once for the same reason. --- Commons.js | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/Commons.js b/Commons.js index 0809f931f..7e4f4b388 100644 --- a/Commons.js +++ b/Commons.js @@ -253,7 +253,7 @@ yesterday.ROI = 0; yesterday.anualizedRateOfReturn = 0; - if (interExecutionMemory.roundtrips === undefined) { + if (interExecutionMemory.roundtrips === undefined) { // This just means that the inter execution memory was never used before. /* Initialize the data structure we will use inter execution. */ @@ -321,6 +321,8 @@ interExecutionMemory.ROI = 0; interExecutionMemory.anualizedRateOfReturn = 0; + interExecutionMemory.announcements = [] + } else { /* We get the initial values from the day previous to the candles we receive at the current execution */ @@ -1980,7 +1982,7 @@ } } - This validation is disbled for now because we do not have the correct end date at this point. + /*We wont take a position if we are past the final datetime */ if (bot.VALUES_TO_USE.timeRange.finalDatetime !== undefined) { if (candle.begin > bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf()) { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> putOpeningOrder -> Not placing the trade at the exchange because current candle begins after the end date. -> bot.VALUES_TO_USE.timeRange.finalDatetime = " + bot.VALUES_TO_USE.timeRange.finalDatetime); } @@ -2671,11 +2673,38 @@ } function checkAnnouncements(node) { - if (node.announcements !== undefined) { + if (node.announcements !== undefined) { for (let i = 0; i < node.announcements.length; i++) { let announcement = node.announcements[i] - bot.SESSION.socialBots.announce(announcement) - } + let key = node.type + "-" + announcement.name + "-" + announcement.id + + let lastPeriodAnnounced = -1 + let newAnnouncementRecord + + for (let j = 0; j < interExecutionMemory.announcements.length; j++) { + let announcementRecord = interExecutionMemory.announcements[j] + if (announcementRecord.key === key) { + lastPeriodAnnounced = announcementRecord.periods + newAnnouncementRecord = announcementRecord + break + } + } + + if (periods > lastPeriodAnnounced) { + bot.SESSION.socialBots.announce(announcement) + + /* Next, we will remmeber this announcement was already done, so that it is not announced again in further processing of the same day. */ + if (newAnnouncementRecord !== undefined) { + newAnnouncementRecord.periods = periods + } else { + newAnnouncementRecord = { + key: key, + periods: periods + } + interExecutionMemory.announcements.push(newAnnouncementRecord) + } + } + } } } } From 50e20f38b723b9c5daf32231e84238b67571df56 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 21 Oct 2019 09:24:01 +0200 Subject: [PATCH 238/244] Evaluation formula for announcement --- Commons.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Commons.js b/Commons.js index 7e4f4b388..f11a46836 100644 --- a/Commons.js +++ b/Commons.js @@ -2691,6 +2691,17 @@ } if (periods > lastPeriodAnnounced) { + + let formulaValue + if (announcement.formula !== undefined) { + try { + formulaValue = eval(announcement.formula.code); + } catch (err) { + announcement.formula.error = err.message + } + } + announcement.formulaValue = formulaValue + bot.SESSION.socialBots.announce(announcement) /* Next, we will remmeber this announcement was already done, so that it is not announced again in further processing of the same day. */ From a91f618d243dcdf927bffdd2d833dc49604784e9 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 21 Oct 2019 11:03:30 +0200 Subject: [PATCH 239/244] Announcements at Phases when formula value changes --- Commons.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Commons.js b/Commons.js index f11a46836..9a971641a 100644 --- a/Commons.js +++ b/Commons.js @@ -1445,6 +1445,8 @@ if (phase !== undefined) { if (phase.formula !== undefined) { + let previousValue = stopLoss + stopLoss = formulas.get(key) if (processingDailyFiles) { @@ -1452,7 +1454,11 @@ yesterday.stopLoss = stopLoss } } - } + + if (stopLoss !== previousValue) { + checkAnnouncements(phase) + } + } } } @@ -1568,12 +1574,19 @@ if (phase !== undefined) { if (phase.formula !== undefined) { + + let previousValue = stopLoss + takeProfit = formulas.get(key) if (processingDailyFiles) { if (positionedAtYesterday) { yesterday.takeProfit = takeProfit } } + + if (takeProfit !== previousValue) { + checkAnnouncements(phase) + } } } } From 26b50a23b471c1086431a7dc1e4e430ea518531f Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 21 Oct 2019 12:37:54 +0200 Subject: [PATCH 240/244] Value Variation Implemented --- Commons.js | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/Commons.js b/Commons.js index 9a971641a..23ed8252e 100644 --- a/Commons.js +++ b/Commons.js @@ -1456,7 +1456,7 @@ } if (stopLoss !== previousValue) { - checkAnnouncements(phase) + checkAnnouncements(phase, stopLoss) } } } @@ -1585,7 +1585,7 @@ } if (takeProfit !== previousValue) { - checkAnnouncements(phase) + checkAnnouncements(phase, takeProfit) } } } @@ -2685,14 +2685,20 @@ } } - function checkAnnouncements(node) { + function checkAnnouncements(node, value) { + /* + Value is an optional parameter that represents the value that the announcement is monitoring for change. + If we do receive this value, we will only make the annoucement if the variance is grater than the user pre-defined value + for this variance. + */ + if (node.announcements !== undefined) { for (let i = 0; i < node.announcements.length; i++) { let announcement = node.announcements[i] let key = node.type + "-" + announcement.name + "-" + announcement.id let lastPeriodAnnounced = -1 - let newAnnouncementRecord + let newAnnouncementRecord = {} for (let j = 0; j < interExecutionMemory.announcements.length; j++) { let announcementRecord = interExecutionMemory.announcements[j] @@ -2705,6 +2711,25 @@ 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 valueVariantion + try { + let code = JSON.parse(announcement.code) + valueVariantion = code.valueVariantion + } catch (err) { + announcement.error = err.message + } + + if (newAnnouncementRecord.value !== undefined && valueVariantion !== undefined) { + let upperLimit = newAnnouncementRecord.value + newAnnouncementRecord.value * valueVariantion / 100 + let lowerLimit = newAnnouncementRecord.value - newAnnouncementRecord.value * valueVariantion / 100 + if (value > lowerLimit && value < upperLimit ) { + /* There is not enough variation to announce this again. */ + return + } + } + + /* Here we check if there is a formula attached to the annoucement, we evaluate it to get the annoucement text. */ let formulaValue if (announcement.formula !== undefined) { try { @@ -2718,12 +2743,14 @@ bot.SESSION.socialBots.announce(announcement) /* Next, we will remmeber this announcement was already done, so that it is not announced again in further processing of the same day. */ - if (newAnnouncementRecord !== undefined) { + if (newAnnouncementRecord.periods !== undefined) { newAnnouncementRecord.periods = periods + newAnnouncementRecord.value = value } else { newAnnouncementRecord = { key: key, - periods: periods + periods: periods, + value: value } interExecutionMemory.announcements.push(newAnnouncementRecord) } From 6c5a210ca87c704ae2755dd05661cd09cf725de8 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 27 Oct 2019 11:32:41 +0100 Subject: [PATCH 241/244] Refactoring --- this.bot.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/this.bot.config.json b/this.bot.config.json index 82e37a4a1..8361d7bf1 100644 --- a/this.bot.config.json +++ b/this.bot.config.json @@ -1,7 +1,7 @@ { "displayName": "Jason", "codeName": "AAJason", - "type": "Trading Engine", + "type": "Trading Bot", "version": { "major": 1, "minor": 0, From 353e968770f3e9f9cf408c24639056c369a8179a Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 27 Oct 2019 22:08:58 +0100 Subject: [PATCH 242/244] Name correction --- AAJason-Indicator-Bot.sln => AAJason-Trading-Bot.sln | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename AAJason-Indicator-Bot.sln => AAJason-Trading-Bot.sln (100%) diff --git a/AAJason-Indicator-Bot.sln b/AAJason-Trading-Bot.sln similarity index 100% rename from AAJason-Indicator-Bot.sln rename to AAJason-Trading-Bot.sln From 166394f2e45e648118fa1c3f163151ae3048ea6e Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 19 Nov 2019 10:06:02 +0100 Subject: [PATCH 243/244] Bug Fixed after changes with Indicators fromUI --- Multi-Period/User.Bot.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Multi-Period/User.Bot.js b/Multi-Period/User.Bot.js index 7ee305706..658848110 100644 --- a/Multi-Period/User.Bot.js +++ b/Multi-Period/User.Bot.js @@ -83,11 +83,11 @@ switch (i) { case 0: { - commons.buildPercentageBandwidthArray(dataFile, mapKey, callBackFunction); + commons.buildBollingerBandsArray(dataFile, mapKey, callBackFunction); break; } case 1: { - commons.buildBollingerBandsArray(dataFile, mapKey, callBackFunction); + commons.buildPercentageBandwidthArray(dataFile, mapKey, callBackFunction); break; } case 2: { @@ -121,11 +121,11 @@ switch (i) { case 0: { - commons.buildPercentageBandwidthArray(dataFile, mapKey, callBackFunction); + commons.buildBollingerBandsArray(dataFile, mapKey, callBackFunction); break; } case 1: { - commons.buildBollingerBandsArray(dataFile, mapKey, callBackFunction); + commons.buildPercentageBandwidthArray(dataFile, mapKey, callBackFunction); break; } case 2: { From 121572db6d1a9b296b61b4ca7ccfe99a4b42c416 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Thu, 21 Nov 2019 11:59:58 +0100 Subject: [PATCH 244/244] Final Commit --- Commons.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Commons.js b/Commons.js index 23ed8252e..7b8bc19bf 100644 --- a/Commons.js +++ b/Commons.js @@ -24,7 +24,7 @@ let bollingerChannelsAt = {} let bollingerSubChannelsAt = {} let candlesAt = {} - let processingDailyFiles + return thisObject; @@ -49,7 +49,7 @@ try { if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Entering function."); } - + let processingDailyFiles if (timePeriod > global.dailyFilePeriods[0][0]) { processingDailyFiles = false } else {