diff --git a/Trading/TradingBot.js b/Trading/TradingBot.js index 30eefe350..d94f80e23 100644 --- a/Trading/TradingBot.js +++ b/Trading/TradingBot.js @@ -45,8 +45,13 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR function start(multiPeriodDataFiles, timeFrame, timeFrameLabel, currentDay, simulationState, callBackFunction) { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> Entering function.') } + bot.processingDailyFiles + if (timeFrame > global.dailyFilePeriods[0][0]) { + bot.processingDailyFiles = false + } else { + bot.processingDailyFiles = true + } let chart = {} let mainDependency = {} @@ -89,7 +94,6 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR } /* Single Files */ - let dataFiles = multiPeriodDataFiles.get('Single Files') let products = {} @@ -103,24 +107,12 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR } /* Simulation */ - + const SNAPSHOTS_FOLDER_NAME = 'Snapshots' const TRADING_SIMULATION = require('./TradingSimulation.js') let tradingSimulation = TRADING_SIMULATION.newTradingSimulation(bot, logger, UTILITIES) - let market = bot.market - - const SIMULATED_RECORDS_FOLDER_NAME = 'Trading-Simulation' - const CONDITIONS_FOLDER_NAME = 'Simulation-Conditions' - const STRATEGIES_FOLDER_NAME = 'Simulation-Strategies' - const TRADES_FOLDER_NAME = 'Simulation-Trades' - const SNAPSHOTS_FOLDER_NAME = 'Snapshots' - - const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000 - - let recordsArray = [] - let conditionsArray = [] - let strategiesArray = [] - let positionsArray = [] + let totalFilesRead = 0 + let outputDatasetsMap = new Map() let snapshotHeaders let triggerOnSnapshot @@ -128,369 +120,78 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR let tradingSystem = {} - if (bot.RESUME === true) { - readFiles() - } else { + if (bot.RESUME !== true) { simulationState.tradingEngine = bot.SESSION.tradingEngine simulationState.tradingSystem = bot.SESSION.tradingSystem - runSimulation() } + readFiles() + return function readFiles() { - - if (timeFrame > global.dailyFilePeriods[0][0]) { - readMarketFiles(runSimulation) + /* + This bot have an output of files that it generates. At every call to the bot, it needs to read the previously generated + files in order to later append more information after the execution is over. Here in this function we are going to + read those output files and get them ready for appending content during the simulation. + */ + if (bot.processingDailyFiles) { + readDailyFiles() } else { - readDailyFiles(runSimulation) + readMarketFiles() } } - function readMarketFiles(callBack) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> Entering function.') } + function readMarketFiles() { + for (let i = 0; i < outputDatasets.length; i++) { + let outputDatasetNode = outputDatasets[i] + let dataset = outputDatasetNode.referenceParent - readRecordsFile() - - function readRecordsFile() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> readRecordsFile -> Entering function.') } + if (dataset.config.type === 'Market Files') { let fileName = 'Data.json' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + SIMULATED_RECORDS_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel - filePath += '/' + fileName + let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel - fileStorage.getTextFile(filePath, onFileRead, true) - - function onFileRead(err, text) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> readRecordsFile -> onFileRead -> Entering function.') } - - if (err.message === 'File does not exist.') { - recordsArray = [] - readConditionsFile() - return - } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readRecordsFile -> onFileRead -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readRecordsFile -> onFileRead -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readRecordsFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) - - callBackFunction(err) - return - } - - recordsArray = JSON.parse(text) - readConditionsFile() - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readRecordsFile -> onFileRead -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readRecordsFile -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) + readOutputFile(fileName, filePath, dataset.parentNode.config.pluralVariableName) } } + } - function readConditionsFile() { + function readOutputFile(fileName, filePath, productName) { + + filePath += '/' + fileName + + fileStorage.getTextFile(filePath, onFileRead, true) + + function onFileRead(err, text) { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> readConditionsFile -> Entering function.') } - let fileName = 'Data.json' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + CONDITIONS_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel - filePath += '/' + fileName - - fileStorage.getTextFile(filePath, onFileRead, true) - - function onFileRead(err, text) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> readConditionsFile -> onFileRead -> Entering function.') } - - if (err.message === 'File does not exist.') { - conditionsArray = [] - readStrategiesFile() - return - } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readConditionsFile -> onFileRead -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readConditionsFile -> onFileRead -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readConditionsFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) - - callBackFunction(err) - return - } - - conditionsArray = JSON.parse(text) - conditionsArray = conditionsArray[1] // conditionsArray[0] = a snapshot of the trading system. - readStrategiesFile() - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readConditionsFile -> onFileRead -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } + if (err.message === 'File does not exist.') { + outputDatasetsMap.set(productName, []) + anotherFileRead() + return } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readConditionsFile -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - function readStrategiesFile() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> readStrategiesFile -> Entering function.') } + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> filePath = ' + filePath) + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) - let fileName = 'Data.json' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + STRATEGIES_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel - filePath += '/' + fileName - - fileStorage.getTextFile(filePath, onFileRead, true) - - function onFileRead(err, text) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> readStrategiesFile -> onFileRead -> Entering function.') } - - if (err.message === 'File does not exist.') { - strategiesArray = [] - readPositionsFile() - return - } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readStrategiesFile -> onFileRead -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readStrategiesFile -> onFileRead -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readStrategiesFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) - - callBackFunction(err) - return - } - - strategiesArray = JSON.parse(text) - readPositionsFile() - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readStrategiesFile -> onFileRead -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } + callBackFunction(err) + return } + + outputDatasetsMap.set(productName, JSON.parse(text)) + anotherFileRead() } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readStrategiesFile -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - - function readPositionsFile() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> readPositionsFile -> Entering function.') } - - let fileName = 'Data.json' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + TRADES_FOLDER_NAME + '/' + 'Multi-Period-Market' + '/' + timeFrameLabel - filePath += '/' + fileName - - fileStorage.getTextFile(filePath, onFileRead, true) - - function onFileRead(err, text) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readMarketFiles -> readPositionsFile -> onFileRead -> Entering function.') } - - if (err.message === 'File does not exist.') { - positionsArray = [] - callBack() - return - } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readPositionsFile -> onFileRead -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readPositionsFile -> onFileRead -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readPositionsFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) - - callBackFunction(err) - return - } - - positionsArray = JSON.parse(text) - callBack() - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readPositionsFile -> onFileRead -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readPositionsFile -> err = ' + err.stack) + logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> err = ' + err.stack) callBackFunction(global.DEFAULT_FAIL_RESPONSE) } } } - function readDailyFiles(callBack) { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> Entering function.') } - - readRecordsFile() - - function readRecordsFile() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readRecordsFile -> Entering function.') } - - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) - let fileName = 'Data.json' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + SIMULATED_RECORDS_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath - filePath += '/' + fileName - - fileStorage.getTextFile(filePath, onFileRead, true) - - function onFileRead(err, text) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readRecordsFile -> onFileRead -> Entering function.') } - - if (err.message === 'File does not exist.') { - recordsArray = [] - readConditionsFile() - return - } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readRecordsFile -> onFileRead -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readRecordsFile -> onFileRead -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readRecordsFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) - - callBackFunction(err) - return - } - - recordsArray = JSON.parse(text) - readConditionsFile() - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readRecordsFile -> onFileRead -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readRecordsFile -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - - function readConditionsFile() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readConditionsFile -> Entering function.') } - - fileStorage.getTextFile(filePath, onFileRead, true) - - function onFileRead(err, text) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readConditionsFile -> onFileRead -> Entering function.') } - - if (err.message === 'File does not exist.') { - conditionsArray = [] - readStrategiesFile() - return - } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readConditionsFile -> onFileRead -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readConditionsFile -> onFileRead -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readConditionsFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) - - callBackFunction(err) - return - } - - conditionsArray = JSON.parse(text) - conditionsArray = conditionsArray[1] // conditionsArray[0] = a snapshot of the trading system. - readStrategiesFile() - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readConditionsFile -> onFileRead -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readConditionsFile -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - - function readStrategiesFile() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readStrategiesFile -> Entering function.') } - - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) - let fileName = 'Data.json' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + STRATEGIES_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath - filePath += '/' + fileName - - fileStorage.getTextFile(filePath, onFileRead, true) - - function onFileRead(err, text) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readStrategiesFile -> onFileRead -> Entering function.') } - - if (err.message === 'File does not exist.') { - strategiesArray = [] - readPositionsFile() - return - } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readStrategiesFile -> onFileRead -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readStrategiesFile -> onFileRead -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readStrategiesFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) - - callBackFunction(err) - return - } - - strategiesArray = JSON.parse(text) - readPositionsFile() - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readStrategiesFile -> onFileRead -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readStrategiesFile -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - - function readPositionsFile() { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readPositionsFile -> Entering function.') } - - let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2) - let fileName = 'Data.json' - let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + TRADES_FOLDER_NAME + '/' + 'Multi-Period-Daily' + '/' + timeFrameLabel + '/' + dateForPath - filePath += '/' + fileName - - fileStorage.getTextFile(filePath, onFileRead, true) - - function onFileRead(err, text) { - try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] start -> readDailyFiles -> readPositionsFile -> onFileRead -> Entering function.') } - - if (err.message === 'File does not exist.') { - positionsArray = [] - callBack() - return - } - - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readPositionsFile -> onFileRead -> err = ' + err.stack) - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readPositionsFile -> onFileRead -> filePath = ' + filePath) - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readPositionsFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset) - - callBackFunction(err) - return - } - - positionsArray = JSON.parse(text) - callBack() - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readPositionsFile -> onFileRead -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } - } - } catch (err) { - logger.write(MODULE_NAME, '[ERROR] start -> readDailyFiles -> readPositionsFile -> err = ' + err.stack) - callBackFunction(global.DEFAULT_FAIL_RESPONSE) - } + function anotherFileRead() { + totalFilesRead++ + if (totalFilesRead === outputDatasets.length) { + runSimulation() } } @@ -498,19 +199,15 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR tradingSimulation.runSimulation( chart, dataDependencies, - timeFrame, - timeFrameLabel, - currentDay, simulationState, exchangeAPI, - recordsArray, - conditionsArray, - strategiesArray, - positionsArray, + outputDatasets, + outputDatasetsMap, writeFiles, callBackFunction) } + function writeFiles(pTradingSystem, pSnapshotHeaders, pTriggerOnSnapshot, pTakePositionSnapshot) { tradingSystem = pTradingSystem @@ -518,10 +215,10 @@ exports.newTradingBot = function newTradingBot(bot, logger, UTILITIES, FILE_STOR triggerOnSnapshot = pTriggerOnSnapshot takePositionSnapshot = pTakePositionSnapshot - if (timeFrame > global.dailyFilePeriods[0][0]) { - writeMarketFiles() - } else { + if (bot.processingDailyFiles) { writeDailyFiles() + } else { + writeMarketFiles() } } diff --git a/MultiPeriod.js b/Trading/TradingProcess.js similarity index 98% rename from MultiPeriod.js rename to Trading/TradingProcess.js index 2ffe071fd..725d66510 100644 --- a/MultiPeriod.js +++ b/Trading/TradingProcess.js @@ -1,8 +1,12 @@ -exports.newMultiPeriod = function newMultiPeriod(bot, logger, UTILITIES, USER_BOT_MODULE, USER_BOT_COMMONS) { +exports.newTradingProcess = function newTradingProcess(bot, logger, UTILITIES, USER_BOT_MODULE, USER_BOT_COMMONS) { + /* + This Module will load all the process data dependencies from files and send them to the Trading Bot. + After execution, will save the time range and status report of the process. + */ const FULL_LOG = true; const LOG_FILE_CONTENT = false; - const MODULE_NAME = "Multi Period"; + const MODULE_NAME = "Trading Process"; const GMT_SECONDS = ':00.000 GMT+0000'; const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000; @@ -21,7 +25,7 @@ let botInstance; - const FILE_STORAGE = require('./FileStorage.js'); + const FILE_STORAGE = require('../FileStorage.js'); let fileStorage = FILE_STORAGE.newFileStorage(logger); let processConfig; @@ -29,7 +33,6 @@ return thisObject; function initialize(pProcessConfig, pStatusDependencies, pDataDependencies, exchangeAPI, callBackFunction) { - try { logger.fileName = MODULE_NAME; @@ -39,7 +42,7 @@ dataDependenciesModule = pDataDependencies; processConfig = pProcessConfig; - let USER_BOT_MODULE = require("./Trading/TradingBot") + let USER_BOT_MODULE = require("./TradingBot") botInstance = USER_BOT_MODULE.newTradingBot(bot, logger, UTILITIES, FILE_STORAGE); botInstance.initialize(exchangeAPI, callBackFunction); diff --git a/Trading/TradingRecords.js b/Trading/TradingRecords.js index fcdf8e415..3168f6097 100644 --- a/Trading/TradingRecords.js +++ b/Trading/TradingRecords.js @@ -3,166 +3,83 @@ exports.newTradingRecords = function newTradingRecords(bot, logger) { const MODULE_NAME = 'Trading Records' let thisObject = { - addSimulationRecord: addSimulationRecord, - addConditionsRecord: addConditionsRecord, - addStrategyRecord: addStrategyRecord, - addPositionRecord: addPositionRecord, + appendRecords: appendRecords, initialize: initialize, finalize: finalize } let tradingEngine + let tradingSystem + let outputDatasets + let outputDatasetsMap return thisObject - function initialize() { + function initialize(pOutputDatasets, pOutputDatasetsMap) { tradingEngine = bot.TRADING_ENGINE + tradingSystem = bot.TRADING_SYSTEM + outputDatasets = pOutputDatasets // These are the nodes defined at the UI + outputDatasetsMap = pOutputDatasetsMap // These are the files turned into arrays, stored in a Map by Product codeName. } function finalize() { tradingEngine = undefined + tradingSystem = undefined + outputDatasets = undefined + outputDatasetsMap = undefined } - function addSimulationRecord() { - /* Simulation Record */ - let simulationRecord - - if (tradingEngine.current.balance.baseAsset.value === Infinity) { - tradingEngine.current.balance.baseAsset.value = Number.MAX_SAFE_INTEGER - } - - if (tradingEngine.current.balance.quotedAsset.value === Infinity) { - tradingEngine.current.balance.quotedAsset.value = Number.MAX_SAFE_INTEGER - } - - simulationRecord = [ - candle.begin, - candle.end, - tradingEngine.current.balance.baseAsset.value, - tradingEngine.current.balance.quotedAsset.value, - tradingEngine.episode.episodeStatistics.profitLoss.value, - tradingEngine.last.position.profitLoss.value, - tradingEngine.current.position.stopLoss.value, - tradingEngine.episode.positionCounters.positions.value, - tradingEngine.episode.episodeCounters.hits.value, - tradingEngine.episode.episodeCounters.fails.value, - tradingEngine.episode.episodeStatistics.hitRatio.value, - tradingEngine.episode.episodeStatistics.ROI.value, - tradingEngine.episode.episodeCounters.periods, - tradingEngine.episode.episodeStatistics.days, - tradingEngine.episode.episodeStatistics.anualizedRateOfReturn.value, - tradingEngine.current.position.rate.value, - tradingEngine.last.position.ROI.value, - tradingEngine.current.position.takeProfit.value, - tradingEngine.current.position.stopLoss.stopLossPhase.value, - tradingEngine.current.position.takeProfit.takeProfitPhase.value, - tradingEngine.current.position.size.value, - sessionParameters.sessionBaseAsset.config.initialBalance, - sessionParameters.sessionBaseAsset.config.minimumBalance, - sessionParameters.sessionBaseAsset.config.maximumBalance, - sessionParameters.sessionQuotedAsset.config.initialBalance, - sessionParameters.sessionQuotedAsset.config.minimumBalance, - sessionParameters.sessionQuotedAsset.config.maximumBalance, - '"' + sessionParameters.sessionBaseAsset.name + '"', - '"' + sessionParameters.sessionQuotedAsset.name + '"', - '"' + bot.market.marketBaseAsset + '"', - '"' + bot.market.marketQuotedAsset + '"', - tradingEngine.current.position.positionCounters.periods.value, - tradingEngine.current.position.positionStatistics.days.value - ] - - recordsArray.push(simulationRecord) - } - - function addConditionsRecord() { - /* Prepare the information for the Conditions File */ - let conditionsRecord = [ - candle.begin, - candle.end, - tradingEngine.current.strategy.index.value, - tradingEngine.current.position.stopLoss.stopLossPhase.value, - tradingEngine.current.position.takeProfit.takeProfitPhase.value, - conditionsValues, - formulasErrors, - formulasValues - ] - - conditionsArray.push(conditionsRecord) - } - - function addStrategyRecord() { + function appendRecords() { /* - Lets see if there will be an open strategy ... - Except if we are at the head of the market (remember we skipped the last candle for not being closed.) - */ - if ( - tradingEngine.current.strategy.begin.value !== 0 && - tradingEngine.current.strategy.end.value === 0 && - currentCandleIndex === candles.length - 2 && - lastCandle.end !== lastInstantOfTheDay - ) { - tradingEngine.current.strategy.status.value = 'Open' - tradingEngine.current.strategy.end.value = candle.end - } + Here we add records to the output files. At the product config property nodePath + we have a pointer to the node that have the information we need to extract. + Later, based on the product record definition we will extract each individual value. + */ + for (let i = 0; i < outputDatasets.length; i++) { + let outputDatasetNode = outputDatasets[i] + let dataset = outputDatasetNode.referenceParent + let product = dataset.parentNode + let record - /* Prepare the information for the Strategies File */ - if (tradingEngine.current.strategy.begin.value !== 0 && tradingEngine.current.strategy.end.value !== 0) { - let strategyRecord = [ - tradingEngine.current.strategy.begin.value, - tradingEngine.current.strategy.end.value, - tradingEngine.current.strategy.status.value, - tradingEngine.current.strategy.index.value, - tradingEngine.current.strategy.beginRate.value, - tradingEngine.current.strategy.endRate.value, - '"' + tradingEngine.current.strategy.situationName.value + '"', - '"' + tradingEngine.current.strategy.strategyName.value + '"' - ] - - strategiesArray.push(strategyRecord) - - inializeCurrentStrategy() - } - } - - function addPositionRecord() { - /* - Lets see if there will be an open trade ... - Except if we are at the head of the market (remember we skipped the last candle for not being closed.) - */ - if (tradingEngine.current.position.begin.value !== 0 && - tradingEngine.current.position.end.value === 0 && - currentCandleIndex === candles.length - 2 && - lastCandle.end !== lastInstantOfTheDay) { - - /* This means the trade is open */ - tradingEngine.current.position.status.value = 2 - tradingEngine.current.position.end.value = candle.end - tradingEngine.current.position.endRate.value = candle.close - - /* Here we will calculate the ongoing ROI */ - if (sessionParameters.sessionBaseAsset.name === bot.market.marketBaseAsset) { - tradingEngine.current.position.positionStatistics.ROI.value = (tradingEngine.current.position.rate.value - candle.close) / tradingEngine.current.position.rate.value * 100 - } else { - tradingEngine.current.position.positionStatistics.ROI.value = (candle.close - tradingEngine.current.position.rate.value) / tradingEngine.current.position.rate.value * 100 + if (bot.processingDailyFiles === true && dataset.config.type === 'Daily Files') { + record = scanRecordDefinition(product) } + + if (bot.processingDailyFiles === false && dataset.config.type === 'Market Files') { + record = scanRecordDefinition(product) + } + + let outputDatasetArray = outputDatasetsMap.get(product.config.codeName) + outputDatasetArray.push(record) } - /* Prepare the information for the Positions File */ - if (tradingEngine.current.position.begin.value !== 0 && tradingEngine.current.position.end.value !== 0) { - let positionRecord = [ - tradingEngine.current.position.begin.value, - tradingEngine.current.position.end.value, - tradingEngine.current.position.status.value, - tradingEngine.current.position.positionStatistics.ROI.value, - tradingEngine.current.position.beginRate.value, - tradingEngine.current.position.endRate.value, - tradingEngine.current.position.exitType.value, - '"' + tradingEngine.current.position.situationName.value + '"' - ] + function scanRecordDefinition(product) { + let rootNode = eval(product.config.nodePath) + let record = [] + for (let j = 0; j < product.recordDefinition.recordProperties.length; j++) { + let recordProperty = product.recordDefinition.recordProperties[j] + let value + if (recordProperty.config.nodePath !== undefined) { + let childNode = rootNode[recordProperty.config.childNode] + if (recordProperty.config.index !== undefined) { + value = childNode[recordProperty.config.codeName] // this returns an array + value = value[recordProperty.config.index].value // this return a node item of the array and its value + } else { + value = childNode[recordProperty.config.codeName].value // here we get the value of the childNode + } + } else { + value = rootNode[recordProperty.config.codeName].value // this is the standard way + } + if (value === Infinity) { + value = Number.MAX_SAFE_INTEGER + } + if (recordProperty.config.isString === true) { + value = '"' + value + '"' + } + record.push(value) + } - positionsArray.push(positionRecord) - - initializeCurrentPosition() + return record } } } \ No newline at end of file diff --git a/Trading/TradingSimulation.js b/Trading/TradingSimulation.js index dc71a3726..14929837c 100644 --- a/Trading/TradingSimulation.js +++ b/Trading/TradingSimulation.js @@ -1,11 +1,8 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILITIES) { const FULL_LOG = true - const LOG_FILE_CONTENT = false const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000 const MODULE_NAME = 'Trading Simulation -> ' + bot.SESSION.name - const GMT_SECONDS = ':00.000 GMT+0000' - let thisObject = { finalize: finalize, runSimulation: runSimulation @@ -22,25 +19,13 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT function runSimulation( chart, dataDependencies, - timeFrame, - timeFrameLabel, - currentDay, simulationState, exchangeAPI, - recordsArray, - conditionsArray, - strategiesArray, - positionsArray, + outputDatasets, + outputDatasetsMap, callback, callBackFunction) { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> Entering function.') } - let processingDailyFiles - if (timeFrame > global.dailyFilePeriods[0][0]) { - processingDailyFiles = false - } else { - processingDailyFiles = true - } let tradingSystem = simulationState.tradingSystem let tradingEngine = simulationState.tradingEngine @@ -63,12 +48,6 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT let takePositionNow = false let closePositionNow = false - /* In some cases we need to know if we are positioned at the last candle of the calendar day, for that we need these variables. */ - let lastInstantOfTheDay = 0 - if (currentDay) { - lastInstantOfTheDay = currentDay.valueOf() + ONE_DAY_IN_MILISECONDS - 1 - } - /* These are the Modules we will need to run the Simulation */ const TRADING_ENGINE_MODULE = require('./TradingEngine.js') let tradingEngineModule = TRADING_ENGINE_MODULE.newTradingEngine(bot, logger) @@ -80,7 +59,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT const TRADING_RECORDS_MODULE = require('./TradingRecords.js') let tradingRecordsModule = TRADING_RECORDS_MODULE.newTradingRecords(bot, logger) - tradingRecordsModule.initialize() + tradingRecordsModule.initialize(outputDatasets, outputDatasetsMap) const SNAPSHOTS_MODULE = require('./Snapshots.js') let snapshotsModule = SNAPSHOTS_MODULE.newSnapshots(bot, logger) @@ -255,18 +234,13 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT } snapshotsModule.manageSnapshots() - tradingRecordsModule.addSimulationRecord() - tradingRecordsModule.addConditionsRecord() - tradingRecordsModule.addStrategyRecord() - tradingRecordsModule.addPositionRecord() + tradingRecordsModule.appendRecords() annoucementsModule.makeAnnoucements() // After everything at the simulation level was done, we will do the annoucements that are pending. controlLoop() } function controlLoop() { - if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> controlLoop -> Entering function.') } - /* Checking if we should continue processing this loop or not. */ if (bot.STOP_SESSION === true) { if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing this session.') } @@ -374,7 +348,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT */ /* Finding the Current Element on Market Files */ - if (processingDailyFiles) { + if (bot.processingDailyFiles) { for (let j = 0; j < global.dailyFilePeriods.length; j++) { let mapKey = dailyFilePeriods[j][1] let propertyName = 'at' + mapKey.replace('-', '') @@ -430,7 +404,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT We skip the candle at the head of the market because it has not closed yet. The procedure to determine if we are at the head of the market is different when we are processing Market Files than when we are processing Daily Files. TODO Check that the procedure is good for Beta 6 */ - if (processingDailyFiles) { // We are processing Daily Files + if (bot.processingDailyFiles) { // We are processing Daily Files let candlesPerDay = ONE_DAY_IN_MILISECONDS / sessionParameters.timeFrame.config.value if (tradingEngine.current.candle.index.value === candles.length - 1) { if ((candles.length < candlesPerDay) || (candles.length > candlesPerDay && candles.length < candlesPerDay * 2)) { diff --git a/TradingBotProcessMainLoop.js b/TradingBotProcessMainLoop.js index 73264fec4..ec15efa4d 100644 --- a/TradingBotProcessMainLoop.js +++ b/TradingBotProcessMainLoop.js @@ -8,9 +8,7 @@ let USER_BOT_MODULE; let USER_BOT_COMMONS; - const MULTI_PERIOD_MARKET = require(ROOT_DIR + 'MultiPeriodMarket'); - const MULTI_PERIOD_DAILY = require(ROOT_DIR + 'MultiPeriodDaily'); - const MULTI_PERIOD = require(ROOT_DIR + 'MultiPeriod'); + const TRADING_PROCESS_MODULE = require(ROOT_DIR + '/Trading/TradingProcess.js'); const FILE_STORAGE = require('./FileStorage.js'); const SESSION = require(ROOT_DIR + 'Session'); @@ -526,8 +524,8 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeExchangeAPI -> onInizialized -> Execution finished well."); } switch (processConfig.framework.name) { - case 'Multi-Period': { - processFramework = MULTI_PERIOD.newMultiPeriod(bot, logger, UTILITIES, USER_BOT_MODULE, USER_BOT_COMMONS); + case 'Trading-Process': { + processFramework = TRADING_PROCESS_MODULE.newTradingProcess(bot, logger, UTILITIES, USER_BOT_MODULE, USER_BOT_COMMONS); intitializeProcessFramework(); break; }