From 1e4d187222123ad0f0fd53267a4c59b540e3a574 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 10 Aug 2019 00:15:47 +0200 Subject: [PATCH 1/5] timePeriod and beginDate coming at simulationParams --- MultiPeriodDaily.js | 2 +- MultiPeriodMarket.js | 2 +- Run.js | 55 +++++++++++++++++++++++++++++++++----------- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/MultiPeriodDaily.js b/MultiPeriodDaily.js index 66a220f4e..003f97ec8 100644 --- a/MultiPeriodDaily.js +++ b/MultiPeriodDaily.js @@ -370,7 +370,7 @@ } } - let timePeriodFilter = process.env.TIME_PERIOD + let timePeriodFilter = global.EXECUTION_CONFIG.timePeriodFileStorage if (timePeriodFilter !== undefined) { if (timePeriodFilter.indexOf(outputPeriodLabel) === -1) { periodsControlLoop(); diff --git a/MultiPeriodMarket.js b/MultiPeriodMarket.js index d5bf944ee..ceab3ff19 100644 --- a/MultiPeriodMarket.js +++ b/MultiPeriodMarket.js @@ -141,7 +141,7 @@ let dependencyIndex = 0; dataFiles = []; - let timePeriodFilter = process.env.TIME_PERIOD + let timePeriodFilter = global.EXECUTION_CONFIG.timePeriodFileStorage if (timePeriodFilter !== undefined) { if (timePeriodFilter.indexOf(outputPeriodLabel) === -1) { periodsControlLoop(); diff --git a/Run.js b/Run.js index dcaa1f688..5760e67a3 100644 --- a/Run.js +++ b/Run.js @@ -69,7 +69,7 @@ function sequenceExecution(currentStep) { processedSteps.set(stepKey, 0); } console.log("Sequence Execution Parameters: " + JSON.stringify(execution)) - readExecutionConfiguration(); + readExecutionConfiguration(execution.type); sequenceStep++; } @@ -97,24 +97,49 @@ function onExecutionFinish (result, finishStepKey) { } -async function readExecutionConfiguration() { +async function readExecutionConfiguration(botType) { try { console.log("[INFO] Run -> readExecutionConfiguration -> Entering function. "); + let timePeriod + let botProcess + /* Try to get the begin and end dates from the Definition */ let definition = await strategy.getStrategy() + + /* Dates are taken initially from .env, but can be overwritten if they are defined by the user */ let initialDatetime = process.env.BEGIN_DATE_TIME let finalDatetime = process.env.END_DATE_TIME - if (definition !== undefined) { - 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) - initialDatetime = code.initialDatetime - finalDatetime = code.finalDatetime + if (botType === 'Trading-Engine') { + if (definition !== undefined) { + if (definition.simulationParams !== undefined) { + if (definition.simulationParams.beginDatetime !== undefined) { + initialDatetime = new Date(definition.simulationParams.beginDatetime) /* The first override occurs here, with the simulation parameters */ + } + /* Here we only look for one timePeriod, in the future we will be able to process the whole array, but not for now. */ + if (definition.simulationParams.timePeriodDailyArray !== undefined) { + if (definition.simulationParams.timePeriodDailyArray.length > 0) { + timePeriod = definition.simulationParams.timePeriodDailyArray[0] + botProcess = "Multi-Period-Daily" + } + } + if (definition.simulationParams.timePeriodMarketArray !== undefined) { + if (definition.simulationParams.timePeriodMarketArray.length > 0) { + timePeriod = definition.simulationParams.timePeriodMarketArray[0] + botProcess = "Multi-Period-Market" + } + } + } + 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) + initialDatetime = code.initialDatetime /* The second override occurs here, with the date explicitelly defined by the user */ + finalDatetime = code.finalDatetime + } } } } @@ -189,19 +214,21 @@ async function readExecutionConfiguration() { startMode[process.env.START_MODE].run = "true" + if (botProcess === undefined) { botProcess = process.env.PROCESS } // Only use the .env when nothing comes at Definition.json let cloneToExecute = { enabled: "true", devTeam: process.env.DEV_TEAM, bot: process.env.BOT, - process: process.env.PROCESS, + process: botProcess, repo: global.CURRENT_BOT_REPO } + if (timePeriod === undefined) { timePeriod = process.env.TIME_PERIOD} // Only use the .env when nothing comes at Definition.json global.EXECUTION_CONFIG = { cloneToExecute: cloneToExecute, startMode: startMode, - timePeriod: getTimePeriod(process.env.TIME_PERIOD), - timePeriodFileStorage: process.env.TIME_PERIOD, + timePeriod: getTimePeriod(timePeriod), + timePeriodFileStorage: timePeriod, dataSet: process.env.DATA_SET }; From 2f60782dd90720f24fc21eeb5429b13083a2adde Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 10 Aug 2019 01:00:16 +0200 Subject: [PATCH 2/5] BUG FIXES with bothasjuststarted and initialdatetime --- Root.js | 6 +-- Run.js | 35 +++++++------ sequence.json | 133 +------------------------------------------------- 3 files changed, 24 insertions(+), 150 deletions(-) diff --git a/Root.js b/Root.js index 657b41f65..fe4275081 100644 --- a/Root.js +++ b/Root.js @@ -345,7 +345,7 @@ let month = pad((new Date()).getUTCMonth() + 1, 2); let year = (new Date()).getUTCFullYear(); - if (processConfig.startMode.noTime.resumeExecution === "true") { + if (processConfig.startMode.noTime.resumeExecution === true) { botConfig.hasTheBotJustStarted = false; } else { botConfig.hasTheBotJustStarted = true; @@ -403,7 +403,7 @@ let month = pad((new Date()).getUTCMonth() + 1, 2); let year = (new Date()).getUTCFullYear(); - if (processConfig.startMode.live.resumeExecution === "true") { + if (processConfig.startMode.live.resumeExecution === true) { botConfig.hasTheBotJustStarted = false; } else { botConfig.hasTheBotJustStarted = true; @@ -459,7 +459,7 @@ botConfig.competition = processConfig.startMode.competition; - if (processConfig.startMode.competition.resumeExecution === "false") { + if (processConfig.startMode.competition.resumeExecution === false) { botConfig.hasTheBotJustStarted = true; } else { botConfig.hasTheBotJustStarted = false; diff --git a/Run.js b/Run.js index 5760e67a3..4d29c03eb 100644 --- a/Run.js +++ b/Run.js @@ -35,18 +35,19 @@ if (process.env.RUN_SEQUENCE !== undefined) { } if (isRunSequence) { - sequenceExecution(sequenceStep) + sequenceExecution(sequenceStep, false) } else { readExecutionConfiguration() } -function sequenceExecution(currentStep) { +function sequenceExecution(currentStep, notFirstSequence) { let execution = sequenceList[currentStep]; + process.env.STOP_GRACEFULLY = true; execution.devTeam ? process.env.DEV_TEAM = execution.devTeam : undefined; execution.bot ? process.env.BOT = execution.bot : undefined; execution.mode ? process.env.START_MODE = execution.mode : undefined; - execution.resumeExecution ? process.env.RESUME_EXECUTION = execution.resumeExecution : undefined; + execution.resumeExecution = notFirstSequence execution.type ? process.env.TYPE = execution.type : undefined; execution.process ? process.env.PROCESS = execution.process : undefined; execution.startYear ? process.env.MIN_YEAR = execution.startYear : undefined; @@ -69,7 +70,7 @@ function sequenceExecution(currentStep) { processedSteps.set(stepKey, 0); } console.log("Sequence Execution Parameters: " + JSON.stringify(execution)) - readExecutionConfiguration(execution.type); + readExecutionConfiguration(execution); sequenceStep++; } @@ -79,17 +80,17 @@ function onExecutionFinish (result, finishStepKey) { console.log('[INFO] onExecutionFinish -> Step already processed.') } else { if (sequenceStep < sequenceList.length) { - sequenceExecution(sequenceStep) + sequenceExecution(sequenceStep, true) } else { if (sequenceStep < sequenceList.length) { - sequenceExecution(sequenceStep); + sequenceExecution(sequenceStep, true); } else { setTimeout(function () { console.log("[INFO] onExecutionFinish -> New round for sequence execution started."); sequenceList = require('./sequence'); // We read again the sequence after every loop sequenceStep = 0; processedSteps = new Map(); - sequenceExecution(sequenceStep); + sequenceExecution(sequenceStep, true); }, process.env.EXECUTION_LOOP_DELAY); } } @@ -97,7 +98,7 @@ function onExecutionFinish (result, finishStepKey) { } -async function readExecutionConfiguration(botType) { +async function readExecutionConfiguration(execution) { try { console.log("[INFO] Run -> readExecutionConfiguration -> Entering function. "); @@ -111,7 +112,7 @@ async function readExecutionConfiguration(botType) { let initialDatetime = process.env.BEGIN_DATE_TIME let finalDatetime = process.env.END_DATE_TIME - if (botType === 'Trading-Engine') { + if (execution.type === 'Trading-Engine') { if (definition !== undefined) { if (definition.simulationParams !== undefined) { if (definition.simulationParams.beginDatetime !== undefined) { @@ -137,8 +138,12 @@ async function readExecutionConfiguration(botType) { 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) - initialDatetime = code.initialDatetime /* The second override occurs here, with the date explicitelly defined by the user */ - finalDatetime = code.finalDatetime + if (code.initialDatetime !== undefined) { + initialDatetime = code.initialDatetime /* The second override occurs here, with the date explicitelly defined by the user */ + } + if (code.finalDatetime !== undefined) { + finalDatetime = code.finalDatetime + } } } } @@ -156,21 +161,21 @@ async function readExecutionConfiguration(botType) { if (process.env.TYPE === 'Trading' || process.env.TYPE === 'Trading-Engine') { let live = { run: 'false', - resumeExecution: process.env.RESUME_EXECUTION, + resumeExecution: execution.resumeExecution, beginDatetime: initialDatetime, endDatetime: finalDatetime } let backtest = { run: 'false', - resumeExecution: process.env.RESUME_EXECUTION, + resumeExecution: execution.resumeExecution, beginDatetime: initialDatetime, endDatetime: finalDatetime } let competition = { run: 'false', - resumeExecution: process.env.RESUME_EXECUTION, + resumeExecution: execution.resumeExecution, beginDatetime: initialDatetime, endDatetime: finalDatetime } @@ -194,7 +199,7 @@ async function readExecutionConfiguration(botType) { let noTime = { run: "false", beginDatetime: process.env.BEGIN_DATE_TIME, - resumeExecution: process.env.RESUME_EXECUTION + resumeExecution: execution.resumeExecution } let fixedInterval = { run: "false", diff --git a/sequence.json b/sequence.json index 10ca0ec47..401cc5ecf 100644 --- a/sequence.json +++ b/sequence.json @@ -1,136 +1,5 @@ [ - { - "devTeam": "AAMasters", - "bot": "AACharly", - "mode": "noTime", - "resumeExecution": true, - "type": "Sensor", - "exchangeName": "Poloniex", - "process": "Live-Trades", - "startYear": 2019, - "endYear": 2021, - "month": 1 - }, - { - "devTeam": "AAMasters", - "bot": "AACharly", - "mode": "noTime", - "resumeExecution": true, - "type": "Sensor", - "exchangeName": "Poloniex", - "process": "Hole-Fixing", - "startYear": 2019, - "endYear": 2021, - "month": 1 - }, - { - "devTeam": "AAMasters", - "bot": "AABruce", - "mode": "noTime", - "resumeExecution": true, - "type": "Indicator", - "exchangeName": "Poloniex", - "process": "Single-Period-Daily", - "startYear": 2019, - "endYear": 2021, - "month": 1 - }, - { - "devTeam": "AAMasters", - "bot": "AAOlivia", - "mode": "noTime", - "resumeExecution": true, - "type": "Indicator", - "exchangeName": "Poloniex", - "process": "Multi-Period-Daily", - "startYear": 2019, - "endYear": 2021, - "month": 1 - }, - { - "devTeam": "AAMasters", - "bot": "AAOlivia", - "mode": "noTime", - "resumeExecution": true, - "type": "Indicator", - "exchangeName": "Poloniex", - "process": "Multi-Period-Market", - "startYear": 2019, - "endYear": 2021, - "month": 1 - }, - { - "devTeam": "AAMasters", - "bot": "AATom", - "mode": "noTime", - "resumeExecution": true, - "type": "Indicator", - "exchangeName": "Poloniex", - "process": "Multi-Period-Daily", - "startYear": 2019, - "endYear": 2021, - "month": 1 - }, - { - "devTeam": "AAMasters", - "bot": "AATom", - "mode": "noTime", - "resumeExecution": true, - "type": "Indicator", - "exchangeName": "Poloniex", - "process": "Multi-Period-Market", - "startYear": 2019, - "endYear": 2021, - "month": 1 - }, - { - "devTeam": "AAMasters", - "bot": "AAChris", - "mode": "noTime", - "resumeExecution": true, - "type": "Indicator", - "exchangeName": "Poloniex", - "process": "Multi-Period-Daily", - "startYear": 2019, - "endYear": 2021, - "month": 1 - }, - { - "devTeam": "AAMasters", - "bot": "AAChris", - "mode": "noTime", - "resumeExecution": true, - "type": "Indicator", - "exchangeName": "Poloniex", - "process": "Multi-Period-Market", - "startYear": 2019, - "endYear": 2021, - "month": 1 - }, - { - "devTeam": "AAMasters", - "bot": "AAPaula", - "mode": "noTime", - "resumeExecution": true, - "type": "Indicator", - "exchangeName": "Poloniex", - "process": "Multi-Period-Daily", - "startYear": 2019, - "endYear": 2021, - "month": 1 - }, - { - "devTeam": "AAMasters", - "bot": "AAPaula", - "mode": "noTime", - "resumeExecution": true, - "type": "Indicator", - "exchangeName": "Poloniex", - "process": "Multi-Period-Market", - "startYear": 2019, - "endYear": 2021, - "month": 1 - }, + { "devTeam": "AAMasters", "bot": "AAJason", From 881c17951e3dcdedb5172221814b9fd8f0c7ddfc Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 10 Aug 2019 11:15:44 +0200 Subject: [PATCH 3/5] s --- Run.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Run.js b/Run.js index 4d29c03eb..785bfb0d1 100644 --- a/Run.js +++ b/Run.js @@ -141,7 +141,7 @@ async function readExecutionConfiguration(execution) { if (code.initialDatetime !== undefined) { initialDatetime = code.initialDatetime /* The second override occurs here, with the date explicitelly defined by the user */ } - if (code.finalDatetime !== undefined) { + if (code.finalDatetime !== undefined) { finalDatetime = code.finalDatetime } } From 5e67457875a9f75de02d732b2659e50c1afc869f Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 10 Aug 2019 12:41:04 +0200 Subject: [PATCH 4/5] BUG FIXED: Context has its own stauts report --- Commons.js | 2349 ------------------------------- Context.js | 2 +- Project.njsproj | 2 - StatusReport.js | 4 +- TradingEngineProcessMainLoop.js | 8 +- User.Bot.js | 556 -------- 6 files changed, 7 insertions(+), 2914 deletions(-) delete mode 100644 Commons.js delete mode 100644 User.Bot.js diff --git a/Commons.js b/Commons.js deleted file mode 100644 index c03e873f7..000000000 --- a/Commons.js +++ /dev/null @@ -1,2349 +0,0 @@ -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() - - const FULL_LOG = true; - 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 = { - 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 = []; - } - - async function runSimulation( - timePeriod, - currentDay, - startDate, - endDate, - interExecutionMemory, - assistant, - callback, - callBackFunction) { - - try { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Entering function."); } - - let executionArray = []; - let recordsArray = []; - let conditionsArray = []; - let strategiesArray = []; - let tradesArray = []; - let lastObjectsArray = []; - - let definition = await strategy.getStrategy(); - let tradingSystem = definition.tradingSystem; - - /* Initial Default Values */ - - 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 - 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) { - 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' - } - } - - 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 - } - } - } catch (err) { - tradingSystem.parameters.baseAsset.formula.error = err.message - } - } - } - } - - /* 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 */ - - 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; - 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; - let anualizedRateOfReturn = 0; - let type = '""'; - 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; - 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 - 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 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 = initialBalanceB; - - let lastTradeProfitLoss = 0; - let profit = 0; - let lastTradeROI = 0; - - let roundtrips = 0; - let fails = 0; - let hits = 0; - let periods = 0; - - /* Message to the Simulation Executor */ - - let orderId = 0; - let messageId = 0; - - let yesterday = {}; - - yesterday.balanceAssetA = balanceAssetA; - yesterday.balanceAssetB = balanceAssetB; - - yesterday.lastTradeProfitLoss = 0; - yesterday.profit = 0; - yesterday.lastTradeROI = 0; - - yesterday.Roundtrips = 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. */ - - interExecutionMemory.balanceAssetA = balanceAssetA; - interExecutionMemory.balanceAssetB = balanceAssetB; - - interExecutionMemory.lastTradeProfitLoss = lastTradeProfitLoss; - interExecutionMemory.profit = profit; - interExecutionMemory.lastTradeROI = lastTradeROI; - - interExecutionMemory.roundtrips = 0; - interExecutionMemory.fails = 0; - interExecutionMemory.hits = 0; - interExecutionMemory.periods = 0; - - 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 */ - - 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; - - yesterday.balanceAssetA = balanceAssetA; - yesterday.balanceAssetB = balanceAssetB; - - } - - lastTradeProfitLoss = interExecutionMemory.lastTradeProfitLoss; - profit = interExecutionMemory.profit; - lastTradeROI = interExecutionMemory.lastTradeROI; - - roundtrips = interExecutionMemory.roundtrips; - fails = interExecutionMemory.fails; - hits = interExecutionMemory.hits; - periods = interExecutionMemory.periods; - - orderId = interExecutionMemory.orderId; - messageId = interExecutionMemory.messageId; - - hitRatio = interExecutionMemory.hitRatio; - ROI = interExecutionMemory.ROI; - anualizedRateOfReturn = interExecutionMemory.anualizedRateOfReturn; - - 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); } - - 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]; - 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 any of the needed indicators is missing, then that period is not calculated */ - - 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) { controlLoop(); return} - - 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++; - } - - /* 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)) { - /*We are at the head of the market, thus we skip the last candle because it has not close yet. */ - controlLoop(); - return - /* Note here that in the last candle of the first day or the second day it will use an incomplete candle and partially calculated indicators. - if we skip these two 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(); - 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; - 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); - - 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 - - /* Continue with the rest of the formulas and conditions */ - - 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); - } - } - } - } - - 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); - } - } - } - } - } - - let openStage = strategy.openStage - - 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++) { - - 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) { - formulaError = "Formula evaluates to Infinity." - formulaValue = MAX_TAKE_PROFIT_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_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) { - - 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); - } - } - } - } - } - } - } - - strategy.positionSize = positionSize - strategy.positionRate = positionRate - } - - 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]; - - /* 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 + '-' + '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); - } - } - } - } - } - } - - if (manageStage.takeProfit !== undefined) { - - for (let p = 0; p < manageStage.takeProfit.phases.length; p++) { - - let phase = manageStage.takeProfit.phases[p]; - - /* Evaluate Formula */ - let formulaValue - let formulaError = '' - - 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) { - 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 - } - - 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') > 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 { - conditionsArrayValues.push(0); - } - } - } - } - - /* Trigger On Conditions */ - if ( - strategyStage === 'No Stage' && - currentStrategyIndex === -1 - ) { - let minimumBalance - let maximumBalance - let balance - - if (baseAsset === 'BTC') { - balance = balanceAssetA - minimumBalance = minimumBalanceA - maximumBalance = maximumBalanceA - } else { - balance = balanceAssetB - minimumBalance = minimumBalanceB - maximumBalance = maximumBalanceB - } - - if (balance > minimumBalance && balance < maximumBalance) { - - /* - Here we need to pick a strategy, or if there is not suitable strategy for the current - market conditions, we pass until the next period. - - 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++) { - - 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]; - let passed = true; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m; - - let value = false - if (conditions.get(key) !== undefined) { - value = conditions.get(key).value; - } - - if (value === false) { passed = false; } - } - - 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; - } - } - } - } - } - } else { - let stopRunningDate = new Date(candle.begin) - if (balance < minimumBalance) { - tradingSystem.error = "Min Balance @ " + stopRunningDate.toUTCString() - } - if (balance > maximumBalance) { - tradingSystem.error = "Max Balance @ " + stopRunningDate.toUTCString() - } - } - } - - /* Trigger Off Condition */ - if (strategyStage === 'Trigger Stage') { - - let strategy = tradingSystem.strategies[currentStrategyIndex]; - - let triggerStage = strategy.triggerStage - - if (triggerStage !== undefined) { - - if (triggerStage.triggerOff !== undefined) { - - for (let k = 0; k < triggerStage.triggerOff.situations.length; k++) { - - let situation = triggerStage.triggerOff.situations[k]; - let passed = true; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = currentStrategyIndex + '-' + 'triggerStage' + '-' + 'triggerOff' + '-' + k + '-' + m; - - let value = false - if (conditions.get(key) !== undefined) { - value = conditions.get(key).value; - } - - 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 = -1; - break; - } - } - } - } - } - - /* 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 = false - if (conditions.get(key) !== undefined) { - value = conditions.get(key).value; - } - - if (value === false) { passed = false; } - } - - if (passed) { - - type = '"Take Position"'; - - 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 ( - (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') && - takePositionNow !== true - ) { - - checkStopPhases() - calculateStopLoss(); - - } - - function checkStopPhases() { - - 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 (stopLossStage === 'Open Stage' && openStage !== undefined) { - if (openStage.initialDefinition !== undefined) { - if (openStage.initialDefinition.stopLoss !== undefined) { - parentNode = openStage.initialDefinition - initialDefinitionKey = '-' + 'initialDefinition' - stageKey = 'openStage' - p = stopLossPhase - 1 - } - } - } - - if (stopLossStage === 'Manage Stage' && manageStage !== undefined) { - if (manageStage.stopLoss !== undefined) { - parentNode = manageStage - stageKey = 'manageStage' - p = stopLossPhase - 2 - } - } - - let phase = parentNode.stopLoss.phases[p]; - - let nextPhaseEvent = phase.nextPhaseEvent; - if (nextPhaseEvent !== undefined) { - - for (let k = 0; k < nextPhaseEvent.situations.length; k++) { - - let situation = nextPhaseEvent.situations[k]; - let passed = true; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'stopLoss' + '-' + p + '-' + k + '-' + m; - - let value = false - if (conditions.get(key) !== undefined) { - value = conditions.get(key).value; - } - - if (value === false) { passed = false; } - } - - if (passed) { - - stopLossPhase++; - stopLossStage = 'Manage Stage' - if (takeProfitPhase > 1) { strategyStage = 'Manage Stage' } - return; - } - } - } - } - - function calculateStopLoss() { - - let strategy = tradingSystem.strategies[currentStrategyIndex]; - 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); - } - } - } - - if (stopLossStage === 'Manage Stage' && manageStage !== undefined) { - if (manageStage.stopLoss !== undefined) { - phase = manageStage.stopLoss.phases[stopLossPhase - 2]; - key = currentStrategyIndex + '-' + 'manageStage' + '-' + 'stopLoss' + '-' + (stopLossPhase - 2); - } - } - - if (phase !== undefined) { - if (phase.formula !== undefined) { - stopLoss = formulas.get(key) - } - } - } - - /* Take Profit Management */ - if ( - (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') && - takePositionNow !== true - ) { - - checkTakeProfitPhases(); - calculateTakeProfit(); - - } - - function checkTakeProfitPhases() { - - 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 (takeProfitStage === 'Open Stage' && openStage !== undefined) { - if (openStage.initialDefinition !== undefined) { - if (openStage.initialDefinition.takeProfit !== undefined) { - parentNode = openStage.initialDefinition - initialDefinitionKey = '-' + 'initialDefinition' - stageKey = 'openStage' - p = takeProfitPhase - 1 - } - } - } - - if (takeProfitStage === 'Manage Stage' && manageStage !== undefined) { - if (manageStage.takeProfit !== undefined) { - parentNode = manageStage - stageKey = 'manageStage' - p = takeProfitPhase - 2 - } - } - - let phase = parentNode.takeProfit.phases[p]; - - let nextPhaseEvent = phase.nextPhaseEvent; - if (nextPhaseEvent !== undefined) { - - for (let k = 0; k < nextPhaseEvent.situations.length; k++) { - - let situation = nextPhaseEvent.situations[k]; - let passed = true; - - for (let m = 0; m < situation.conditions.length; m++) { - - let condition = situation.conditions[m]; - let key = j + '-' + stageKey + initialDefinitionKey + '-' + 'takeProfit' + '-' + p + '-' + k + '-' + m; - - let value = false - if (conditions.get(key) !== undefined) { - value = conditions.get(key).value; - } - - if (value === false) { passed = false; } - } - - if (passed) { - - takeProfitPhase++; - takeProfitStage = 'Manage Stage' - if (stopLossPhase > 1) { strategyStage = 'Manage Stage' } - return; - } - } - } - } - - function calculateTakeProfit() { - - let strategy = tradingSystem.strategies[currentStrategyIndex]; - 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' + '-' + (takeProfitPhase - 1); - } - } - } - - if (takeProfitStage === 'Manage Stage' && manageStage !== undefined) { - if (manageStage.takeProfit !== undefined) { - phase = manageStage.takeProfit.phases[takeProfitPhase - 2]; - key = currentStrategyIndex + '-' + 'manageStage' + '-' + 'takeProfit' + '-' + (takeProfitPhase - 2); - } - } - - 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') && - 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. */ - - /* 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') { - 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; - } - - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { - yesterday.balanceAssetA = balanceAssetA; - yesterday.balanceAssetB = balanceAssetB; - } - } - - marketRate = stopLoss; - type = '"Close@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') { - 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; - } - - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { - yesterday.balanceAssetA = balanceAssetA; - yesterday.balanceAssetB = balanceAssetB; - - } - } - - marketRate = takeProfit; - type = '"Close@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; - } - } - - /* Taking a Position */ - if ( - takePositionNow === true - ) { - takePositionNow = false - - /* 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) { - 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 "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. - break - } - 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) { - putOpeningOrder() - return - } - } - } - - takePositionAtSimulation() - return - - function putOpeningOrder() { - - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> 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()) { - 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.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, openPositionRate, amountA, amountB, onOrderPut) - - function onOrderPut(err) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> 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 "); } - 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; - } - } - 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 - } - } - } - - 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 */ - if (strategyStage === 'Close Stage') { - - /* 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. - break - } - case "In a Position": { // This should mean that we already put the order at the exchange. - if (strategy.closeStage !== undefined) { - if (strategy.closeStage.closeExecution !== undefined) { - putClosingOrder() - return - } - } - break - } - case "Closing Position": { // Waiting for a confirmation that the position was taken. - if (strategy.closeStage !== undefined) { - if (strategy.closeStage.closeExecution !== undefined) { - putClosingOrder() - return - } - } - break - } - - case "Position Closed": { // - break - } - } - } - - closePositionAtSimulation() - return - - function putClosingOrder() { - - 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[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) { - 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, closePositionRate, amountA, amountB, onOrderPut) - - function onOrderPut(err) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> 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 "); } - 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; - } - } - 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 - } - } - } - - function closePositionAtSimulation() { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> closePositionAtSimulation -> Entering function."); } - - roundtrips++; - - if (currentDay !== undefined) { - if (positionInstant < currentDay.valueOf()) { - yesterday.Roundtrips++; - } - } - - 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.lastTradeProfitLoss = lastTradeProfitLoss; - yesterday.profit = profit; - yesterday.lastTradeROI = lastTradeROI; - } - } - - currentTrade.lastTradeROI = lastTradeROI; - currentTrade.stopRate = stopLoss; - - 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 - } - } - - /* Not a buy or sell condition */ - - 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; - 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 -> 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 = "" - 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) { - case 'No Stage': { - strategyStageNumber = 0 - break - } - case 'Trigger Stage': { - strategyStageNumber = 1 - break - } - case 'Open Stage': { - strategyStageNumber = 2 - break - } - case 'Manage Stage': { - strategyStageNumber = 3 - break - } - case 'Close Stage': { - strategyStageNumber = 4 - break - } - } - - if (balanceAssetA === Infinity) { - balanceAssetA = Number.MAX_SAFE_INTEGER - } - - if (balanceAssetB === Infinity) { - balanceAssetB = Number.MAX_SAFE_INTEGER - } - - let quotedBaseAsset = '"' + baseAsset + '"' - - simulationRecord = { - begin: candle.begin, - end: candle.end, - type: type, - marketRate: marketRate, - amount: 1, - balanceA: balanceAssetA, - balanceB: balanceAssetB, - profit: profit, - lastTradeProfitLoss: lastTradeProfitLoss, - stopLoss: stopLoss, - roundtrips: roundtrips, - hits: hits, - fails: fails, - hitRatio: hitRatio, - ROI: ROI, - periods: periods, - days: days, - anualizedRateOfReturn: anualizedRateOfReturn, - positionRate: tradePositionRate, - lastTradeROI: lastTradeROI, - strategy: currentStrategyIndex, - strategyStageNumber: strategyStageNumber, - takeProfit: takeProfit, - stopLossPhase: stopLossPhase, - takeProfitPhase: takeProfitPhase, - executionRecord: executionMessage, - positionSize: tradePositionSize, - initialBalanceA: initialBalanceA, - minimumBalanceA: minimumBalanceA, - maximumBalanceA: maximumBalanceA, - initialBalanceB: initialBalanceB, - minimumBalanceB: minimumBalanceB, - maximumBalanceB: maximumBalanceB, - baseAsset: quotedBaseAsset - } - - recordsArray.push(simulationRecord); - - type = '""'; - - /* Prepare the information for the Conditions File */ - - conditionsArrayRecord.push(currentStrategyIndex); - conditionsArrayRecord.push(strategyStageNumber); - conditionsArrayRecord.push(stopLossPhase); - conditionsArrayRecord.push(takeProfitPhase); - conditionsArrayRecord.push(conditionsArrayValues); - conditionsArrayRecord.push(formulasErrors); - conditionsArrayRecord.push(formulasValues); - - conditionsArray.push(conditionsArrayRecord); - - /* Prepare the information for the Strategies File*/ - - if ( - (currentStrategy.begin !== 0 && currentStrategy.end !== 0) || - (currentStrategy.begin !== 0 && i === candles.length - 1 && lastCandle.end !== lastInstantOfTheDay) - ) { - - 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 && lastCandle.end !== lastInstantOfTheDay) - ) { - - currentTrade.profit = lastTradeProfitLoss; - - tradesArray.push(currentTrade); - - currentTrade = { - begin: 0, - end: 0, - status: 0, - lastTradeROI: 0, - exitType: 0, - beginRate: 0, - endRate: 0 - } - } - } - } - - function controlLoop() { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> controlLoop -> Entering function."); } - i++ - if (i < candles.length) { - loop() - } else { - afterLoop() - } - } - - 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); - } - - - 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 - } - } - - return - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] runSimulation -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildLRC(dataFile, callBackFunction) { - - 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.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildPercentageBandwidthMap(dataFile, callBackFunction) { - - 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.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildBollingerBandsMap(dataFile, callBackFunction) { - - 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.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildBollingerChannelsArray(dataFile, callBackFunction) { - - 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] - }; - - bollingerChannel.previous = previous; - - bollingerChannelsArray.push(bollingerChannel); - - previous = bollingerChannel; - } - } - catch (err) { - logger.write(MODULE_NAME, "[ERROR] buildBollingerChannelsArray -> err = " + err.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildBollingerSubChannelsArray(dataFile, callBackFunction) { - - 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.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } - - function buildCandles(dataFile, callBackFunction) { - - 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.stack); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - } -}; - - - diff --git a/Context.js b/Context.js index 19742d5db..47e9a960b 100644 --- a/Context.js +++ b/Context.js @@ -131,7 +131,7 @@ if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> getStatusReport -> Entering function."); } - let key = bot.devTeam + "-" + bot.codeName + "-" + bot.process + "-" + bot.dataSetVersion; + let key = bot.devTeam + "-" + bot.codeName + "-" + "Context" + "-" + bot.dataSetVersion; statusReportModule = statusDependencies.statusReports.get(key); thisObject.statusReport = statusReportModule.file; diff --git a/Project.njsproj b/Project.njsproj index b5d1b8cbb..53091cd23 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -24,7 +24,6 @@ Code - @@ -37,7 +36,6 @@ Code - Code diff --git a/StatusReport.js b/StatusReport.js index 9d2ca43f6..8be203686 100644 --- a/StatusReport.js +++ b/StatusReport.js @@ -162,7 +162,7 @@ let ownerId = owner.devTeam + "-" + owner.bot + "-" + owner.botVersion.major + "-" + owner.botVersion.minor + "-" + owner.process + "-" + owner.dataSetVersion; let botId = bot.devTeam + "-" + bot.codeName + "-" + bot.version.major + "-" + bot.version.minor + "-" + bot.process + "-" + bot.dataSetVersion; - if (ownerId !== botId) { + if (ownerId !== botId && owner.process !== "Context") { // Context is a special case where the report is created by the Context.js module itself. let customErr = { result: global.CUSTOM_FAIL_RESPONSE.result, @@ -176,7 +176,7 @@ let fileName = "Status.Report." + global.MARKET.assetA + '_' + global.MARKET.assetB + ".json"; let filePath = bot.filePathRoot + "/Reports/" + owner.process + timePath; - if (bot.type === 'Trading') { + if (bot.type === 'Trading' ) { fileName = bot.startMode + "." + fileName; } diff --git a/TradingEngineProcessMainLoop.js b/TradingEngineProcessMainLoop.js index de6e93245..19db8df72 100644 --- a/TradingEngineProcessMainLoop.js +++ b/TradingEngineProcessMainLoop.js @@ -56,8 +56,8 @@ } USER_BOT_MODULE = {} - USER_BOT_MODULE.newUserBot = require(ROOT_DIR + 'User.Bot').newUserBot // Use this for a better debugging experience. You need to bring this js module to this folder in order to work. - //USER_BOT_MODULE.newUserBot = eval(text); // Use this for production + //USER_BOT_MODULE.newUserBot = require(ROOT_DIR + 'User.Bot').newUserBot // Use this for a better debugging experience. You need to bring this js module to this folder in order to work. + USER_BOT_MODULE.newUserBot = eval(text); // Use this for production filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo; filePath += "/Commons.js" @@ -72,8 +72,8 @@ return; } COMMONS_MODULE = {} - COMMONS_MODULE.newCommons = require(ROOT_DIR + 'Commons').newCommons // Use this for a better debugging experience. You need to bring this js module to this folder in order to work. - //COMMONS_MODULE.newCommons = eval(text); // Use this for production + //COMMONS_MODULE.newCommons = require(ROOT_DIR + 'Commons').newCommons // Use this for a better debugging experience. You need to bring this js module to this folder in order to work. + COMMONS_MODULE.newCommons = eval(text); // Use this for production callBackFunction(global.DEFAULT_OK_RESPONSE); } diff --git a/User.Bot.js b/User.Bot.js deleted file mode 100644 index ca0130408..000000000 --- a/User.Bot.js +++ /dev/null @@ -1,556 +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 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; - - } - - 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]; - - /* 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 + "]"; - - 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 + "," + - record.stopRate + "]"; - - 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); - } - } -}; From f7cc7af3712e87657836054251c66d37fc115efb Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 10 Aug 2019 12:46:15 +0200 Subject: [PATCH 5/5] Full sequence working --- sequence.json | 133 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 132 insertions(+), 1 deletion(-) diff --git a/sequence.json b/sequence.json index 401cc5ecf..10ca0ec47 100644 --- a/sequence.json +++ b/sequence.json @@ -1,5 +1,136 @@ [ - + { + "devTeam": "AAMasters", + "bot": "AACharly", + "mode": "noTime", + "resumeExecution": true, + "type": "Sensor", + "exchangeName": "Poloniex", + "process": "Live-Trades", + "startYear": 2019, + "endYear": 2021, + "month": 1 + }, + { + "devTeam": "AAMasters", + "bot": "AACharly", + "mode": "noTime", + "resumeExecution": true, + "type": "Sensor", + "exchangeName": "Poloniex", + "process": "Hole-Fixing", + "startYear": 2019, + "endYear": 2021, + "month": 1 + }, + { + "devTeam": "AAMasters", + "bot": "AABruce", + "mode": "noTime", + "resumeExecution": true, + "type": "Indicator", + "exchangeName": "Poloniex", + "process": "Single-Period-Daily", + "startYear": 2019, + "endYear": 2021, + "month": 1 + }, + { + "devTeam": "AAMasters", + "bot": "AAOlivia", + "mode": "noTime", + "resumeExecution": true, + "type": "Indicator", + "exchangeName": "Poloniex", + "process": "Multi-Period-Daily", + "startYear": 2019, + "endYear": 2021, + "month": 1 + }, + { + "devTeam": "AAMasters", + "bot": "AAOlivia", + "mode": "noTime", + "resumeExecution": true, + "type": "Indicator", + "exchangeName": "Poloniex", + "process": "Multi-Period-Market", + "startYear": 2019, + "endYear": 2021, + "month": 1 + }, + { + "devTeam": "AAMasters", + "bot": "AATom", + "mode": "noTime", + "resumeExecution": true, + "type": "Indicator", + "exchangeName": "Poloniex", + "process": "Multi-Period-Daily", + "startYear": 2019, + "endYear": 2021, + "month": 1 + }, + { + "devTeam": "AAMasters", + "bot": "AATom", + "mode": "noTime", + "resumeExecution": true, + "type": "Indicator", + "exchangeName": "Poloniex", + "process": "Multi-Period-Market", + "startYear": 2019, + "endYear": 2021, + "month": 1 + }, + { + "devTeam": "AAMasters", + "bot": "AAChris", + "mode": "noTime", + "resumeExecution": true, + "type": "Indicator", + "exchangeName": "Poloniex", + "process": "Multi-Period-Daily", + "startYear": 2019, + "endYear": 2021, + "month": 1 + }, + { + "devTeam": "AAMasters", + "bot": "AAChris", + "mode": "noTime", + "resumeExecution": true, + "type": "Indicator", + "exchangeName": "Poloniex", + "process": "Multi-Period-Market", + "startYear": 2019, + "endYear": 2021, + "month": 1 + }, + { + "devTeam": "AAMasters", + "bot": "AAPaula", + "mode": "noTime", + "resumeExecution": true, + "type": "Indicator", + "exchangeName": "Poloniex", + "process": "Multi-Period-Daily", + "startYear": 2019, + "endYear": 2021, + "month": 1 + }, + { + "devTeam": "AAMasters", + "bot": "AAPaula", + "mode": "noTime", + "resumeExecution": true, + "type": "Indicator", + "exchangeName": "Poloniex", + "process": "Multi-Period-Market", + "startYear": 2019, + "endYear": 2021, + "month": 1 + }, { "devTeam": "AAMasters", "bot": "AAJason",